The result of an opposed test — two actors directly competing via their respective success tests.

Opposed tests are used for contested actions: grappling, stealth vs. perception, persuasion vs. will, and similar skill-vs-skill situations. Each side performs a success test independently, and the results are compared to determine the winner.

Opposed tests are executed in two phases:

  1. sohl.entity.modifier.MasteryLevelModifier.opposedTestStart — source rolls and result is posted to chat with a "respond" button.
  2. sohl.entity.modifier.MasteryLevelModifier.opposedTestResume — target rolls and the opposed outcome is evaluated and posted.

CombatResult extends this for full combat resolution (attack vs. defense with damage calculation).

Hierarchy (View Summary)

Constructors

Properties

breakTies: boolean

Whether a tie should be broken (see resolveTieBreak) rather than reported as a tie.

rollMode: string

Foundry roll mode for chat output.

The initiating (source) actor's success test.

The responding (target) actor's success test.

tieBreak: number

Which side a tied contest is awarded to (an OPPOSED_TEST_RESULT_TIEBREAK value) — NONE while the tie stands. Set by resolveTieBreak, or supplied up front by a rule that dictates the victor.

tieBreakReason: TieBreakReason

Which rule settled a broken tie, for the card to report; empty while the tie stands.

Accessors

  • get description(): string
  • Human-readable description shown on the result's chat card.

    Returns string

  • get isTieBroken(): boolean
  • Whether this contest was a tie that the tie-break rule then settled — the two sides reached the same success level, but tieBreak awarded the contest to one of them (see resolveTieBreak).

    Returns boolean

  • get kind(): string
  • The serialization discriminator for this instance — the concrete class's static Kind. Written into the JSON by toJSON under the kind key and read back by sohl.utils.defaultFromJSON to select the constructor. Derived from the class, never stored per-instance.

    Returns string

  • get name(): string
  • Internal identifier for this result (distinct from the display title).

    Returns string

  • get parent(): SohlLogic<any>
  • The Logic that owns this entity. Always present (the constructor rejects a missing parent) and transient — it is not serialized and is re-supplied when the entity is revived or cloned.

    Returns SohlLogic<any>

  • get victoryStarMarks(): boolean[]
  • victoryStars as one entry per star for the card to draw — true where the star is the tester's (drawn filled) and false where it is the target's (drawn hollow), so a glance at the line says who won as well as by how much. Empty when nobody won.

    Returns boolean[]

    Marks, not markup: the card turns each entry into a Font Awesome star (fa-solid / fa-regular), matching how the sheets already draw a filled or hollow flag. Building the <i> elements here would put HTML in the Foundry-free layer for no gain.

  • get victoryStars(): number
  • Victory Stars — how decisively the contest was won: one star per step between the two success levels, or exactly one for a tie settled by the tie-break rule.

    Returns number

    The margin has no ceiling. It is measured on the raw (unclamped) levels, so a modifier that pushes a level past the four-point scale widens the margin with it — a Marginal Success against a Critical Failure worsened by −1 is three stars, not two. An unbroken tie and a mutual failure are both worth none.

Methods

  • Post the opposed-test card via the source's speaker — the request card (opposed-request-card.hbs, with the Respond button) by default, or the result card (opposed-result-card.hbs) when the caller supplies that template (as sohl.entity.modifier.MasteryLevelModifier.opposedTestResume does).

    Both sides are shaped into plain sourceTestResult / targetTestResult data (title, token, item, mlMod display fields, roll, outcome flags) rather than the live results, because the delegated sohl.entity.result.SuccessTestResult.toChat folds this through fvttMergeObject, which deep-copies and would strip a live instance's getters. That delegation also honors the caller's template now (#845), so the opposed card is no longer overridden by the standard test card.

    Parameters

    • data: PlainObject = {}

      Extra template data; template / title select and label the card (request vs. result).

    Returns Promise<void>