labag 2.6.7 → 3.0.1
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/dist/index.d.ts +2 -11
- package/dist/index.js +1 -20
- package/dist/labag.d.ts +10 -96
- package/dist/labag.js +36 -267
- package/dist/test.js +21 -35
- package/dist/types/index.d.ts +9 -18
- package/package.json +1 -1
- package/src/index.ts +2 -29
- package/src/labag.ts +42 -294
- package/src/test.ts +23 -42
- package/src/types/index.ts +9 -27
- package/src/mode.ts +0 -90
- package/src/modes/greenwei.ts +0 -97
- package/src/modes/index.ts +0 -5
- package/src/modes/pikachu.ts +0 -52
- package/src/modes/superhhh.ts +0 -88
- package/src/pattern.ts +0 -31
- package/src/recordChecker.ts +0 -74
- package/src/recorder.ts +0 -93
package/src/labag.ts
CHANGED
|
@@ -1,308 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { patterns } from "./pattern";
|
|
3
|
-
import { Pattern, LaBaGEvent, PatternName, ModeName } from "./types";
|
|
1
|
+
import { Pattern, Payout } from "./types";
|
|
4
2
|
import { randInt } from "./utils/randInt";
|
|
5
3
|
|
|
6
|
-
/**
|
|
7
|
-
* 拉霸遊戲的主要類別。
|
|
8
|
-
*/
|
|
9
4
|
export class LaBaG {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
__defaultMode__: Mode;
|
|
30
|
-
|
|
31
|
-
constructor(times: number = 30) {
|
|
32
|
-
this.times = times;
|
|
33
|
-
this.played = 0;
|
|
34
|
-
this.rounds = 0;
|
|
35
|
-
this.score = 0;
|
|
36
|
-
this.marginScore = 0;
|
|
37
|
-
this.randNums = [];
|
|
38
|
-
this.patterns = [null, null, null];
|
|
39
|
-
this.modes = [];
|
|
40
|
-
this.eventListeners = {
|
|
41
|
-
gameOver: [],
|
|
42
|
-
gameStart: [],
|
|
43
|
-
roundStart: [],
|
|
44
|
-
roundEnd: [],
|
|
45
|
-
rollSlots: [],
|
|
46
|
-
calculateScore: [],
|
|
5
|
+
patterns: Pattern[];
|
|
6
|
+
reels: Pattern[];
|
|
7
|
+
payouts: Payout[];
|
|
8
|
+
|
|
9
|
+
constructor(patterns: Pattern[], payouts: Payout[]) {
|
|
10
|
+
this.patterns = patterns;
|
|
11
|
+
this.reels = [patterns[0], patterns[1], patterns[2]];
|
|
12
|
+
this.payouts = payouts;
|
|
13
|
+
}
|
|
14
|
+
spin() {
|
|
15
|
+
this.reels = [
|
|
16
|
+
this.randomPattern(),
|
|
17
|
+
this.randomPattern(),
|
|
18
|
+
this.randomPattern(),
|
|
19
|
+
];
|
|
20
|
+
const reward = this.caculateReward(this.reels);
|
|
21
|
+
return {
|
|
22
|
+
reels: this.reels,
|
|
23
|
+
reward,
|
|
47
24
|
};
|
|
48
|
-
|
|
49
|
-
this.__defaultMode__ = new Mode({
|
|
50
|
-
active: true,
|
|
51
|
-
name: "normal",
|
|
52
|
-
rates: {
|
|
53
|
-
gss: 36,
|
|
54
|
-
hhh: 24,
|
|
55
|
-
hentai: 17,
|
|
56
|
-
handson: 12,
|
|
57
|
-
kachu: 8,
|
|
58
|
-
rrr: 3,
|
|
59
|
-
},
|
|
60
|
-
eventListener: {
|
|
61
|
-
gameStart: (game) => {
|
|
62
|
-
game.played = 0;
|
|
63
|
-
game.rounds = 0;
|
|
64
|
-
game.score = 0;
|
|
65
|
-
game.marginScore = 0;
|
|
66
|
-
game.randNums = [];
|
|
67
|
-
game.patterns = [null, null, null];
|
|
68
|
-
},
|
|
69
|
-
roundStart: (game) => {
|
|
70
|
-
game.played += 1;
|
|
71
|
-
game.rounds += 1;
|
|
72
|
-
game.marginScore = 0;
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
rollSlots: (game) => {
|
|
76
|
-
const { ranges } = game.getCurrentConfig();
|
|
77
|
-
const rangesAcc =
|
|
78
|
-
ranges.length > 0 ? ranges[ranges.length - 1].threshold : 0;
|
|
79
|
-
|
|
80
|
-
// 產生 3 個隨機數字並直接尋找對應圖案
|
|
81
|
-
for (let i = 0; i < 3; i++) {
|
|
82
|
-
const num = randInt(1, rangesAcc);
|
|
83
|
-
game.randNums[i] = num;
|
|
84
|
-
|
|
85
|
-
let matchedPattern: Pattern | null = null;
|
|
86
|
-
for (let j = 0; j < ranges.length; j++) {
|
|
87
|
-
if (num <= ranges[j].threshold) {
|
|
88
|
-
matchedPattern = ranges[j].pattern;
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
game.patterns[i] = matchedPattern;
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
calculateScore: (game, mode) => {
|
|
96
|
-
const [p1, p2, p3] = game.patterns;
|
|
97
|
-
if (!p1 || !p2 || !p3) {
|
|
98
|
-
game.marginScore = 0;
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
if (p1.name === p2.name && p2.name === p3.name) {
|
|
102
|
-
// 三個圖案相同
|
|
103
|
-
this.marginScore += p1.scores[0];
|
|
104
|
-
} else if (
|
|
105
|
-
p1.name === p2.name ||
|
|
106
|
-
p2.name === p3.name ||
|
|
107
|
-
p1.name === p3.name
|
|
108
|
-
) {
|
|
109
|
-
// 兩個圖案相同
|
|
110
|
-
if (p1.name === p2.name) {
|
|
111
|
-
this.marginScore += p1.scores[1];
|
|
112
|
-
this.marginScore += p3.scores[2];
|
|
113
|
-
} else if (p2.name === p3.name) {
|
|
114
|
-
this.marginScore += p2.scores[1];
|
|
115
|
-
this.marginScore += p1.scores[2];
|
|
116
|
-
} else {
|
|
117
|
-
this.marginScore += p1.scores[1];
|
|
118
|
-
this.marginScore += p2.scores[2];
|
|
119
|
-
}
|
|
120
|
-
this.marginScore = Math.round(
|
|
121
|
-
this.marginScore / mode.variable.twoMatchDivisor,
|
|
122
|
-
);
|
|
123
|
-
} else {
|
|
124
|
-
// 三個圖案皆不同
|
|
125
|
-
this.marginScore += p1.scores[2];
|
|
126
|
-
this.marginScore += p2.scores[2];
|
|
127
|
-
this.marginScore += p3.scores[2];
|
|
128
|
-
this.marginScore = Math.round(
|
|
129
|
-
this.marginScore / mode.variable.allDifferentDivisor,
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
},
|
|
133
|
-
roundEnd: (game) => {
|
|
134
|
-
game.score += game.marginScore;
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
variable: {
|
|
138
|
-
twoMatchDivisor: 1.4,
|
|
139
|
-
allDifferentDivisor: 3,
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
this.addMode(this.__defaultMode__);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* 觸發指定事件。
|
|
147
|
-
* @param event - 要觸發的事件名稱。
|
|
148
|
-
*/
|
|
149
|
-
private emit(event: LaBaGEvent) {
|
|
150
|
-
const listeners = this.eventListeners[event];
|
|
151
|
-
for (let i = 0; i < listeners.length; i++) {
|
|
152
|
-
listeners[i](this);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* 新增事件監聽器。
|
|
158
|
-
* @param event - 要監聽的事件名稱。
|
|
159
|
-
* @param listener - 事件觸發時要執行的函式。
|
|
160
|
-
* @remarks 可以為同一事件添加多個監聽器,這些監聽器將按照添加的順序依次執行。
|
|
161
|
-
* @example
|
|
162
|
-
* game.addEventListener("gameStart", (game) => {
|
|
163
|
-
* console.log("遊戲開始了!");
|
|
164
|
-
* });
|
|
165
|
-
* game.addEventListener("roundEnd", (game) => {
|
|
166
|
-
* console.log("一輪結束了!");
|
|
167
|
-
* });
|
|
168
|
-
*/
|
|
169
|
-
addEventListener(event: LaBaGEvent, callbackFn: (game: LaBaG) => void) {
|
|
170
|
-
this.eventListeners[event].push(callbackFn);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* 移除事件監聽器。
|
|
175
|
-
* @param event - 要移除監聽器的事件名稱。
|
|
176
|
-
* @param listener - 要移除的監聽器函式。
|
|
177
|
-
* @remarks 這將從指定事件的監聽器列表中移除第一個匹配的函式。
|
|
178
|
-
* @example
|
|
179
|
-
* const onGameStart = (game) => {
|
|
180
|
-
* console.log("遊戲開始了!");
|
|
181
|
-
* };
|
|
182
|
-
* game.addEventListener("gameStart", onGameStart);
|
|
183
|
-
* // 之後如果想要移除這個監聽器:
|
|
184
|
-
* game.removeEventListener("gameStart", onGameStart);
|
|
185
|
-
*/
|
|
186
|
-
removeEventListener(event: LaBaGEvent, callbackFn: (game: LaBaG) => void) {
|
|
187
|
-
const listeners = this.eventListeners[event];
|
|
188
|
-
const index = listeners.indexOf(callbackFn);
|
|
189
|
-
if (index !== -1) {
|
|
190
|
-
listeners.splice(index, 1);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* 新增遊戲模式。
|
|
196
|
-
* @param mode - 要新增的遊戲模式實例。
|
|
197
|
-
* @remarks 這將把指定的模式添加到遊戲的模式列表中,並自動註冊該模式定義的事件監聽器。
|
|
198
|
-
* @example
|
|
199
|
-
* const myMode = new Mode({
|
|
200
|
-
* active: false,
|
|
201
|
-
* name: "myMode",
|
|
202
|
-
* rates: {
|
|
203
|
-
* gss: 10,
|
|
204
|
-
* hhh: 20,
|
|
205
|
-
* hentai: 30,
|
|
206
|
-
* handson: 20,
|
|
207
|
-
* kachu: 10,
|
|
208
|
-
* rrr: 10,
|
|
209
|
-
* },
|
|
210
|
-
* });
|
|
211
|
-
* game.addMode(myMode);
|
|
212
|
-
*/
|
|
213
|
-
addMode(mode: Mode<any>) {
|
|
214
|
-
this.modes.push(mode);
|
|
215
|
-
// 註冊特定模式的監聽器
|
|
216
|
-
Object.entries(mode.eventListener).forEach(([event, listener]) => {
|
|
217
|
-
if (listener) {
|
|
218
|
-
this.addEventListener(event as LaBaGEvent, (game) =>
|
|
219
|
-
listener(game, mode),
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
25
|
}
|
|
224
26
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
hhh: 0,
|
|
237
|
-
hentai: 0,
|
|
238
|
-
handson: 0,
|
|
239
|
-
kachu: 0,
|
|
240
|
-
rrr: 0,
|
|
241
|
-
};
|
|
242
|
-
for (let i = 0; i < activeModes.length; i++) {
|
|
243
|
-
const mode = activeModes[i];
|
|
244
|
-
for (const patternName in mode.rates) {
|
|
245
|
-
combinedRates[patternName as PatternName] +=
|
|
246
|
-
mode.rates[patternName as PatternName];
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// 預先計算合併後的區間
|
|
251
|
-
const ranges: { threshold: number; pattern: Pattern }[] = [];
|
|
252
|
-
let acc = 0;
|
|
253
|
-
for (const pattern of patterns) {
|
|
254
|
-
const rate = combinedRates[pattern.name];
|
|
255
|
-
if (rate !== undefined) {
|
|
256
|
-
acc += rate;
|
|
257
|
-
ranges.push({ threshold: acc, pattern });
|
|
27
|
+
randomPattern(): Pattern {
|
|
28
|
+
const totalWeight = this.patterns.reduce(
|
|
29
|
+
(sum, pattern) => sum + pattern.weight,
|
|
30
|
+
0,
|
|
31
|
+
);
|
|
32
|
+
const randNum = randInt(1, totalWeight);
|
|
33
|
+
let cumulativeWeight = 0;
|
|
34
|
+
for (const pattern of this.patterns) {
|
|
35
|
+
cumulativeWeight += pattern.weight;
|
|
36
|
+
if (randNum <= cumulativeWeight) {
|
|
37
|
+
return pattern;
|
|
258
38
|
}
|
|
259
39
|
}
|
|
260
|
-
|
|
261
|
-
return { modes: activeModes, ranges };
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
init() {
|
|
265
|
-
this.emit("gameStart");
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
roundStart() {
|
|
269
|
-
this.emit("roundStart");
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
rollSlots() {
|
|
273
|
-
this.emit("rollSlots");
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
calculateScore() {
|
|
277
|
-
this.emit("calculateScore");
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
roundEnd() {
|
|
281
|
-
this.emit("roundEnd");
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
gameOver() {
|
|
285
|
-
this.emit("gameOver");
|
|
40
|
+
throw new Error("No pattern found");
|
|
286
41
|
}
|
|
287
42
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
43
|
+
caculateReward(reels: Pattern[]): number {
|
|
44
|
+
const patternCounts: { [key: string]: number } = {};
|
|
45
|
+
for (const pattern of reels) {
|
|
46
|
+
patternCounts[pattern.id] = (patternCounts[pattern.id] || 0) + 1;
|
|
291
47
|
}
|
|
292
|
-
|
|
293
|
-
this.
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
this.gameOver();
|
|
48
|
+
let totalReward = 0;
|
|
49
|
+
for (const payout of this.payouts) {
|
|
50
|
+
if (patternCounts[payout.pattern_id] === payout.match_count) {
|
|
51
|
+
totalReward += payout.reward;
|
|
52
|
+
}
|
|
298
53
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
getMode(name: ModeName) {
|
|
302
|
-
return this.modes.find((m) => m.name === name);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
get isRunning() {
|
|
306
|
-
return this.played < this.times;
|
|
54
|
+
return totalReward;
|
|
307
55
|
}
|
|
308
56
|
}
|
package/src/test.ts
CHANGED
|
@@ -1,45 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { recorder } from "./index";
|
|
3
|
-
labag.addEventListener("gameStart", (game) => {
|
|
4
|
-
console.log("Game Started!");
|
|
5
|
-
console.log(`Total Rounds: ${game.times}\n`);
|
|
6
|
-
});
|
|
7
|
-
labag.addEventListener("roundStart", (game) => {
|
|
8
|
-
console.log(`--- Round ${game.rounds} Start ---`);
|
|
9
|
-
});
|
|
10
|
-
labag.addEventListener("rollSlots", (game) => {
|
|
11
|
-
const { modes, ranges } = game.getCurrentConfig();
|
|
12
|
-
console.log(`Active Modes: ${modes.map((m) => m.name).join(", ")}`);
|
|
13
|
-
console.log(
|
|
14
|
-
`Probability Ranges: ${ranges
|
|
15
|
-
.map((r) => `${r.pattern.name}<=${r.threshold}`)
|
|
16
|
-
.join(", ")}`,
|
|
17
|
-
);
|
|
18
|
-
});
|
|
19
|
-
labag.addEventListener("roundEnd", (game) => {
|
|
20
|
-
console.log(game.patterns.map((p) => (p ? p.name : "null")).join(" | "));
|
|
21
|
-
console.log(`Margin Score: ${game.marginScore}`);
|
|
22
|
-
console.log(`Score: ${game.score}\n`);
|
|
23
|
-
});
|
|
1
|
+
import { LaBaG } from "./labag";
|
|
24
2
|
|
|
25
|
-
|
|
26
|
-
|
|
3
|
+
const patterns = [
|
|
4
|
+
{ id: "A", weight: 50 , image: "A.png"},
|
|
5
|
+
{ id: "B", weight: 30 , image: "B.png"},
|
|
6
|
+
{ id: "C", weight: 20 , image: "C.png"},
|
|
7
|
+
];
|
|
27
8
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
9
|
+
const payouts = [
|
|
10
|
+
{ id: "payout1", pattern_id: "A", match_count: 3, reward: 100 },
|
|
11
|
+
{ id: "payout2", pattern_id: "B", match_count: 3, reward: 50 },
|
|
12
|
+
{ id: "payout3", pattern_id: "C", match_count: 3, reward: 20 },
|
|
13
|
+
{ id: "payout4", pattern_id: "A", match_count: 2, reward: 10 },
|
|
14
|
+
{ id: "payout5", pattern_id: "B", match_count: 2, reward: 5 },
|
|
15
|
+
{ id: "payout6", pattern_id: "C", match_count: 2, reward: 2 },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const labag = new LaBaG(patterns, payouts);
|
|
31
19
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
`
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
);
|
|
40
|
-
console.log(`record: ${JSON.stringify(recorder.getRecord(), null, 2)}`);
|
|
41
|
-
console.log(
|
|
42
|
-
checker.check(recorder.getRecord())
|
|
43
|
-
? "Record is valid!"
|
|
44
|
-
: "Record is invalid!",
|
|
45
|
-
);
|
|
20
|
+
let totalReward = 0;
|
|
21
|
+
for (let i = 0; i < 10; i++) {
|
|
22
|
+
const result = labag.spin();
|
|
23
|
+
console.log(`Spin ${i + 1}:`, result);
|
|
24
|
+
totalReward += result.reward;
|
|
25
|
+
}
|
|
26
|
+
console.log("Total Reward:", totalReward);
|
package/src/types/index.ts
CHANGED
|
@@ -1,30 +1,12 @@
|
|
|
1
|
-
import { modes } from "../modes";
|
|
2
|
-
import { patterns } from "../pattern";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 拉霸遊戲的事件類型。
|
|
6
|
-
*/
|
|
7
|
-
export type LaBaGEvent =
|
|
8
|
-
| "gameOver"
|
|
9
|
-
| "gameStart"
|
|
10
|
-
| "roundStart"
|
|
11
|
-
| "roundEnd"
|
|
12
|
-
| "rollSlots"
|
|
13
|
-
| "calculateScore";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* 代表一個圖案及其對應的分數。
|
|
17
|
-
*/
|
|
18
1
|
export type Pattern = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
scores: number[];
|
|
2
|
+
id: string;
|
|
3
|
+
weight: number;
|
|
4
|
+
image: string;
|
|
23
5
|
};
|
|
24
6
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
7
|
+
export type Payout = {
|
|
8
|
+
id: string;
|
|
9
|
+
pattern_id: Pattern["id"];
|
|
10
|
+
match_count: number;
|
|
11
|
+
reward: number;
|
|
12
|
+
};
|
package/src/mode.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { LaBaG } from "./labag";
|
|
2
|
-
import { patterns } from "./pattern";
|
|
3
|
-
import { LaBaGEvent, Pattern, PatternName } from "./types";
|
|
4
|
-
interface ModeConfig<
|
|
5
|
-
VariableType extends Record<string, any>,
|
|
6
|
-
N extends string = string,
|
|
7
|
-
> {
|
|
8
|
-
active: boolean;
|
|
9
|
-
name: N;
|
|
10
|
-
rates: Record<PatternName, number>;
|
|
11
|
-
eventListener?: Partial<
|
|
12
|
-
Record<LaBaGEvent, (game: LaBaG, mode: Mode<VariableType>) => void>
|
|
13
|
-
>;
|
|
14
|
-
variable?: VariableType;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 代表遊戲的一種模式,包含機率設定和事件監聽器。
|
|
19
|
-
*/
|
|
20
|
-
export class Mode<
|
|
21
|
-
VariableType extends Record<string, any> = Record<string, any>,
|
|
22
|
-
N extends string = string,
|
|
23
|
-
> implements ModeConfig<VariableType, N> {
|
|
24
|
-
/** 模式是否啟用 */
|
|
25
|
-
active: boolean;
|
|
26
|
-
/** 模式名稱 */
|
|
27
|
-
name: N;
|
|
28
|
-
/** 各圖案出現的機率 */
|
|
29
|
-
rates: Record<PatternName, number>;
|
|
30
|
-
// 預先計算的區間,用於高效查找
|
|
31
|
-
ranges: { threshold: number; pattern: Pattern }[];
|
|
32
|
-
/** 事件監聽器 */
|
|
33
|
-
eventListener: Partial<
|
|
34
|
-
Record<LaBaGEvent, (game: LaBaG, mode: Mode<VariableType>) => void>
|
|
35
|
-
>;
|
|
36
|
-
|
|
37
|
-
/** 模式專屬的變數儲存空間 */
|
|
38
|
-
variable: VariableType;
|
|
39
|
-
/** 機率總和 */
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* 建立一個新的遊戲模式。
|
|
43
|
-
* @param config 模式的設定,包括啟用狀態、名稱、機率、事件監聽器和專屬變數。
|
|
44
|
-
* @remarks 會根據提供的機率設定預先計算出對應的區間,以便在遊戲中快速查找圖案。
|
|
45
|
-
* @example
|
|
46
|
-
* const myMode = new Mode({
|
|
47
|
-
* active: false,
|
|
48
|
-
* name: "myMode",
|
|
49
|
-
* rates: {
|
|
50
|
-
* gss: 10,
|
|
51
|
-
* hhh: 20,
|
|
52
|
-
* hentai: 30,
|
|
53
|
-
* handson: 20,
|
|
54
|
-
* kachu: 10,
|
|
55
|
-
* rrr: 10,
|
|
56
|
-
* },
|
|
57
|
-
* eventListener: {
|
|
58
|
-
* gameStart: (game, mode) => {
|
|
59
|
-
* console.log("遊戲開始了!", mode.name);
|
|
60
|
-
* },
|
|
61
|
-
* roundEnd: (game, mode) => {
|
|
62
|
-
* console.log("一輪結束了!", mode.name);
|
|
63
|
-
* },
|
|
64
|
-
* },
|
|
65
|
-
* variable: {
|
|
66
|
-
* myCustomValue: 123,
|
|
67
|
-
* },
|
|
68
|
-
* });
|
|
69
|
-
*/
|
|
70
|
-
constructor(config: ModeConfig<VariableType, N>) {
|
|
71
|
-
const { active, name, rates, eventListener, variable } = config;
|
|
72
|
-
this.active = active;
|
|
73
|
-
this.name = name;
|
|
74
|
-
this.rates = rates;
|
|
75
|
-
this.eventListener = eventListener ?? {};
|
|
76
|
-
this.variable = variable ?? ({} as VariableType);
|
|
77
|
-
|
|
78
|
-
// 預先計算機率區間
|
|
79
|
-
this.ranges = [];
|
|
80
|
-
let acc = 0;
|
|
81
|
-
// 遍歷定義的圖案以確保順序一致
|
|
82
|
-
for (const pattern of patterns) {
|
|
83
|
-
const rate = rates[pattern.name];
|
|
84
|
-
if (rate !== undefined) {
|
|
85
|
-
acc += rate;
|
|
86
|
-
this.ranges.push({ threshold: acc, pattern });
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
package/src/modes/greenwei.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { patterns } from "../pattern";
|
|
2
|
-
import { Mode } from "../mode";
|
|
3
|
-
import { randInt } from "../utils/randInt";
|
|
4
|
-
|
|
5
|
-
export default new Mode({
|
|
6
|
-
active: false,
|
|
7
|
-
name: "greenwei",
|
|
8
|
-
rates: {
|
|
9
|
-
gss: 0,
|
|
10
|
-
hhh: 0,
|
|
11
|
-
hentai: 0,
|
|
12
|
-
handson: 0,
|
|
13
|
-
kachu: 0,
|
|
14
|
-
rrr: 0,
|
|
15
|
-
},
|
|
16
|
-
eventListener: {
|
|
17
|
-
gameStart: (_, mode) => {
|
|
18
|
-
mode.active = false;
|
|
19
|
-
mode.variable.times = 0;
|
|
20
|
-
mode.variable.count = 0;
|
|
21
|
-
},
|
|
22
|
-
roundStart: (_, mode) => {
|
|
23
|
-
if (!mode.active) return;
|
|
24
|
-
mode.variable.times -= 1;
|
|
25
|
-
},
|
|
26
|
-
rollSlots: (_, mode) => {
|
|
27
|
-
mode.variable.randNum = randInt(1, 100);
|
|
28
|
-
},
|
|
29
|
-
calculateScore: (game, mode) => {
|
|
30
|
-
if (mode.active) {
|
|
31
|
-
game.marginScore = Math.round(
|
|
32
|
-
game.marginScore * mode.variable.mutiplier,
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
roundEnd: (game, mode) => {
|
|
37
|
-
const { patterns } = game;
|
|
38
|
-
const { variable } = mode;
|
|
39
|
-
|
|
40
|
-
let gssCount = 0;
|
|
41
|
-
let allGSS = true;
|
|
42
|
-
for (const p of patterns) {
|
|
43
|
-
if (p?.name === mode.variable.bindPattern.name) {
|
|
44
|
-
gssCount++;
|
|
45
|
-
} else {
|
|
46
|
-
allGSS = false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
variable.count += gssCount;
|
|
51
|
-
|
|
52
|
-
if (mode.active) {
|
|
53
|
-
if (allGSS) {
|
|
54
|
-
variable.times += mode.variable.extendTimes;
|
|
55
|
-
}
|
|
56
|
-
if (variable.times <= 0) {
|
|
57
|
-
mode.active = false;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
if (!mode.active) {
|
|
61
|
-
let activated = false;
|
|
62
|
-
if (variable.randNum <= variable.rate && allGSS) {
|
|
63
|
-
activated = true;
|
|
64
|
-
variable.times += mode.variable.extendTimes;
|
|
65
|
-
} else if (variable.count >= mode.variable.requiredBindPatternCount) {
|
|
66
|
-
activated = true;
|
|
67
|
-
variable.times += mode.variable.bonusTimes;
|
|
68
|
-
variable.count -= mode.variable.requiredBindPatternCount;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (activated) {
|
|
72
|
-
mode.active = true;
|
|
73
|
-
for (let i = 0; i < patterns.length; i++) {
|
|
74
|
-
if (patterns[i]?.name === mode.variable.bindPattern.name) {
|
|
75
|
-
patterns[i] = variable.pattern;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
variable: {
|
|
83
|
-
times: 0,
|
|
84
|
-
rate: 35,
|
|
85
|
-
randNum: 0,
|
|
86
|
-
count: 0,
|
|
87
|
-
pattern: {
|
|
88
|
-
name: "greenwei",
|
|
89
|
-
scores: [800, 400, 180],
|
|
90
|
-
},
|
|
91
|
-
extendTimes: 2,
|
|
92
|
-
bindPattern: patterns[0],
|
|
93
|
-
bonusTimes: 2,
|
|
94
|
-
requiredBindPatternCount: 20,
|
|
95
|
-
mutiplier: 3,
|
|
96
|
-
},
|
|
97
|
-
});
|