import { Assets, Ticker } from 'pixi.js'; import { Meta, PixiStory, StoryFn } from '@pixi/storybook-renderer'; import HoldAndWinMachine from 'src/slotMachines/HoldAndWinMachine'; import { SlotMachineConfig } from 'src/types/SlotMachineConfig'; import { centerView } from 'src/stories/utils/resize'; import MachineContainer from 'src/stories/utils/MachineContainer'; import { createScreenInputMap } from 'src/stories/utils/createScreenInputMap'; import SlotMultipliersSystem from 'src/systems/SlotMultipliersSystem'; import SlotMultiplierEntity from 'src/entities/SlotMultiplierEntity'; import { STATES } from 'src/states/BasicStateMachine'; import {argTypes, getDefaultArgs} from "src/stories/utils/argTypes"; const args = { accelerationTime: 1, backCoef: 1.1, maxSpeed: 15, reelStartDelay: 0.2, reelStopDelay: 0.5, slotStopDelay: 0, spinningDuration: 2, blur: false, bounce: true }; /** * Creates argTypes with fractional range steps for finer Hold & Win tuning. */ const createHoldAndWinArgTypes = (initialArgs: typeof args): ReturnType => { const baseArgTypes = argTypes(initialArgs); Object.keys(initialArgs).forEach((key) => { const descriptor = baseArgTypes[key]; const control = descriptor?.control; if (!control || control.type !== 'range') return; baseArgTypes[key] = { ...descriptor, control: { ...control, step: control.step && control.step < 1 ? control.step : 0.1, }, }; }); return baseArgTypes; }; const meta: Meta = { title: 'systems/SlotMultipliersSystem', tags: ['autodocs'], parameters: { docs: { description: { component: 'Displays Spine-based multiplier overlays for every slot based on the slotMultipliers map.', }, }, }, argTypes: createHoldAndWinArgTypes(args), args: getDefaultArgs(args), }; export default meta; /** * Updates the multiplier map with random positive values and zeroed blanks. */ function randomiseMultipliers(machine: HoldAndWinMachine): void { const total = machine.config.reels * machine.config.slots; machine.maps.slotMultipliers = Array.from({ length: total }, () => (Math.random() > 0.6 ? Math.ceil(Math.random() * 10) : 0)); } export const HoldAndWinMultipliers: StoryFn = (_params, context) => new PixiStory({ context, init: async (view) => { Assets.reset(); await Assets.init({ manifest: 'hold-and-win/manifest.json' }); await Assets.loadBundle('configs'); await Assets.loadBundle('symbols'); await Assets.loadBundle('addons'); const config: SlotMachineConfig = Assets.get('slot_machine_config'); const machine = new HoldAndWinMachine(config); const container = new MachineContainer(machine); container.scale.set(1); view.addChild(container); context.machine = machine; context.prevSpinState = machine.systems.spin.state; machine.inputs.initMap = createScreenInputMap(config); machine.inputs.screenMap = machine.inputs.initMap; const slotMultipliersSystem = new SlotMultipliersSystem(machine); slotMultipliersSystem.setSettings({ entityClass: SlotMultiplierEntity }); machine.systems.slotMultipliers = slotMultipliersSystem; // Apply story args to spin system and trigger spin machine.systems.spin.setSettings(_params as any); const idleState = machine.stateMachine.states[STATES.IDLE]; if (idleState && !idleState.systems.includes('slotMultipliers')) { idleState.systems.push('slotMultipliers'); } const spinningState = machine.stateMachine.states[STATES.SPINNING]; if (spinningState && !spinningState.systems.includes('slotMultipliers')) { spinningState.systems.push('slotMultipliers'); } randomiseMultipliers(machine); machine.inputs.spin = true; context.spinDelayMs = 0; centerView(view); }, resize: centerView, update: () => { const machine: HoldAndWinMachine | undefined = context.machine; if (!machine) return; const dt = Ticker.shared.deltaMS; machine.update(dt); const spinSystem = machine.systems.spin; const prevState = context.prevSpinState ?? spinSystem.state; if (prevState !== spinSystem.state) { if (spinSystem.state === 'starting') { machine.inputs.spin = false; } if (spinSystem.state === 'stopped') { context.spinDelayMs = 500; } context.prevSpinState = spinSystem.state; } if ((context.spinDelayMs ?? 0) > 0) { context.spinDelayMs -= dt; if (context.spinDelayMs <= 0) { randomiseMultipliers(machine); machine.inputs.spin = true; context.spinDelayMs = 0; } } }, });