gambling-bot-shared 0.1.40 → 0.1.42

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.
@@ -82,7 +82,6 @@ export declare const defaultCasinoSettings: {
82
82
  };
83
83
  plinko: {
84
84
  binMultipliers: {
85
- 0: number;
86
85
  1: number;
87
86
  2: number;
88
87
  3: number;
@@ -91,6 +90,7 @@ export declare const defaultCasinoSettings: {
91
90
  6: number;
92
91
  7: number;
93
92
  8: number;
93
+ 9: number;
94
94
  };
95
95
  maxBet: number;
96
96
  minBet: number;
@@ -99,15 +99,15 @@ exports.defaultCasinoSettings = {
99
99
  },
100
100
  plinko: {
101
101
  binMultipliers: {
102
- 0: 8,
103
- 1: 6,
104
- 2: 1.5,
105
- 3: 0.75,
106
- 4: 0.5,
107
- 5: 0.75,
108
- 6: 1.5,
109
- 7: 6,
110
- 8: 8
102
+ 1: 8,
103
+ 2: 6,
104
+ 3: 1.5,
105
+ 4: 0.75,
106
+ 5: 0.5,
107
+ 6: 0.75,
108
+ 7: 1.5,
109
+ 8: 6,
110
+ 9: 8
111
111
  },
112
112
  maxBet: 0,
113
113
  minBet: 0
@@ -3,4 +3,5 @@ export * from './maxSimulations';
3
3
  export * from './lotteryConfig';
4
4
  export * from './rouletteConfig';
5
5
  export * from './gameRecordFields';
6
+ export * from './plinkoConfig';
6
7
  export * from './transaction';
@@ -19,4 +19,5 @@ __exportStar(require("./maxSimulations"), exports);
19
19
  __exportStar(require("./lotteryConfig"), exports);
20
20
  __exportStar(require("./rouletteConfig"), exports);
21
21
  __exportStar(require("./gameRecordFields"), exports);
22
+ __exportStar(require("./plinkoConfig"), exports);
22
23
  __exportStar(require("./transaction"), exports);
@@ -0,0 +1,13 @@
1
+ export declare const PLINKO_BIN_COUNT = 9;
2
+ export declare const PLINKO_ROW_COUNT: number;
3
+ export declare const PLINKO_CENTER_BIN = 5;
4
+ export declare const PLINKO_EDITABLE_BINS: readonly [1, 2, 3, 4, 5];
5
+ export type PlinkoEditableBin = (typeof PLINKO_EDITABLE_BINS)[number];
6
+ export declare const getPlinkoMirrorBin: (bin: number) => number;
7
+ export declare const pathIndexToPlinkoBin: (pathIndex: number) => number;
8
+ export declare const plinkoBinToPathIndex: (bin: number) => number;
9
+ export declare const expandPlinkoBinMultipliers: (editable: Record<string | number, number | string>) => Record<string, number>;
10
+ /** Migrate legacy 0-indexed bins and enforce symmetric 1–9 layout. */
11
+ export declare const normalizePlinkoBinMultipliers: (input: Record<string | number, number | string> | null | undefined) => Record<string, number>;
12
+ export declare const getPlinkoMultiplierAtPathIndex: (binMultipliers: Record<string | number, number | string>, pathIndex: number) => number;
13
+ export declare const formatPlinkoBinMultipliersForDisplay: (binMultipliers: Record<string | number, number | string>) => Record<string, number>;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatPlinkoBinMultipliersForDisplay = exports.getPlinkoMultiplierAtPathIndex = exports.normalizePlinkoBinMultipliers = exports.expandPlinkoBinMultipliers = exports.plinkoBinToPathIndex = exports.pathIndexToPlinkoBin = exports.getPlinkoMirrorBin = exports.PLINKO_EDITABLE_BINS = exports.PLINKO_CENTER_BIN = exports.PLINKO_ROW_COUNT = exports.PLINKO_BIN_COUNT = void 0;
4
+ const defaultConfig_1 = require("./defaultConfig");
5
+ exports.PLINKO_BIN_COUNT = 9;
6
+ exports.PLINKO_ROW_COUNT = exports.PLINKO_BIN_COUNT - 1;
7
+ exports.PLINKO_CENTER_BIN = 5;
8
+ exports.PLINKO_EDITABLE_BINS = [1, 2, 3, 4, 5];
9
+ const getPlinkoMirrorBin = (bin) => exports.PLINKO_BIN_COUNT + 1 - bin;
10
+ exports.getPlinkoMirrorBin = getPlinkoMirrorBin;
11
+ const pathIndexToPlinkoBin = (pathIndex) => pathIndex + 1;
12
+ exports.pathIndexToPlinkoBin = pathIndexToPlinkoBin;
13
+ const plinkoBinToPathIndex = (bin) => bin - 1;
14
+ exports.plinkoBinToPathIndex = plinkoBinToPathIndex;
15
+ const toNumber = (val) => {
16
+ if (typeof val === 'string')
17
+ return parseFloat(val) || 0;
18
+ if (typeof val === 'number')
19
+ return val;
20
+ return 0;
21
+ };
22
+ const defaultBinMultipliers = () => defaultConfig_1.defaultCasinoSettings.plinko.binMultipliers;
23
+ const expandPlinkoBinMultipliers = (editable) => {
24
+ const defaults = defaultBinMultipliers();
25
+ const result = {};
26
+ for (const bin of exports.PLINKO_EDITABLE_BINS) {
27
+ result[String(bin)] = toNumber(editable[bin] ?? editable[String(bin)] ?? defaults[String(bin)] ?? 0);
28
+ }
29
+ for (let bin = exports.PLINKO_CENTER_BIN + 1; bin <= exports.PLINKO_BIN_COUNT; bin++) {
30
+ const mirror = (0, exports.getPlinkoMirrorBin)(bin);
31
+ result[String(bin)] = result[String(mirror)];
32
+ }
33
+ return result;
34
+ };
35
+ exports.expandPlinkoBinMultipliers = expandPlinkoBinMultipliers;
36
+ /** Migrate legacy 0-indexed bins and enforce symmetric 1–9 layout. */
37
+ const normalizePlinkoBinMultipliers = (input) => {
38
+ if (!input || Object.keys(input).length === 0) {
39
+ return (0, exports.expandPlinkoBinMultipliers)(defaultBinMultipliers());
40
+ }
41
+ const raw = {};
42
+ for (const [key, value] of Object.entries(input)) {
43
+ const numKey = Number(key);
44
+ if (!Number.isFinite(numKey))
45
+ continue;
46
+ raw[numKey] = toNumber(value);
47
+ }
48
+ const usesZeroIndex = Object.prototype.hasOwnProperty.call(input, '0');
49
+ const editable = {};
50
+ const defaults = defaultBinMultipliers();
51
+ if (usesZeroIndex) {
52
+ for (let bin = 1; bin <= exports.PLINKO_CENTER_BIN; bin++) {
53
+ editable[bin] = raw[bin - 1] ?? toNumber(defaults[String(bin)]);
54
+ }
55
+ }
56
+ else {
57
+ for (const bin of exports.PLINKO_EDITABLE_BINS) {
58
+ editable[bin] = raw[bin] ?? toNumber(defaults[String(bin)]);
59
+ }
60
+ }
61
+ return (0, exports.expandPlinkoBinMultipliers)(editable);
62
+ };
63
+ exports.normalizePlinkoBinMultipliers = normalizePlinkoBinMultipliers;
64
+ const getPlinkoMultiplierAtPathIndex = (binMultipliers, pathIndex) => {
65
+ const normalized = (0, exports.normalizePlinkoBinMultipliers)(binMultipliers);
66
+ return normalized[String((0, exports.pathIndexToPlinkoBin)(pathIndex))] ?? 0;
67
+ };
68
+ exports.getPlinkoMultiplierAtPathIndex = getPlinkoMultiplierAtPathIndex;
69
+ const formatPlinkoBinMultipliersForDisplay = (binMultipliers) => {
70
+ const normalized = (0, exports.normalizePlinkoBinMultipliers)(binMultipliers);
71
+ return Object.fromEntries(exports.PLINKO_EDITABLE_BINS.map((bin) => [String(bin), normalized[String(bin)]]));
72
+ };
73
+ exports.formatPlinkoBinMultipliersForDisplay = formatPlinkoBinMultipliersForDisplay;
@@ -158,7 +158,6 @@ export declare const GuildConfigurationSchema: Schema<TGuildConfiguration, impor
158
158
  };
159
159
  plinko: {
160
160
  binMultipliers: {
161
- 0: number;
162
161
  1: number;
163
162
  2: number;
164
163
  3: number;
@@ -167,6 +166,7 @@ export declare const GuildConfigurationSchema: Schema<TGuildConfiguration, impor
167
166
  6: number;
168
167
  7: number;
169
168
  8: number;
169
+ 9: number;
170
170
  };
171
171
  maxBet: number;
172
172
  minBet: number;
@@ -81,7 +81,7 @@ export declare const casinoSettingsSchema: z.ZodObject<{
81
81
  casinoCut: z.ZodNumber;
82
82
  }, z.core.$strip>;
83
83
  plinko: z.ZodObject<{
84
- binMultipliers: z.ZodRecord<z.ZodString, z.ZodNumber>;
84
+ binMultipliers: z.ZodPipe<z.ZodRecord<z.ZodString, z.ZodNumber>, z.ZodTransform<Record<string, number>, Record<string, number>>>;
85
85
  minBet: z.ZodNumber;
86
86
  maxBet: z.ZodNumber;
87
87
  }, z.core.$strip>;
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.bonusFormSchema = exports.managerRoleFormSchema = exports.vipSettingsFormSchema = exports.casinoSettingsSchema = exports.channelsFormSchema = exports.raffleChannelsFormSchema = exports.predictionChannelsFormSchema = exports.casinoChannelsFormSchema = exports.atmChannelsFormSchema = void 0;
7
7
  const zod_1 = __importDefault(require("zod"));
8
+ const plinkoConfig_1 = require("../constants/plinkoConfig");
8
9
  const NO_CHANNEL = 'At least one channel must be selected.';
9
10
  exports.atmChannelsFormSchema = zod_1.default.object({
10
11
  actions: zod_1.default.string().min(1, { message: NO_CHANNEL }),
@@ -80,7 +81,9 @@ exports.casinoSettingsSchema = zod_1.default.object({
80
81
  casinoCut: num
81
82
  }),
82
83
  plinko: zod_1.default.object({
83
- binMultipliers: zod_1.default.record(zod_1.default.string(), num),
84
+ binMultipliers: zod_1.default
85
+ .record(zod_1.default.string(), num)
86
+ .transform(plinkoConfig_1.normalizePlinkoBinMultipliers),
84
87
  minBet: num,
85
88
  maxBet: num
86
89
  })
@@ -1,33 +1,34 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.calculateBonusReward = void 0;
4
+ const getCycleLength = (rewardMode, baseReward, maxReward, streakIncrement, streakMultiplier) => {
5
+ if (rewardMode === 'linear') {
6
+ return streakIncrement > 0
7
+ ? Math.floor((maxReward - baseReward) / streakIncrement) + 1
8
+ : 1;
9
+ }
10
+ return streakMultiplier > 1
11
+ ? Math.floor(Math.log(maxReward / baseReward) / Math.log(streakMultiplier)) +
12
+ 1
13
+ : 1;
14
+ };
4
15
  const calculateBonusReward = ({ streak, settings }) => {
5
16
  const { rewardMode, baseReward, streakIncrement = 0, streakMultiplier = 1, maxReward, resetOnMax, milestoneBonus } = settings;
6
17
  let base = rewardMode === 'linear'
7
18
  ? baseReward + (streak - 1) * streakIncrement
8
19
  : baseReward * Math.pow(streakMultiplier, streak - 1);
9
20
  let isReset = false;
10
- if (maxReward > 0 && base > maxReward) {
11
- if (resetOnMax) {
12
- isReset = true;
13
- if (rewardMode === 'linear') {
14
- const cycle = streakIncrement > 0
15
- ? Math.floor((maxReward - baseReward) / streakIncrement) + 1
16
- : 1;
17
- const newStreak = ((streak - 1) % cycle) + 1;
18
- base = baseReward + (newStreak - 1) * streakIncrement;
19
- }
20
- else {
21
- const cycle = streakMultiplier > 1
22
- ? Math.floor(Math.log(maxReward / baseReward) / Math.log(streakMultiplier)) + 1
23
- : 1;
24
- const newStreak = ((streak - 1) % cycle) + 1;
25
- base = baseReward * Math.pow(streakMultiplier, newStreak - 1);
26
- }
27
- }
28
- else {
29
- base = maxReward;
30
- }
21
+ if (maxReward > 0 && resetOnMax && base > maxReward) {
22
+ const cycle = getCycleLength(rewardMode, baseReward, maxReward, streakIncrement, streakMultiplier);
23
+ const cycleStreak = ((streak - 1) % cycle) + 1;
24
+ isReset = streak > cycle && cycleStreak === 1;
25
+ base =
26
+ rewardMode === 'linear'
27
+ ? baseReward + (cycleStreak - 1) * streakIncrement
28
+ : baseReward * Math.pow(streakMultiplier, cycleStreak - 1);
29
+ }
30
+ else if (maxReward > 0 && base > maxReward) {
31
+ base = maxReward;
31
32
  }
32
33
  const weekly = streak % 7 === 0 ? milestoneBonus.weekly : 0;
33
34
  const monthly = streak % 28 === 0 ? milestoneBonus.monthly : 0;
@@ -103,17 +103,13 @@ const calculateRTP = (game, settings) => {
103
103
  return 0;
104
104
  case 'plinko': {
105
105
  const { binMultipliers } = settings;
106
- const multipliers = binMultipliers;
107
- const bins = Object.keys(multipliers)
108
- .map(Number)
109
- .sort((a, b) => a - b);
110
- const N = bins.length - 1; // rows
106
+ const multipliers = (0, constants_1.normalizePlinkoBinMultipliers)(binMultipliers);
107
+ const N = constants_1.PLINKO_ROW_COUNT;
111
108
  const p = 0.5;
112
109
  let rtp = 0;
113
110
  for (let k = 0; k <= N; k++) {
114
111
  const probability = combination(N, k) * Math.pow(p, k) * Math.pow(1 - p, N - k);
115
- const multiplier = toNumber(multipliers[k] ?? 0);
116
- rtp += probability * multiplier;
112
+ rtp += probability * (0, constants_1.getPlinkoMultiplierAtPathIndex)(multipliers, k);
117
113
  }
118
114
  return rtp * 100;
119
115
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gambling-bot-shared",
3
- "version": "0.1.40",
3
+ "version": "0.1.42",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "MIT",