@energy8platform/game-engine 0.40.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -4
- package/dist/devtools.cjs.js +2 -0
- package/dist/devtools.cjs.js.map +1 -1
- package/dist/devtools.d.ts +12 -0
- package/dist/devtools.esm.js +2 -0
- package/dist/devtools.esm.js.map +1 -1
- package/dist/reel-panel-client.cjs.js +2 -0
- package/dist/reel-panel-client.cjs.js.map +1 -1
- package/dist/reel-panel-client.esm.js +2 -0
- package/dist/reel-panel-client.esm.js.map +1 -1
- package/dist/slot.cjs.js +24 -7
- package/dist/slot.cjs.js.map +1 -1
- package/dist/slot.d.ts +20 -0
- package/dist/slot.esm.js +24 -7
- package/dist/slot.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/slot/config/ReelSystemConfig.ts +13 -0
- package/src/slot/devtools/fieldSchema.ts +1 -0
- package/src/slot/motion/AnticipationController.ts +12 -2
- package/src/slot/motion/SpinEngine.ts +16 -2
- package/src/slot/system/ReelSystem.ts +5 -1
package/package.json
CHANGED
|
@@ -184,6 +184,8 @@ export interface AnticipationOverride {
|
|
|
184
184
|
slowdown?: PerReel<number>;
|
|
185
185
|
/** Extra hold before landing. Scalar, or per-reel indexed by reel index. */
|
|
186
186
|
holdMs?: PerReel<number>;
|
|
187
|
+
/** Growth of the gap between successive cells within a reel. Scalar, or per-reel. */
|
|
188
|
+
cellStaggerRamp?: PerReel<number>;
|
|
187
189
|
}
|
|
188
190
|
|
|
189
191
|
export interface AnticipationConfig {
|
|
@@ -213,6 +215,16 @@ export interface AnticipationConfig {
|
|
|
213
215
|
progressiveSlowdown: number;
|
|
214
216
|
/** Extra hold (ms) added per successive anticipated reel: reel #i gets `holdMs + i * this`. */
|
|
215
217
|
progressiveHoldMs: number;
|
|
218
|
+
/**
|
|
219
|
+
* `cascade-drop`: how the gap between SUCCESSIVE CELLS grows inside an anticipated reel. The
|
|
220
|
+
* gap before cell #i is `cellStagger * <reel slowdown> * progressiveCellStagger ** i`, so 1
|
|
221
|
+
* (the default) keeps the reel's cells evenly spaced and > 1 makes each symbol land later than
|
|
222
|
+
* the last — the drip that turns a reel into a countdown.
|
|
223
|
+
*
|
|
224
|
+
* It compounds with `progressiveSlowdown`: that widens the base gap reel by reel, this widens
|
|
225
|
+
* it cell by cell, so a later reel drips both slower AND with a steeper ramp.
|
|
226
|
+
*/
|
|
227
|
+
progressiveCellStagger: number;
|
|
216
228
|
/** Optional grid zoom while anticipating (magnum-opus uses 1.3×). */
|
|
217
229
|
zoom: { enabled: boolean; scale: number; ms: number };
|
|
218
230
|
}
|
|
@@ -503,6 +515,7 @@ export const DEFAULT_REEL_CONFIG: ReelSystemConfig = {
|
|
|
503
515
|
decide: null,
|
|
504
516
|
progressiveSlowdown: 1,
|
|
505
517
|
progressiveHoldMs: 0,
|
|
518
|
+
progressiveCellStagger: 1,
|
|
506
519
|
zoom: { enabled: false, scale: 1.15, ms: 600 },
|
|
507
520
|
},
|
|
508
521
|
cascade: {
|
|
@@ -151,6 +151,7 @@ export const REEL_FIELD_SCHEMA: Section[] = [
|
|
|
151
151
|
{ kind: 'range', path: 'anticipation.holdMs', label: 'Hold (ms)', min: 0, max: 1200, step: 50 },
|
|
152
152
|
{ kind: 'range', path: 'anticipation.progressiveSlowdown', label: 'Slowdown ramp ×/reel', min: 0.3, max: 1, step: 0.05 },
|
|
153
153
|
{ kind: 'range', path: 'anticipation.progressiveHoldMs', label: 'Hold ramp (ms/reel)', min: 0, max: 600, step: 25 },
|
|
154
|
+
{ kind: 'range', path: 'anticipation.progressiveCellStagger', label: 'Cell ramp ×/cell', min: 1, max: 2.5, step: 0.05 },
|
|
154
155
|
{ kind: 'toggle', path: 'anticipation.zoom.enabled', label: 'Reel zoom' },
|
|
155
156
|
{ kind: 'range', path: 'anticipation.zoom.scale', label: 'Zoom scale', min: 1, max: 1.6, step: 0.05 },
|
|
156
157
|
{ kind: 'range', path: 'anticipation.zoom.ms', label: 'Zoom (ms)', min: 200, max: 1200, step: 50 },
|
|
@@ -18,10 +18,18 @@ export interface AnticipationDecision {
|
|
|
18
18
|
slowdown: PerReel<number>;
|
|
19
19
|
/** Extra hold before landing. Scalar or per-reel array, same as `slowdown`. */
|
|
20
20
|
holdMs: PerReel<number>;
|
|
21
|
+
/** `cascade-drop`: growth of the gap between successive cells inside the reel (1 = even). */
|
|
22
|
+
cellStaggerRamp: PerReel<number>;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/** Fresh "nothing to anticipate" decision (fresh, so callers may mutate `reels` freely). */
|
|
24
|
-
const none = (): AnticipationDecision => ({
|
|
26
|
+
const none = (): AnticipationDecision => ({
|
|
27
|
+
active: false,
|
|
28
|
+
reels: [],
|
|
29
|
+
slowdown: 1,
|
|
30
|
+
holdMs: 0,
|
|
31
|
+
cellStaggerRamp: 1,
|
|
32
|
+
});
|
|
25
33
|
|
|
26
34
|
export class AnticipationController {
|
|
27
35
|
private _cfg: AnticipationConfig;
|
|
@@ -53,7 +61,7 @@ export class AnticipationController {
|
|
|
53
61
|
if (!custom) return none();
|
|
54
62
|
const o: AnticipationOverride = Array.isArray(custom) ? { reels: custom } : custom;
|
|
55
63
|
if (!o.reels?.length) return none();
|
|
56
|
-
return this.build(o.reels.slice(), o.slowdown, o.holdMs);
|
|
64
|
+
return this.build(o.reels.slice(), o.slowdown, o.holdMs, o.cellStaggerRamp);
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
if (Array.isArray(this._cfg.reels)) {
|
|
@@ -86,10 +94,12 @@ export class AnticipationController {
|
|
|
86
94
|
reels: number[],
|
|
87
95
|
slowdown?: PerReel<number>,
|
|
88
96
|
holdMs?: PerReel<number>,
|
|
97
|
+
cellStaggerRamp?: PerReel<number>,
|
|
89
98
|
): AnticipationDecision {
|
|
90
99
|
return {
|
|
91
100
|
active: true,
|
|
92
101
|
reels,
|
|
102
|
+
cellStaggerRamp: cellStaggerRamp ?? this._cfg.progressiveCellStagger,
|
|
93
103
|
slowdown:
|
|
94
104
|
slowdown ??
|
|
95
105
|
this.ramp(reels, this._cfg.slowdownFactor, (base, i) =>
|
|
@@ -38,6 +38,12 @@ export interface SpinRunOpts {
|
|
|
38
38
|
anticipateSlowdown?: PerReel<number>;
|
|
39
39
|
/** Extra hold (ms) for anticipated reels. Scalar, or per-reel indexed by reel. */
|
|
40
40
|
anticipateHoldMs?: PerReel<number>;
|
|
41
|
+
/**
|
|
42
|
+
* `cascade-drop`: growth of the gap between successive cells inside an anticipated reel — the
|
|
43
|
+
* gap before cell #i is `cellStagger * <reel slowdown> * ramp ** i`. 1 keeps the reel evenly
|
|
44
|
+
* spaced. Scalar, or per-reel indexed by reel.
|
|
45
|
+
*/
|
|
46
|
+
anticipateCellStaggerRamp?: PerReel<number>;
|
|
41
47
|
/**
|
|
42
48
|
* Reels whose tape runs normally but whose landing is NOT handed back. The engine stops and
|
|
43
49
|
* disposes of the tape as usual and leaves the real cells hidden and unseated; the caller owns
|
|
@@ -137,6 +143,7 @@ export class SpinEngine {
|
|
|
137
143
|
const anticipate = new Set(opts?.anticipateReels ?? []);
|
|
138
144
|
const defer = new Set(opts?.deferReveal ?? []);
|
|
139
145
|
const holds: number[] = [];
|
|
146
|
+
const ramps: number[] = [];
|
|
140
147
|
const out: ReelStopPlan[] = [];
|
|
141
148
|
for (let reel = 0; reel < cols; reel++) {
|
|
142
149
|
const idx = order(reel);
|
|
@@ -154,6 +161,7 @@ export class SpinEngine {
|
|
|
154
161
|
const hold = isAnticipated ? perReelValue(opts?.anticipateHoldMs, reel, 0) * f : 0;
|
|
155
162
|
stopTime += hold;
|
|
156
163
|
holds[reel] = hold;
|
|
164
|
+
ramps[reel] = isAnticipated ? perReelValue(opts?.anticipateCellStaggerRamp, reel, 1) : 1;
|
|
157
165
|
const speed = isAnticipated ? perReelValue(opts?.anticipateSlowdown, reel, 1) : 1;
|
|
158
166
|
|
|
159
167
|
out.push({
|
|
@@ -166,7 +174,7 @@ export class SpinEngine {
|
|
|
166
174
|
deferred: defer.has(reel),
|
|
167
175
|
});
|
|
168
176
|
}
|
|
169
|
-
if (this._cfg.style === 'cascade-drop') this._planDrop(out, holds, f, order);
|
|
177
|
+
if (this._cfg.style === 'cascade-drop') this._planDrop(out, holds, ramps, f, order);
|
|
170
178
|
return out;
|
|
171
179
|
}
|
|
172
180
|
|
|
@@ -179,6 +187,7 @@ export class SpinEngine {
|
|
|
179
187
|
private _planDrop(
|
|
180
188
|
out: ReelStopPlan[],
|
|
181
189
|
holds: number[],
|
|
190
|
+
ramps: number[],
|
|
182
191
|
f: number,
|
|
183
192
|
order: (reel: number) => number,
|
|
184
193
|
): void {
|
|
@@ -205,10 +214,15 @@ export class SpinEngine {
|
|
|
205
214
|
const chained = chainFrom >= 0 && position > 0 && position >= chainFrom;
|
|
206
215
|
const start = (chained ? previousEnd + gap : position * gap) + (holds[p.reel] ?? 0);
|
|
207
216
|
|
|
217
|
+
// The gap before cell #i is `cellStagger * scale * ramp**i` — accumulate rather than
|
|
218
|
+
// multiply, so a ramp of 1 stays exactly the old evenly-spaced schedule.
|
|
219
|
+
const ramp = ramps[p.reel] ?? 1;
|
|
208
220
|
const cells: number[] = [];
|
|
221
|
+
let offset = 0;
|
|
209
222
|
for (let i = 0; i < rows; i++) {
|
|
210
223
|
const row = bottomUp ? rows - 1 - i : i;
|
|
211
|
-
cells[row] = start +
|
|
224
|
+
cells[row] = start + offset + fall;
|
|
225
|
+
offset += this._cfg.cellStagger * scale * Math.pow(ramp, i);
|
|
212
226
|
}
|
|
213
227
|
p.cellStopTimes = cells;
|
|
214
228
|
p.stopTime = cells.length ? Math.max(...cells) : start;
|
|
@@ -215,12 +215,15 @@ export function createReelSystem(opts: CreateReelSystemOptions): ReelSystem {
|
|
|
215
215
|
function resolveAnticipation(target: CellData[][], runOpts?: SpinRunOpts): AnticipationDecision {
|
|
216
216
|
const explicit = runOpts?.anticipateReels;
|
|
217
217
|
if (!explicit) return anticipation.decide(target);
|
|
218
|
-
if (!explicit.length)
|
|
218
|
+
if (!explicit.length)
|
|
219
|
+
return { active: false, reels: [], slowdown: 1, holdMs: 0, cellStaggerRamp: 1 };
|
|
219
220
|
return {
|
|
220
221
|
active: true,
|
|
221
222
|
reels: explicit.slice(),
|
|
222
223
|
slowdown: runOpts?.anticipateSlowdown ?? config.anticipation.slowdownFactor,
|
|
223
224
|
holdMs: runOpts?.anticipateHoldMs ?? config.anticipation.holdMs,
|
|
225
|
+
cellStaggerRamp:
|
|
226
|
+
runOpts?.anticipateCellStaggerRamp ?? config.anticipation.progressiveCellStagger,
|
|
224
227
|
};
|
|
225
228
|
}
|
|
226
229
|
|
|
@@ -234,6 +237,7 @@ export function createReelSystem(opts: CreateReelSystemOptions): ReelSystem {
|
|
|
234
237
|
anticipateReels: decision.active ? decision.reels : undefined,
|
|
235
238
|
anticipateSlowdown: decision.slowdown,
|
|
236
239
|
anticipateHoldMs: decision.holdMs,
|
|
240
|
+
anticipateCellStaggerRamp: decision.cellStaggerRamp,
|
|
237
241
|
};
|
|
238
242
|
}
|
|
239
243
|
|