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:

InputDecision
StoryCharacterWhich campaign is active
Conversation.IDWhich conversation was requested
World or death persistent dataWhether 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:

HookParametersSuitable boundary
On.SSOracleBehavior.InitateConversationself, conversation ID, conversation behaviorObserve or replace a selected Pebbles conversation
On.SSOracleBehavior.StartItemConversationself, data pearlObserve or replace an item triggered conversation
On.SSOracleBehavior.PebblesConversation.AddEventsPebbles conversationChange 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, and global::SLOracleBehaviorHasMark.MoonConversation in Assembly-CSharp.dll, SHA-256 B6BE1D4E18CE219D21091B51564CB6A11C1E4106B41DE903EB8E58849CB16FDB. See Runtime reference.
  • On.SSOracleBehavior.InitateConversation, On.SSOracleBehavior.StartItemConversation, and On.SSOracleBehavior.PebblesConversation.AddEvents in the installed generated hook assembly.
  • SlugBase save data extension methods at the pinned commit