/** * THE WANTED BOARD (A1, T84, 2026-10-14; AREA_PROPOSALS.md "The Wanted Board"): player bounties in the Dreadwoods. A board in * Gallowmere's palisade (a safe pocket, nobody can be attacked there) where a player the woods' PvP has wronged can put coins on * the head of the player who killed them. Hunters claim the pot by killing the target in the woods. * * The rules, all enforced by the server (backend wantedBoard.ts), all PLACEHOLDER numbers (balance is done last): * - RIGHT TO POST: only after a real woods kill recorded by the server (not a duel, not a safe pocket). One kill = one bounty, * posted within WANTED_KILL_WINDOW_MS, on the player who killed you, never on yourself, never on your own account's other character. * - THE POT is taken out of the poster's bag when posted and held in escrow (it is nobody's until the bounty ends), plus a FEE that is * not held: it is burned (a coin sink), so posting is never free. Pots are capped; so are open bounties per poster and per target. * - EXPIRY: a bounty ends WANTED_EXPIRY_MS after posting and the pot goes back to the poster (the fee does not). The poster can also * cancel at the board for the same refund. A refund or a payout to a player who is offline waits (saved) and is paid at their next join. * - CLAIM: the hunter must kill the target in the woods (PvP zone, a woods fight, not a duel), within WANTED_MAX_LEVEL_GAP levels, * and must not be the poster, the target, or on either's account. The same hunter claiming on the same target again within * WANTED_CLAIM_PAIR_COOLDOWN_MS is paid nothing, and a hunter is paid at most WANTED_HUNTER_DAILY_CAP times a day. * - A repeated kill by the same killer on the same victim inside WANTED_PAIR_KILL_COOLDOWN_MS gives no new right to post. * * Every number is a world tile or a placeholder. Backend wantedBoard.ts keeps the live board and world.ts wires it in. */ export declare const WANTED_KEEPER: { readonly id: "wanted-keeper"; readonly name: "Bailiff Wynn Ashby"; readonly x: 395; readonly z: 610; readonly faceX: 395; readonly faceZ: 614; readonly leash: 1; }; export declare const WANTED_KEEPER_REACH = 3; /** Where the board stands, for the guide and the verify links. */ export declare const WANTED_BOARD_PLACE = "Gallowmere's palisade"; /** The keeper's menu actions (npc_action ids). */ export declare const WANTED_READ_ACTION = "wanted-read"; export declare const WANTED_KILLERS_ACTION = "wanted-killers"; export declare const WANTED_MINE_ACTION = "wanted-mine"; export declare const WANTED_CANCEL_ACTION = "wanted-cancel"; export declare const WANTED_POST_ACTIONS: readonly string[]; export declare const WANTED_ACTIONS: readonly string[]; export declare function isWantedAction(action: string): boolean; /** PLACEHOLDER pots for the three "post on my latest killer" buttons, and the bounds of a typed `/wanted post `. */ export declare const WANTED_POT_TIERS: readonly number[]; export declare const WANTED_MIN_POT = 50; export declare const WANTED_MAX_POT = 2000; /** The fee on top of the pot: a percentage, at least the minimum. Burned, never held. */ export declare const WANTED_FEE_PERCENT = 10; export declare const WANTED_FEE_MIN = 10; export declare const WANTED_EXPIRY_MS: number; /** A kill gives the right to post for this long. */ export declare const WANTED_KILL_WINDOW_MS: number; /** A repeated kill by the same killer on the same victim inside this gives no new right to post. */ export declare const WANTED_PAIR_KILL_COOLDOWN_MS: number; export declare const WANTED_CLAIM_PAIR_COOLDOWN_MS: number; export declare const WANTED_HUNTER_DAILY_CAP = 3; export declare const WANTED_HUNTER_WINDOW_MS: number; export declare const WANTED_MAX_LEVEL_GAP = 10; export declare const WANTED_MIN_COMBAT = 10; export declare const WANTED_POSTS_PER_POSTER = 2; export declare const WANTED_OPEN_PER_TARGET = 3; export declare const WANTED_BOARD_MAX = 200; export declare const WANTED_KILLS_MAX = 400; export declare const WANTED_KILLS_PER_VICTIM = 5; export declare const WANTED_OWED_PER_CHARACTER = 20; export declare const WANTED_CLAIMS_MAX = 400; /** Ids of settled payouts a character remembers, so a payout is never paid twice after a crash (Character.wantedSettled). */ export declare const WANTED_SETTLED_MAX = 60; /** Ids of bounties a poster has funded, so a half-finished posting is told from a finished one after a crash (Character.wantedFunded). */ export declare const WANTED_FUNDED_MAX = 40; /** Ledger lines (section `wanted`); the server writes each mark. */ export declare const LEDGER_WANTED_XP = 60; export declare const LEDGER_WANTED_LINES: readonly { id: string; label: string; }[]; export type WantedKill = { id: string; killerId: string; killerAccount: string; killerName: string; victimId: string; victimAccount: string; victimName: string; at: number; used: boolean; }; export type WantedBounty = { id: string; posterId: string; posterAccount: string; posterName: string; targetId: string; targetAccount: string; targetName: string; pot: number; createdAt: number; expiresAt: number; /** False between "the board took the note" and "the poster's coins were saved as gone" (see backend wantedBoard.ts, reconcile). */ funded: boolean; killId: string; }; export type WantedOwedWhy = 'claim' | 'expired' | 'cancelled' | 'unfunded-cancelled'; /** Coins owed to a character who was not online when the bounty ended. Paid once at their next join. */ export type WantedOwed = { id: string; charId: string; coins: number; why: WantedOwedWhy; at: number; text: string; }; export type WantedClaimRecord = { hunterId: string; targetId: string; at: number; }; export type WantedSave = { v: 1; seq: number; bounties: WantedBounty[]; kills: WantedKill[]; owed: WantedOwed[]; claims: WantedClaimRecord[]; }; export declare function emptyWantedSave(): WantedSave; export declare function wantedFee(pot: number): number; /** What the poster pays out of the bag: the pot (held) plus the fee (burned). */ export declare function wantedCost(pot: number): number; export declare function wantedPotValid(pot: unknown): pot is number; export declare function wantedTimeLeft(ms: number): string; /** The bounties still open (not past their end) on a target. */ export declare function wantedOpenOn(save: WantedSave, targetId: string, now: number): WantedBounty[]; /** The kills that gave `victimId` the right to post and have not been used or expired, newest first. */ export declare function wantedKillersOf(save: WantedSave, victimId: string, now: number): WantedKill[]; export type WantedCheck = { ok: true; } | { ok: false; reason: string; }; /** * Whether a kill may be written down as giving the victim the right to post. A repeated kill by the same killer on the same victim * inside the cooldown is not (pairs trading kills cannot farm the right), nor is a kill of one of your own account's characters. */ export declare function wantedKillRecordable(save: WantedSave, kill: Pick): WantedCheck; export type WantedPoster = { id: string; account: string; combat: number; }; /** Whether a poster may put `pot` on the killer named by `kill` now. `coins` is what their bag holds. */ export declare function wantedPostCheck(save: WantedSave, poster: WantedPoster, kill: WantedKill | null, targetCombat: number, pot: number, coins: number, now: number): WantedCheck; export type WantedHunter = { id: string; account: string; combat: number; }; /** Whether `hunter` felling `target` collects `bounty` now (the kill itself was already checked as a woods kill). */ export declare function wantedClaimCheck(save: WantedSave, bounty: WantedBounty, hunter: WantedHunter, target: { id: string; account: string; combat: number; }, now: number): WantedCheck; /** The board as chat lines. `viewerId` marks your own postings and the ones on your head. */ export declare function wantedBoardLines(save: WantedSave, now: number, viewerId?: string): string[]; /** Whatever the database held, made safe: bounded lists, whole numbers, unknown shapes dropped. */ export declare function parseWantedSave(raw: unknown): WantedSave; //# sourceMappingURL=wantedBoard.d.ts.map