TypeScript 97.6%
SQL 1.4%
JavaScript 0.5%
1import type { GameDefinition, GameSymbol, SymbolStyle, SymbolTier } from "./types";23type Optional = "payScale" | "tags" | "rules" | "featureNames" | "id" | "minBet" | "maxBet" | "betDivisor";45/** `defineGame` fills defaults and derives feature names from the configured mechanics. */6export function defineGame(input: Omit<GameDefinition, Optional> & Partial<Pick<GameDefinition, Optional>>): GameDefinition {7 const def: GameDefinition = {8 id: input.id ?? input.slug,9 minBet: input.minBet ?? 10,10 maxBet: input.maxBet ?? 1000,11 payScale: input.payScale ?? 1,12 betDivisor: input.betDivisor ?? (input.payModel.type === "lines" ? input.payModel.lines.length : input.grid.reels >= 6 ? 50 : 25),13 tags: input.tags ?? [],14 rules: input.rules ?? [],15 featureNames: input.featureNames ?? [],16 ...input,17 } as GameDefinition;18 if (def.featureNames.length === 0) def.featureNames = deriveFeatureNames(def);19 return def;20}2122export function deriveFeatureNames(def: GameDefinition): string[] {23 const f: string[] = [];24 if (def.payModel.type === "ways") f.push(`${waysCount(def)} ways`);25 else f.push(`${def.payModel.lines.length} paylines`);26 if (def.wild?.expanding) f.push("Expanding wilds");27 if (def.wild?.sticky) f.push("Sticky wilds");28 if (def.wild?.stacked) f.push("Stacked wilds");29 if (def.wild?.exploding) f.push("Exploding wilds");30 if (def.wild?.moving) f.push("Moving wilds");31 if (def.wild?.floating) f.push("Random wilds");32 if (def.wild?.multiplier) f.push("Multiplier wilds");33 if (def.cascades) f.push("Cascades");34 if (def.scatter) f.push("Free spins");35 if (def.spinCollect) f.push("Collect multiplier");36 if (def.holdRespin) f.push("Hold & respin");37 if (def.pickBonuses?.length) f.push("Bonus game");38 if (def.meter) f.push("Charge meter");39 if (def.heat) f.push("Heat meter");40 if (def.mystery) f.push("Mystery symbols");41 if (def.randomFeatures) f.push("Feature drops");42 if (def.quantum) f.push("Quantum split");43 if (def.dynamicGrid) f.push("Dynamic grid");44 if (def.jackpot || def.holdRespin) f.push("Jackpots");45 return f;46}4748export function waysCount(def: GameDefinition): number {49 return Math.pow(def.grid.rows, def.grid.reels);50}5152/** Helper for concise symbol declarations. */53export function sym(54 id: string,55 name: string,56 tier: SymbolTier,57 pays: Record<number, number> | null,58 weight: number | number[],59 style: SymbolStyle,60 extra: Partial<GameSymbol> = {},61): GameSymbol {62 return {63 id,64 name,65 kind: extra.kind ?? "regular",66 tier,67 pays: pays ?? undefined,68 weight,69 style,70 ...extra,71 };72}7374export const wildSym = (id: string, name: string, weight: number | number[], style: SymbolStyle, extra: Partial<GameSymbol> = {}): GameSymbol =>75 sym(id, name, "special", null, weight, style, { kind: "wild", ...extra });7677export const scatterSym = (id: string, name: string, weight: number | number[], style: SymbolStyle, scatterPays?: Record<number, number>, extra: Partial<GameSymbol> = {}): GameSymbol =>78 sym(id, name, "special", null, weight, style, { kind: "scatter", scatterPays, ...extra });79