Dialogue & Dialogue Helper
This document covers both the high-level Dialogue Helper plugin automation and the underlying Dialog Actions SDK API.
Design Principle
OSRS dialogue is stateless: if the target widget is visible on the screen, click it; if not, do nothing. There is no signature tracking, lockout, retry backoff, or player-busy guards. Those concepts are wrong for dialogue and cause the plugin/API to suppress legitimate clicks.
Shared Action Pacing
Dialogue interactions respect the suite-wide ActionPacer ticked by PacketUtilsPlugin.onGameTick.
- When a Quest Helper option, continue prompt, or options dialog is visible, we check
ActionPacer.isReady(...)before queuing packets. - A paced result returns immediately without clicking, without updating the tick guard, and without logging an action.
- After successful widget click and resume/pause delivery, the code calls
ActionPacer.recordAction(). - A local
lastFiredTickfield prevents duplicate sends inside the same game tick.
Stateless Dialogue Flow
Dialogue Helper Plugin
The DialogueHelperPlugin automatically advances dialogue and selects Quest Helper-aligned options.
- Config group:
n3dialoguehelper - Properties registration:
runelite-plugin.properties(disabled by default)
Behavior (Per Game Tick)
- Gate on
GameState.LOGGED_IN. - Gate on
client.getTickCount() != lastFiredTickto prevent duplicate packets in the same tick. - Quest Option Scan (if
autoQuestOptions):- Search for a widget where
parentId == (219 << 16) | 1. - Parse the
[N]prefix from its text. - Require
ActionPacer.isReady(...). - Call
WidgetApi.click()+WidgetApi.resumePause(id, N)+ActionPacer.recordAction(). - Update
lastFiredTick = tickand return.
- Search for a widget where
- Continue Scan (if
autoContinue):- Match
Text.removeTags(text).trim()against"Click here to continue". - Require
ActionPacer.isReady(...). - Call
WidgetApi.click()+WidgetApi.resumePause(id, -1)+ActionPacer.recordAction(). - Update
lastFiredTick = tickand return.
- Match
Quest option selection takes precedence over continue prompts.
Configuration
| Key | Default | Purpose |
|---|---|---|
autoContinue | true | Click continue prompts |
autoQuestOptions | true | Select Quest Helper–highlighted options |
debugLogging | false | Info-level log on each action |
Dialog Actions API
DialogActions wraps low-level widget detection and interaction. All write methods return InteractionResult and are paced.
Query Methods
isOpen(): true if any dialog type is currently visible.isNPCDialog(): NPC speech widget (group 231) visible.isPlayerDialog(): player speech widget (group 217) visible.isOptionsDialog(): options list widget (group 219) visible.isViewingOptions(): alias forisOptionsDialog().isEnterInputOpen(): chatbox input (group 162) visible.canContinue(): "Click here to continue" widget exists and is visible.isQuestHelperMarkedOptionVisible(): true when a visible option under parent(219 << 16) | 1has a Quest Helper[N]prefix.getOptions()->List<String>: option texts (HTML tags stripped).getText()->String: dialog body text (tags stripped; empty string if closed).getName()->String: speaker name (NPC name or player name; empty if absent).hasOption(String text): case-insensitive contains check againstgetOptions().
Action Methods
continueSpace(): clicks the continue prompt dynamically.chooseQuestHelperMarkedOption(): clicks the Quest Helper-marked[N]option.chooseOption(int index): selects option by 0-based index.chooseOption(String... options): selects first option containing any of the given strings.chooseOption(Predicate<String>): selects first option matching predicate.enterAmount(int amount): sends number input value.enterObject(int objectId): sends object-picker input value (ResumeObjDialog).enterText(String text): sends string input value.enterName(String name): sends name input value.
Quest Helper Option Format
Quest Helper places options under parent (219 << 16) | 1 and prepends a [N] prefix where N is the option index (typically 1-5). Dialogue Helper parses N from the character immediately preceding the ] character.
Code Examples
Example: Basic Conversation Helper
if (DialogActions.isNPCDialog()) {
if (DialogActions.canContinue()) {
DialogActions.continueSpace();
} else if (DialogActions.hasOption("Yes")) {
DialogActions.chooseOption("Yes");
}
}
if (DialogActions.isEnterInputOpen()) {
DialogActions.enterAmount(1000);
}
Example: Custom Predicate Options
DialogActions.chooseOption(text -> text.contains("Start the quest") || text.contains("Tell me more"));
Implementation Details
- OSRS destroys (rather than hides) dialog widgets when they close, so a
nulltext guard is sufficient instead of anisHidden()check. continueSpace()andchooseOption()route throughMousePackets.tryQueueClickPacket()before sending the resume packet. A click packet failure short-circuits the action.ActionPaceris static and ticked suite-wide. Do not tick it again inside feature plugins.
Testing
.\gradlew.bat test --tests com.n3plugins.dialoguehelper.* --console plain
Tests should inject WidgetApi.setAdapterForTesting(mock) and invoke ActionPacer.reset() in @Before.