Oracle dialogue is selected in code from a conversation ID, the current story character, and saved facts. A SlugBase character JSON file does not declare this dispatch. For Five Pebbles, build 22785462 exposes narrow hook points around conversation selection, item conversations, and event construction.
Conversation is abstract. It stores an IOwnAConversation owner, Conversation.ID, HUD.DialogBox, and a list of dialogue events. Its constructor takes those first three values. SSOracleBehavior.PebblesConversation derives from it, receives an SSOracleBehavior, a ConversationBehavior, an ID, and a dialog box, then calls its AddEvents() override from the constructor.
The game method is spelled InitateConversation in both SSOracleBehavior and the generated hook API. Preserve that exact spelling in subscriptions and handler types.
Follow the dispatch inputs
Vanilla Pebbles behavior checks oracle.room.game.StoryCharacter to select character branches. It also reads campaign facts such as saveState.miscWorldSaveData.SSaiConversationsHad and saveState.deathPersistentSaveData.theMark. These inputs answer separate questions:
| Input | Decision |
|---|---|
StoryCharacter | Which campaign is active |
Conversation.ID | Which conversation was requested |
| World or death persistent data | Whether an encounter happened and which branch remains available |
A custom dispatch should keep those tests explicit. Give the conversation a stable ID, limit it to the intended story character, and read a saved fact from the scope that matches its lifetime. Campaign save data covers those scopes.
The following excerpt shows the boundary without supplying a complete conversation implementation:
private static readonly Conversation.ID LanternWrenMeeting =
new Conversation.ID("LanternWren_Meeting", true);
private void SSOracleInitateConversation(
On.SSOracleBehavior.orig_InitateConversation orig,
global::SSOracleBehavior self,
Conversation.ID convoId,
global::SSOracleBehavior.ConversationBehavior convBehav)
{
if (convoId != LanternWrenMeeting)
{
orig(self, convoId, convBehav);
return;
}
DispatchLanternWrenMeeting(self, convBehav);
}DispatchLanternWrenMeeting is deliberately undefined. Before constructing anything, that branch would verify a story session, compare StoryCharacter with the custom identity, and read its encounter flag. The excerpt calls orig once for every unrelated ID. It replaces the original route only for the custom ID, so that branch assumes responsibility for constructing and owning the resulting conversation. See Hook lifecycle before using a replacement hook.
Choose the narrow hook
The generated hook assembly contains these Pebbles seams:
| Hook | Parameters | Suitable boundary |
|---|---|---|
On.SSOracleBehavior.InitateConversation | self, conversation ID, conversation behavior | Observe or replace a selected Pebbles conversation |
On.SSOracleBehavior.StartItemConversation | self, data pearl | Observe or replace an item triggered conversation |
On.SSOracleBehavior.PebblesConversation.AddEvents | Pebbles conversation | Change event construction for a known conversation ID |
The exact generated delegate for the first hook is hook_InitateConversation(orig_InitateConversation orig, SSOracleBehavior self, Conversation.ID convoId, SSOracleBehavior.ConversationBehavior convBehav). StartItemConversation receives a DataPearl. PebblesConversation.AddEvents receives the conversation being populated.
Hooking AddEvents can isolate text event changes from the earlier behavior that decides when a conversation starts. Its constructor timing matters because PebblesConversation invokes AddEvents() immediately. A handler for an unrelated ID should call orig. A handler that replaces a known ID must add the complete event list expected for that ID.
Keep Moon separate
The inspected build uses SLOracleBehaviorHasMark.MoonConversation for Moon conversation objects, including pearl conversations started from SSOracleBehavior.StartItemConversation. This source set establishes the class and call sites but does not establish a tested constructor hook or a safe complete route for custom Moon dialogue. Do not apply the Pebbles constructor pattern to Moon without separate source and game checks.
Text translation also needs its own integration check. Localized text covers Rain World’s general translation lookup, but this page does not claim a tested translated oracle sequence.
SlugBase is optional. It is needed only if the dispatch reads custom data through GetSlugBaseData(). That save API was checked at commit dac343359d0f6e311de9f89345954f9ad2b25f3e, whose compatibility with the current released SlugBase package is unverified. The signatures and excerpt on this page are source verified only. They were not compiled or run.
Sources
global::Conversation,global::SSOracleBehavior,global::SSOracleBehavior.PebblesConversation, andglobal::SLOracleBehaviorHasMark.MoonConversationinAssembly-CSharp.dll, SHA-256B6BE1D4E18CE219D21091B51564CB6A11C1E4106B41DE903EB8E58849CB16FDB. See Runtime reference.On.SSOracleBehavior.InitateConversation,On.SSOracleBehavior.StartItemConversation, andOn.SSOracleBehavior.PebblesConversation.AddEventsin the installed generated hook assembly.- SlugBase save data extension methods at the pinned commit