import { RenderableText } from '../util/renderableText' import { DiceCombo, DieResult, DieType } from './dieState' export interface AIWeights { // How much this AI likes to choose actions that increase the damage bonus // damageBonusWeight is static and does not change readonly damageBonusWeight: number // How much this AI likes to choose actions that increase the requirement of stop dice in a turn // stopWeight is multiplied by the number of stop dice both players can gain readonly stopWeight: number // How much this AI likes to choose actions that decrease the limit of fail dice in a turn // failWeight is multiplied by the number of fail dice both players can lose readonly failWeight: number // How much this AI likes to choose actions that are finishers for the opponent. // finisherWeight is multiplied by the percentage of max damage the opponent has taken readonly finisherWeight: number // How much this AI dislikes choosing actions that are finishers for itself. // selfFinisherWeight is multiplied by the percentage of max damage the AI has taken // If this would reduce the weight of an action to 0 or less, that action has a weight of 0 and will only be // selected randomly if all actions have a weight of 0. readonly selfFinisherWeight: number // Approximate lead that the AI would prefer to have before ending its turn when it has the option to keep pressing readonly desiredLead: number // Approximate damage behind the previous turn total that the AI is willing to take to play it safe, // assuming doing so wouldn't be fatal (not enough damage to kill or not a finisher) // When there's one fail die left, the AI will prioritize stopping as long as the damage it will be taking is within // a randomly selected 50-150% of this value readonly allowedDamage: number // Integer from 0-100: // 100 means AI keeps rolling until it has one fail die left before trying to stop // 0 means AI always stops as soon as it has at least the desired lead // Anything in between is the percentage chance of continuing, which is rolled once for each fail die remaining // besides the last. If the chance fails once, then the AI uses that turn as if it were trying to stop. // This roll is only performed when the AI already has the lead, is ahead by a value within an acceptable distance // of the desired lead, and the AI has at least two additional fail dice remaining before failing. readonly recklessnessPercent: number // Integer from 0-100: // 0 means AI never holds stops until it's ready to end its turn // 100 means AI always holds stops it sees // Anything in between is the percentage chance of locking a new stop die that appears, rolled once per stop die // needed to end the turn per die that comes up stop. If the chance succeeds once, then the AI holds that stop die. // This roll is only performed when the AI is not already stopping its turn. readonly holdStopsPercent: number } export interface PlayerStartingState extends Pick { // Percentage of damage that this player starts off dealing, default 100 readonly damageBonusBase?: number // Percentage of damage this player's damage increases by with each damage bonus earned, default 10 readonly damageBonusIncrement?: number // Maximum number of damage bonuses that this player can have, or 0 if there's no upper limit readonly maxDamageBonuses?: number // Minimum number of dice required to stop readonly minStopCount: number // Minimum number of dice required to fail readonly minFailCount: number // Maximum number of dice required to stop readonly maxStopCount: number // Maximum number of dice required to fail readonly maxFailCount: number // Base amount of damage that must be dealt on subsequent recoveries to recover, or 0 if recovery is forbidden // Defaults to 1000 readonly recoverBase?: number // Amount by which the amount needed to recover increases each time recovery is earned // Defaults to 1000 readonly recoverIncrement?: number // Percentage of current damage taken that is removed when recovery is earned the first time // Defaults to 50 readonly recoverPercentBase?: number // Percentage points to reduce recoverPercent by for each subsequent recovery // Defaults to 0 readonly recoverPercentIncrement?: number // Instructions for if this player is an AI player. If not specified, this player cannot be played by the AI. readonly aiData?: AIWeights } export enum RoundStarter { LAST_ROUND_LOSER = 'last-round-loser', LAST_ROUND_WINNER = 'last-round-winner', ALTERNATE = 'alternate', } export interface Difficulty { // Name of the difficulty in the select menu readonly name: string // Short description of the difficulty in the select menu readonly shortDescription?: string // Description of the difficulty when selected readonly description?: string // The player who should start in this difficulty; defaults to random readonly startingPlayer?: PlayerSide | null // The player who should start a round; defaults to alternate readonly roundStarter?: PlayerSide | RoundStarter // Starting values for each character readonly stats: { readonly [x in PlayerSide]: PlayerStartingState } } export enum PlayerTextEvent { START_GAME = 'start', START_ROUND = 'round', ABORT_GAME = 'abort', WIN_GAME = 'win', } export interface PlayerText { // Possible random names for this player; if not given a name will not be suggested readonly names?: readonly string[] readonly events?: { readonly [key in ActionTextSide]?: { readonly [key in PlayerTextEvent]?: RenderableText } } // The name of the damage value for this player readonly damage: string // The name of the player's damage limit, defaulting to "Max " + damage readonly maxDamage?: string // The name of this player's stop count requirement readonly stopCount: string // The name of this player's fail count limit readonly failCount: string // The name of this player's incoming damage bonus readonly damageBonus: string } export interface GameTheme { readonly name: string readonly shortDescription: string readonly description: string readonly diceCombos: readonly DiceCombo[] readonly actions: readonly GameAction[] readonly difficulties: readonly Difficulty[] readonly commonText?: { readonly [key: string]: RenderableText } readonly narratorName: string readonly text: { readonly [x in PlayerSide]: PlayerText } } export enum ActionTextEvent { SELECTED = 'select', PASSED = 'pass', REROLLED = 'reroll', ROLLED_FAIL = 'rollFail', NEAR_FAILED = 'nearFail', ROLLED_LAST_FAIL = 'lastFail', FAILED = 'fail', ABANDONED = 'abandon', LOST_ROUND = 'loseRound', DEFEATED = 'defeated', } export enum ActionTextSide { SELF = 'self', OPPONENT = 'opponent', } export interface ActionText { // Name of the action in the select list for this side readonly name: string // Description of the action in the select list for this side readonly shortDescription: string // Description of the action when selected for this side readonly description: string readonly text: { [side in ActionTextSide]?: { [event in ActionTextEvent]?: RenderableText } } } export interface GameAction { // The text from each player's perspective. readonly text: { readonly [x in PlayerSide]: ActionText } // The dice that are rolled for this action readonly dice: readonly DieType[] // True if the loser of this action increases the amount of damage they take readonly givesDamageBonus?: boolean // True if the loser of this action has to get an additional stop die to end their turn readonly givesStopCount?: boolean // True if the loser of this action has one fewer buffer for fail dice readonly givesFailCount?: boolean // Whether this action can end the game in a loss for the loser of this action readonly canFinish?: boolean } export enum PlayerSide { TOP = 'top', BOTTOM = 'bottom', } export function oppositePlayer(side: PlayerSide): PlayerSide { switch (side) { case PlayerSide.BOTTOM: return PlayerSide.TOP case PlayerSide.TOP: return PlayerSide.BOTTOM } } export interface PlayerState { // This player's name readonly name: string // Amount of damage taken so far this battle readonly damage: number // Max damage that can be taken, 0 for endless mode readonly damageMax: number // The total damage taken across this battle readonly damageTotal: number // Number of stop dice required to end a turn with stops readonly stopCount: number // Number of fail dice required to fail a turn by accumulating too many fail dice readonly failCount: number // Incoming damage for this side is multiplied by 100% + 10% * damageBonuses readonly damageBonuses: number // Amount that Total Damage must reach to reduce this player's damage by 50% of its current value // 0 means no recovery is allowed for this player readonly nextRecoverAt: number // Number of times damage was recovered so far this game (adds 1000 + 100 * timesRecovered to nextRecoverAt) readonly timesRecovered: number } export enum GamePhase { ROUND_START = 'round_start', TURN_START = 'turn_start', TURN_ROLLED = 'turn_rolled', TURN_FAILED = 'turn_failed', ABORTED = 'aborted', VICTORY = 'victory', } export interface GameState { // The theme that defines this game for the players. readonly theme: GameTheme // The difficulty selected for this game. readonly difficulty: Difficulty // The current phase of the game. readonly gamePhase: GamePhase // The owner of the current phase readonly phaseOwner: PlayerSide // The initiator of the current round readonly roundOwner: PlayerSide // The state of each player in the game. readonly players: { readonly [x in PlayerSide]: PlayerState } // The action chosen for this round. Defaults to the first action in the list. readonly action: GameAction // The total for the previous turn, or 0 if the current player is taking the first turn // If the current player fails when the turn total is 0, they take the penalty and pass the initiative without taking damage. // This can still end the game if the current action is capable of ending the game for this player and // this player has more damage than their maximum. readonly lastTurnTotal: number // The dice available for the current turn readonly lastRoll: readonly DieResult[] // The total value of the selected dice, or 0 if the selected dice cannot be scored. readonly selectedDiceValue: number // Whether the current dice are sufficient to end the turn. readonly currentDiceEndTurn: boolean // The number of dice that have come up failures so far in the current turn, including the lastRoll. readonly countedFails: number // The total of the dice that have been scored so far this turn readonly currentTurnTotal: number }