SPB Git forge

spb/spinza

Public
8commits 1branches 0releases
1.6 MBsize
maindefault branch
16 days agolast push
TypeScript 97.6% SQL 1.4% JavaScript 0.5%
3.0 KB · 79 lines typescript
Raw Blame History
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