/**
 * Translate an Ability DSL `effect` tree into the {@link Buff} stack it
 * contributes (for an attacker-perspective crunch) along with a list of
 * effect fragments the translator could not auto-apply.
 *
 * The buff layer is intentionally a subset of the DSL: it covers the math the
 * cruncher's expected-value engine reads (rerolls, die-roll modifiers, S/A/T
 * stat shifts, FNP, granted weapon keywords, cover) and reports everything
 * else — choice nodes (player decisions), dice-gated effects (stochastic),
 * defender-side bs-modifier, attack-restrictions, ability grants, mortal
 * wound triggers — as `unsupported` so the SPA can surface "this ability has
 * effects we can't auto-apply" rather than silently dropping them.
 *
 * The walker classifies an effect's `target` against the attacker
 * perspective: `self`, `bearer`, `unit`, `attached-unit`, `attacker`, and
 * `friendly-within-aura` are all treated as "applies to my unit". `defender`,
 * `enemy-within-aura`, and `all-enemy` are dropped without being marked
 * unsupported — those are defender-side mods and would surface from the
 * target's perspective (M3 work), not the attacker's.
 *
 * @packageDocumentation
 */
import type { Buff, BuffSource, EngineContext, WeaponKeywordRef } from "./buffs.js";
/** A fragment we couldn't translate. The SPA can render these as warnings. */
export type UnsupportedFragment = {
    reason: string;
    effectFragment: unknown;
};
/**
 * A mutually-limited pool of {@link ActivatableBuff} levers. Dice-pool
 * allocations cap how many options fire at once (`max_activations`); a `choice`
 * lets the player pick exactly one. Levers sharing a `group.id` are subject to
 * that cap — the SPA greys out further checkboxes once it's reached, and an
 * optimizer enumerates subsets within it.
 */
export type ActivatableGroupRef = {
    id: string;
    maxActivations: number;
};
/**
 * A buff-bearing *player decision* the cruncher can't make on its own: a
 * dice-pool option, a `choice` branch, or an activation gated on a timing the
 * player controls (e.g. "start of phase"). It is not auto-applied — the
 * consumer opts in (a checkbox, or an optimizer's search) and then folds
 * {@link buffs} into the crunch. Conditions the activation still carries (a
 * target keyword, a phase) ride on each buff's `applicableWhen`, so the
 * resolver gates them per-target rather than the lever vanishing.
 */
export type ActivatableBuff = {
    /** Stable toggle id, e.g. `"blessings-of-khorne#Warp Blades"`. */
    id: string;
    /** Human label for the lever (option name, or a summary of its buffs). */
    label: string;
    /** Contributions this activation adds when the player opts in (≥1). */
    buffs: Buff[];
    /** Set when the lever belongs to a mutually-limited pool. */
    group?: ActivatableGroupRef;
};
export type EffectTranslation = {
    applied: Buff[];
    unsupported: UnsupportedFragment[];
    /** Buffs sitting behind a player decision — see {@link ActivatableBuff}. */
    activatable: ActivatableBuff[];
};
/**
 * Whose perspective the translation runs from.
 *
 * - `"attacker"`: the buffed unit is *firing*. `target: "unit"/"self"` etc.
 *   become attacker-side mods (re-rolls, hit/wound mods, A/S shifts, granted
 *   keywords). `target: "defender"` is silently dropped — that's incoming
 *   penalty math relevant when the buffed unit is the *target*, surfaced via
 *   the `"target"` perspective instead.
 *
 * - `"target"`: the buffed unit is *being shot at*. Defensive mods on the
 *   buffed unit (`stat-modifier T`, `stat-modifier Sv`, `feel-no-pain`,
 *   `roll-modifier save`) become defender-side buffs. Conversely, attacker-
 *   only mods (re-rolls, hit/wound mods, A/S shifts) drop silently because
 *   they describe what the buffed unit does when *attacking*.
 *
 * The bs-modifier effect (a -1 to incoming hit rolls, e.g. Benefit of Cover)
 * becomes a `hit-mod` buff under target perspective so it stacks correctly
 * with attacker-side modifiers in the resolver's ±1 cap.
 */
export type TranslationPerspective = "attacker" | "target";
/**
 * Walk an ability DSL `effect` tree and produce the buff stack it contributes
 * against `context` from the given `perspective`, plus an `unsupported` list
 * naming any branches the buff layer can't express today.
 */
export declare function effectToBuffs(effect: unknown, source: BuffSource, context: EngineContext, perspective?: TranslationPerspective): EffectTranslation;
/**
 * Parse a printed weapon-keyword string (e.g. `"Sustained Hits 1"`,
 * `"Anti-INFANTRY 4+"`, `"Lethal Hits"`) into a `{keyword_id, parameters?}`
 * catalog reference, or `null` if the form is unrecognised.
 *
 * Reverses the conventions baked into the M0 catalog: kebab-case ids,
 * trailing number → `value`, embedded keyword + threshold → `target_keyword`
 * + `threshold`.
 */
export declare function parseKeywordGrant(raw: string): WeaponKeywordRef | null;
//# sourceMappingURL=from-dsl.d.ts.map