Skip to main content
Combat writes split across three action classes: CombatActions for combat settings, PrayerActions for prayers, and MagicActions for spells. Target discovery belongs to the query helpers; attack dispatch goes through NPCActions.interact(...).

Combat settings

All methods return InteractionResult. Attack-style and auto-retaliate changes require the Combat tab to be visible; a missing prerequisite returns WIDGET_HIDDEN targeting the tab and never selects it. The special-attack orb and quick-prayer orb operations are tab-independent.
Check the resulting widget state, not only the action result. These widget mappings respond to client revision changes; a successful dispatch is not proof of convergence.

Prayer

The core writes are idempotent and converge toward a requested state:
setOnly(...) and disableAll() may need multiple ticks: each call queues at most the next required toggle. Re-evaluate and call again until the observed state matches. A null prayer returns TARGET_NULL; an unmapped, missing, or hidden component returns PRAYER_WIDGET_NOT_FOUND. Prayer changes require the Prayer tab only when the observed state still differs from the request.

Quick prayers

Open the setup before calling setQuickPrayers(...), and toggle the orb only after observing the configured set.

Dwarf multicannon

CannonActions covers the cannon lifecycle. State reads use rev240 object-ID evidence (DWARF_MULTICANNON1, BROKEN_MULTICANNON, and the three build-stage objects); writes are paced. Cannonball ammunition state is deliberately unmodeled: rev240 evidence exposes no ammunition varbit and IDs are never invented. Re-observe isPlaced()/isBroken() after each interaction.

Magic

MagicActions handles result-aware spell interactions. Cast, selection, and deselection require the Magic tab to be visible; otherwise they return WIDGET_HIDDEN targeting tab/MAGIC without changing tabs.

Reads

canCast, getSpellBook, isAutoCasting, isSpellSelected(), and isSpellSelected(Spell) report spell state. Rune-pouch contents come from the sdk.query.RunePouch reads.

Selection and targeted casting

Passing null to selectSpell returns TARGET_NULL. Missing spell widgets yield SPELL_WIDGET_NOT_FOUND; hidden widgets yield SPELL_NOT_CASTABLE.

The inventory-spell transaction

castOnInventoryItem is built for repeated calls from a tick-driven controller. It owns one synchronized transaction shared by all consumers:
  1. With no selection, it requires the Magic tab and selects the exact requested spell. The transaction never opens a closed tab.
  2. Once the exact spell is selected, it validates the inventory widget and queues one mouse-click metadata packet followed by one widget-on-widget packet.
  3. RuneLite owns the transition back to Inventory; the transaction never sends an explicit tab action.
  4. While the selection stays unresolved after target dispatch, further requests return PACED without resending anything. A competing spell or item cannot take over the transaction.
  5. A different selected spell or non-spell widget is cleared and reported as TARGET_STALE. A selection unresolved for five seconds is cleared the same way, and recovery begins with a fresh selection cycle.
DISPATCHED means the action was accepted for dispatch; it does not prove completion. Observe the domain postcondition (an inventory decrement, XP gain, or produced output) before counting the spell as cast. Spell names resolve through MagicActions.resolveSpellInfo(name), backed by the Api.actions.Spell catalog. See the scripting patterns for the resolution rules.

Tick decisions

Use TickDecisionList when a plugin must evaluate ordered, once-per-tick combat policies. Call it from onGameTick; never inside a TaskPipeline or any faster loop.
  • The list suppresses duplicate evaluation within one tick and preserves declaration order.
  • A decision returning true reserves the remainder of the tick; false lets the next decision run.
  • Each decision returns without sleeping and dispatches at most one meaningful action.
lastDecisionName() reports which decision blocked the last evaluated tick.

Eating

EatDecision reads the current tick plus real and boosted hitpoints from the injected Client. The default policy requires 20 missing hitpoints and covers sharks (20), lobsters (14), swordfish (14), jugs of wine (8), blighted manta ray (22), blighted anglerfish (10), and karambwan (45 primary, 18 combo). It clears an active widget selection before eating, records its cooldown only after InventoryActions.use(..., "Eat") accepts, and blocks another eat for three game ticks. When primary and combo food both fit the deficit, it dispatches the primary food and attempts the combo on the next evaluation. Supply custom healing maps, thresholds, and a policy gate through the configurable constructor:
Map iteration order does not select food: the decision scans current inventory order and picks the first food whose heal does not exceed the missing hitpoints.

Potions and variants

ItemVariant groups interchangeable doses in resolution order, preferred dose first:
PotionDecision evaluates rules in the order you add them. A rule whose condition is false does nothing; a rule whose condition is true resolves the first owned variant and dispatches InventoryActions.use(id, "Drink"), ending potion evaluation for that tick. Conditions read state (boost deltas, prayer points, run energy) and stay read-only.

Ordering

Place survival before damage. A typical combat list:
  1. Configure quick prayers.
  2. Move into the combat area.
  3. Drink potions.
  4. Flick or swap prayer.
  5. Eat.
  6. Loot.
  7. Set combat style.
  8. Attack.
Never infer completion from an accepted dispatch; re-read combat, inventory, animation, and skill state on a later tick.

Workflow ownership

Food thresholds, target selection, retries, and death or loot transitions belong in CombatWorkflowBuilder or your own state machine, not in these action methods. See workflow builders for the orchestration layer. In paced unit tests, call ActionPacer.reset() in @Before.