import { type GAMERULES, type JSONTextComponent, type Score, SelectorClass, type SingleEntityArgument } from "sandstone"; import type { ATTRIBUTES, BLOCKS, ENTITY_TYPES, ITEMS } from "sandstone/arguments/generated"; import type { ConditionType } from "sandstone/flow"; import type { LiteralStringUnion } from "./utils"; export type TargetNames = LiteralStringUnion<"all" | "self"> | SelectorClass; export declare function mapTarget(target: string | SelectorClass): SelectorClass | string; export declare const Actions: { /** * Send a chat message to everyone. * @param {JSONTextComponent} message - The message to send. */ announce: ({ message }: { message: JSONTextComponent; }) => void; /** * Pick `count` random participants and tag them. Used to assign hidden * roles in social-deduction challenges — combine with `Actions.tellraw` to * privately notify each tagged participant of their assignment. * * Uses Minecraft's `sort=random,limit=N` selector behavior. The selection * happens at command time (typically `start_challenge`), so it's stable * for the rest of the run. * * @example Saboteur assignment in a 4-player game: * ```ts * start_challenge: () => { * Actions.assignRandomTag({ tag: "saboteur", count: 1 }); * // Then DM each tagged participant their secret role: * Actions.tellraw({ * target: Selector("@a", { tag: "saboteur" }), * message: [{ text: "🔪 You're the saboteur. Stop the miners.", color: "red" }], * }); * } * ``` * * `count` is capped to the number of participants — over-asking just tags * everyone available. */ assignRandomTag: ({ tag: tagName, count }: { tag: string; count: number; }) => void; /** * Pick a uniform random integer in `[min, max]` (both inclusive) and * return it as an anonymous `Score`. Wraps Minecraft's `random value` * command, which Sandstone does not expose as a typed primitive — this * helper is the abstraction so that user code never has to write `raw` * for randomness. * * Use to randomize challenge state at `start_challenge` (which goal block * is "the" goal, which player a saboteur is paired with for a side-quest, * etc.) so behavior isn't gameable across runs. * * @example Pick one of 4 goal directions per run: * ```ts * goal_index: { type: "global", default: 0 }, * * start_challenge: () => { * variables.goal_index.score.set(Actions.randomInt({ min: 0, max: 3 })); * // Then branch: _.if(goal_index.equalTo(0), () => place at N), etc. * } * ``` */ randomInt: ({ min, max }: { min: number; max: number; }) => Score; /** * Clear the inventory of a target. * @param {TargetNames} target - The target to clear the inventory of. */ clear: ({ target }: { target: TargetNames; }) => void; /** * Custom action allowing to run any Sandstone command. * * @param {() => void} callback - The function to execute. */ custom: (callback: () => void) => void; /** * Fill a region with a block. * @param {BLOCKS} block - The block to fill the region with. * @param {number} x1 - The x coordinate of the region. * @param {number} y1 - The y coordinate of the region. * @param {number} z1 - The z coordinate of the region. * @param {number} x2 - The x coordinate of the region. * @param {number} y2 - The y coordinate of the region. * @param {number} z2 - The z coordinate of the region. * @param {boolean} absolute - Whether the coordinates are absolute or relative. * @param {"fill" | "line" | "pyramid"} mode - Required. How to fill the region: `"fill"` (solid box between the two points), `"line"` (1-wide line from point 1 to point 2), or `"pyramid"` (pyramid `|y2|` blocks tall, stepping in by 2 per layer). Omitting it throws `Invalid fill mode` at build time. */ fill: ({ block, x1, y1, z1, x2, y2, z2, absolute, mode, }: { block: BLOCKS; x1: number; y1: number; z1: number; x2: number; y2: number; z2: number; absolute: boolean; mode: "fill" | "line" | "pyramid"; }) => void; /** * Give an item to a target. * @param {ITEMS} item - The item to give. * @param {TargetNames} target - The target to give the item to. * @param {number} count - The number of items to give. */ give: ({ item, target, count }: { item: ITEMS; target: TargetNames; count?: number; }) => void; /** * Give loot to a target with a weighted chance for selecting one of the items. * @param {{ name: ITEMS, count: number, weight: number }[]} items - The items to give. * @param {TargetNames} target - The target to give the item to. */ giveLoot: ({ items, target }: { items: [{ name: ITEMS; count: number; weight: number; }]; target: TargetNames; }) => void; /** * Set a gamerule. * @param {GAMERULES} rule - The name of the gamerule. * @param {boolean | number} value - The value to set the gamerule to. */ gamerule: ({ rule, value }: { rule: GAMERULES; value: boolean | number; }) => void; /** * Kill entities matching a selector. * @param {SelectorArgument} selector - The entities to kill. */ kill: ({ selector }: { selector: TargetNames; }) => void; /** * Set the gamemode of a target. Useful for moving an eliminated player * to spectator without killing them (preserves the entity, lets them * watch the rest of the run). * * @example * Actions.setGamemode({ target: "self", mode: "spectator" }); * Actions.setGamemode({ target: "all", mode: "adventure" }); */ setGamemode: ({ target, mode, }: { target: TargetNames; mode: "survival" | "creative" | "adventure" | "spectator"; }) => void; /** * Eliminate a participant from the active round: switch them to * spectator mode (so they can still observe but can't act). Sister * helper to `kill`, intended for vote-out / king-of-the-hill / battle * royale style games where elimination shouldn't end the agent's * connection. * * Note: this only flips gamemode. The challenge author is responsible * for any per-player tracking variable (e.g. `is_alive`). * * @example * Actions.eliminate({ target: "self" }); */ eliminate: ({ target }: { target: TargetNames; }) => void; /** * Set an attribute for a target. * @param {ATTRIBUTES} attribute_ - The attribute to set. * @param {number} value - The value to set the attribute to. * @param {TargetNames} target - The target to set the attribute for. */ setAttribute: ({ attribute_, value, target }: { attribute_: ATTRIBUTES; value: number; target: TargetNames; }) => void; /** * Set the time of day. * @param {'day' | 'night'} time_ - The time to set. */ setTime: ({ time }: { time: "day" | "night"; }) => void; /** * Summon multiple entities at a specific location. */ summonMultiple: (params: { entity: ENTITY_TYPES; count: number; x: number; y: number; z: number; absolute: boolean; }) => void; /** * Set the end state of the challenge. * @param {string} end_state - The end state to set. * @throws {Error} If KRADLE_CHALLENGE_END_STATES is set and endState is not in the list. */ setEndState: ({ endState }: { endState: string; }) => void; /** * For each `(name, condition)` pair, emit `_.if(condition, () => * setEndState(name))` at the current codegen location. Where (and how * often) those checks run is up to the caller — `events.on_tick` for a * per-tick check, `custom_events.actions` for a single fire, etc. * * Returns a `ConditionType` that is true when at least one of the input * conditions is true (i.e. an end-state was applied). Hand it to * `.end_condition()` if you want the game to end as soon as any end-state * has been set; ignore it if the game's end is gated on something else * (timer, separate condition). * * Note: conditions are evaluated in whatever execution context the caller * is in. From `on_tick` that's the server entity, where per-player score * reads silently fail — see `Actions.maxPlayerScore` for the per-player → * global bridge. * * @example * let endReached: ConditionType | undefined; * const challenge = createChallenge({...}); * challenge * .events((vars) => ({ * on_tick: () => { * endReached = Actions.setEndStates({ * winner_found: vars.top_kills.greaterOrEqualThan(20), * all_dead: vars.alive_players.equalTo(0), * }); * }, * })) * .end_condition(() => endReached!); // game ends as soon as any branch fires */ setEndStates: (endStates: Record) => ConditionType; /** * Set a block at a specific location. */ setBlock: (params: { block: BLOCKS; x: number; y: number; z: number; absolute: boolean; }) => void; /** * Teleport entities to a specific location, or to another entity. * @param {TargetNames} target - The entities to teleport. * @param {SingleEntityArgument} toEntity - The entity to teleport to. * @param {number} x - The x coordinate of the destination. * @param {number} y - The y coordinate of the destination. * @param {number} z - The z coordinate of the destination. * @param {boolean} absolute - Whether the coordinates are absolute or relative. */ teleport: (args: { target: TargetNames; x: number; y: number; z: number; absolute: boolean; } | { target: TargetNames; toEntity: SingleEntityArgument; }) => void; /** * Force the target player(s) to immediately interrupt whatever code they are * running and walk to the given absolute coordinates. Server-initiated: the * challenge forces the move, unlike normal agent movement skills. The agents * always walk to the destination — they are never teleported, even in cheat * mode. Only the interrupt plus a single pathfind are guaranteed; an agent * may decide to walk away again on its next action. * @param {TargetNames} target - "self", "all", a role name, or a Selector. * "self" is the acting agent and only resolves inside a per-player * context; a forceMoveTo("self") reachable from a contextless server * function is caught by the build context-safety check. Raw "@..." * selector strings are rejected by mapTarget — use "self" or a Selector. * @param {number} x - Absolute x coordinate to move to. * @param {number} y - Absolute y coordinate to move to. * @param {number} z - Absolute z coordinate to move to. */ forceMoveTo: ({ target, x, y, z }: { target: TargetNames; x: number; y: number; z: number; }) => void; /** * Send a chat message to a target. * @param {JSONTextComponent} message - The message to send. * @param {TargetNames} target - The target to send the message to. */ tellraw: ({ message, target }: { message: JSONTextComponent; target: TargetNames; }) => void; /** * Increment a score variable by 1. * @param variable - The score variable to increment. */ increment: ({ variable }: { variable: Score; }) => void; /** * Decrement a score variable by 1. * @param variable - The score variable to decrement. */ decrement: ({ variable }: { variable: Score; }) => void; /** * Set a score variable to a specific value. * @param variable - The score variable to set. * @param value - The value to set the score variable to, which can be a number or another score variable. */ set: ({ variable, value }: { variable: Score; value: number | Score; }) => void; /** * Selector that matches `@s` only when standing on the block at the * given absolute coordinate. Use this anywhere you'd otherwise have * written `Selector("@s", { x, y, z })` — that bare form does NOT * constrain position (Minecraft treats x/y/z as the selector origin * for distance math, not as a position filter), so the condition * silently passes for everyone. This helper bakes in the right * `dx: 0, dy: 1, dz: 0` volume covering the block above and the * head space, so the selector matches only when the player's feet * are inside the 1×1×1 column at (x, y+1, z). * * @param {number} x - X of the block being stood on. * @param {number} y - Y of the block being stood on (the player's feet are at y+1). * @param {number} z - Z of the block being stood on. * @param {string} [role] - Optional role tag the player must also have. * * @example * // Trigger alice_shared when Alice steps on her pad block. * alice_shared: { * type: "global", * default: 0, * updater: (value) => { * _.if(value.equalTo(0), () => { * forEveryPlayer(() => { * _.if(Actions.standingOnBlock({ x: ALICE_PAD.x, y: ALICE_PAD.y, z: ALICE_PAD.z, role: "alice" }), () => { * value.set(1); * }); * }); * }); * }, * }, */ standingOnBlock: ({ x, y, z, role }: { x: number; y: number; z: number; role?: string; }) => SelectorClass; /** * Condition that matches `@s` when the player has voted in `voteId` (any * option), or — when `option` is given — only when they voted for that * specific option. Agents cast votes with skills.voteForOption; the arena * records each pick as the player tags kradle.voteOptions. and * kradle.voteOptions..