Skip to content

Commit 7762843

Browse files
committed
chore: dialogue injection docs
1 parent dea7c94 commit 7762843

2 files changed

Lines changed: 181 additions & 0 deletions

File tree

S1API/docs/dialogue-injection.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# Dialogue Injection
2+
3+
`DialogueInjection` lets you attach an extra choice to an existing vanilla or custom NPC dialogue flow without replacing the whole container.
4+
5+
This is useful when you want to extend an NPC's normal conversation with one additional branch, such as a service unlock, a follow-up action, or a context-specific option that should only appear for a specific character.
6+
7+
## Overview
8+
9+
The injection flow has two parts:
10+
11+
1. Create a `DialogueInjection` that describes where the new choice should be inserted
12+
2. Register it with `DialogueInjector.Register(...)`
13+
14+
S1API then waits until the matching NPC is available in the world, finds the requested dialogue container and source node, appends the new choice, creates the node link, and wires up your confirmation callback.
15+
16+
```csharp
17+
using S1API.Dialogues;
18+
19+
DialogueInjector.Register(new DialogueInjection(
20+
npc: "Philip",
21+
container: "CasinoDialogue",
22+
from: "ROOT_NODE_GUID",
23+
to: "BANKING_NODE_GUID",
24+
label: "ASK_ABOUT_PAYOUTS",
25+
text: "Quick question about payouts.",
26+
onConfirmed: () =>
27+
{
28+
// Handle the selected option
29+
}));
30+
```
31+
32+
## When to Use It
33+
34+
Use `DialogueInjection` when you want to:
35+
36+
- Add one or more new choices to an existing NPC dialogue tree
37+
- Reuse an existing container instead of building a full replacement
38+
- Hook into a known dialogue node and branch into your own follow-up node
39+
- Attach lightweight interaction logic to a dialogue choice callback
40+
41+
If you need to build a full custom dialogue flow from scratch, start with **[Dialogue System](dialogue-system.md)** instead.
42+
43+
## Constructor Options
44+
45+
`DialogueInjection` supports two ways to target an NPC.
46+
47+
### By NPC ID
48+
49+
Use the string overload when you know the NPC's ID.
50+
51+
```csharp
52+
var injection = new DialogueInjection(
53+
npc: "Philip",
54+
container: "CasinoDialogue",
55+
from: "ROOT_NODE_GUID",
56+
to: "BANKING_NODE_GUID",
57+
label: "ASK_ABOUT_PAYOUTS",
58+
text: "Quick question about payouts.",
59+
onConfirmed: OnAskAboutPayouts);
60+
```
61+
62+
Internally this maps to `x => x.ID.Equals(npc)`.
63+
64+
### By Predicate
65+
66+
Use the predicate overload when you need more control.
67+
68+
```csharp
69+
using S1API.Entities;
70+
71+
var injection = new DialogueInjection(
72+
appliesToNpc: npc => npc.ID == "Philip" && npc.FullName.Contains("Philip"),
73+
container: "CasinoDialogue",
74+
from: "ROOT_NODE_GUID",
75+
to: "BANKING_NODE_GUID",
76+
label: "ASK_ABOUT_PAYOUTS",
77+
text: "Quick question about payouts.",
78+
onConfirmed: OnAskAboutPayouts);
79+
```
80+
81+
This is helpful when multiple NPC variants share related data or when your targeting rule depends on runtime state.
82+
83+
## Field Reference
84+
85+
Each `DialogueInjection` instance needs the following values:
86+
87+
- `AppliesTo`: Predicate used to decide whether a world NPC should receive the injection
88+
- `ContainerName`: Name of the target dialogue container
89+
- `FromNodeGuid`: GUID of the node that should receive the new choice
90+
- `ToNodeGuid`: GUID of the node the new choice should lead to
91+
- `ChoiceLabel`: Internal identifier used for callback registration
92+
- `ChoiceText`: Text shown to the player in the dialogue UI
93+
- `OnConfirmed`: Action invoked when the player selects the injected choice
94+
95+
## How Registration Works
96+
97+
When you call `DialogueInjector.Register(...)`:
98+
99+
1. The injection is queued
100+
2. S1API starts a lightweight wait loop if one is not already running
101+
3. The loop checks loaded NPCs until one matches `AppliesTo`
102+
4. The injector resolves the requested container by name
103+
5. The injector finds the source node by `FromNodeGuid`
104+
6. A new choice and node link are added to that dialogue container
105+
7. `DialogueChoiceListener` binds your `OnConfirmed` callback to `ChoiceLabel`
106+
107+
This means you can usually register injections during your mod setup without waiting for the NPC to already be spawned.
108+
109+
## Example
110+
111+
The example below adds a new question to an existing NPC dialogue and sends the player into a custom follow-up node when selected.
112+
113+
```csharp
114+
using S1API.Dialogues;
115+
116+
public static class PayoutDialogueFeature
117+
{
118+
public static void Register()
119+
{
120+
DialogueInjector.Register(new DialogueInjection(
121+
npc: "Philip",
122+
container: "CasinoDialogue",
123+
from: "INTRO_NODE_GUID",
124+
to: "PAYOUT_INFO_NODE_GUID",
125+
label: "ASK_PAYOUT_QUESTION",
126+
text: "Quick question about payouts.",
127+
onConfirmed: OnPayoutQuestionSelected));
128+
}
129+
130+
private static void OnPayoutQuestionSelected()
131+
{
132+
// Put your feature logic here
133+
}
134+
}
135+
```
136+
137+
In practice, the target node identified by `ToNodeGuid` must already exist in the container you are linking into.
138+
139+
## Requirements and Limitations
140+
141+
- `ContainerName` must match a real container name exactly
142+
- `FromNodeGuid` must point to an existing node in that container
143+
- `ToNodeGuid` must point to an existing destination node
144+
- `ChoiceLabel` should be unique enough for your mod's callback usage
145+
- If the NPC, container, or node cannot be found, the injection is skipped silently
146+
147+
Because this API works against existing dialogue assets, you should verify container names and GUIDs carefully before shipping.
148+
149+
## Best Practices
150+
151+
- Prefer stable NPC IDs over loose matching when possible
152+
- Keep `ChoiceLabel` descriptive and mod-specific to avoid collisions
153+
- Use player-facing `ChoiceText` that fits the NPC's existing conversation tone
154+
- Keep `OnConfirmed` fast and push larger flows into your own dialogue nodes or systems
155+
- Test the target dialogue path in-game after save loads and scene changes
156+
157+
## Troubleshooting
158+
159+
### The choice never appears
160+
161+
Check these first:
162+
163+
- The NPC ID or predicate actually matches a loaded `S1API.Entities.NPC`
164+
- The container name is correct
165+
- The source node GUID exists in that container
166+
- The target node GUID exists and is reachable
167+
168+
### The callback does not run
169+
170+
Make sure:
171+
172+
- `ChoiceLabel` is unique for the injected choice
173+
- `OnConfirmed` does not throw immediately
174+
- Another mod is not reusing the same choice label in the same dialogue flow
175+
176+
## Next Steps
177+
178+
- Read **[Dialogue System](dialogue-system.md)** for building full containers and custom nodes
179+
- Use `DialogueInjection` for small extensions and `Dialogue.BuildAndRegisterContainer(...)` for larger custom flows

S1API/docs/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
href: delivery-location-registry.md
2424
- name: Dialogue System
2525
href: dialogue-system.md
26+
- name: Dialogue Injection
27+
href: dialogue-injection.md
2628
- name: Customer Behavior
2729
href: customer-behavior.md
2830
- name: Relationship Management

0 commit comments

Comments
 (0)