labag 1.2.1 → 2.0.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/dist/mode.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ import { LaBaG } from "./labag";
2
+ import { LaBaGEvent, Pattern, PatternName } from "./types";
3
+ /**
4
+ * 代表遊戲的一種模式,包含機率設定和事件監聽器。
5
+ */
6
+ export declare class Mode {
7
+ /** 模式是否啟用 */
8
+ active: boolean;
9
+ /** 模式名稱 */
10
+ name: string;
11
+ /** 各圖案出現的機率 */
12
+ rates: Record<PatternName, number>;
13
+ ranges: {
14
+ threshold: number;
15
+ pattern: Pattern;
16
+ }[];
17
+ /** 事件監聽器 */
18
+ eventListener: Partial<Record<LaBaGEvent, (game: LaBaG, mode: Mode) => void>>;
19
+ /** 模式專屬的變數儲存空間 */
20
+ variable: Record<string, any>;
21
+ /** 機率總和 */
22
+ /**
23
+ * 建立一個新的模式。
24
+ * @param active - 是否啟用此模式。
25
+ * @param name - 模式名稱。
26
+ * @param rates - 各圖案的機率設定。
27
+ * @param eventListener - 事件監聽器。
28
+ */
29
+ constructor(active: boolean, name: string, rates: Record<PatternName, number>, eventListener?: Partial<Record<LaBaGEvent, (game: LaBaG, mode: Mode) => void>>, variable?: Record<string, any>);
30
+ }
package/dist/mode.js ADDED
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Mode = void 0;
4
+ const pattern_1 = require("./pattern");
5
+ /**
6
+ * 代表遊戲的一種模式,包含機率設定和事件監聽器。
7
+ */
8
+ class Mode {
9
+ /** 模式是否啟用 */
10
+ active;
11
+ /** 模式名稱 */
12
+ name;
13
+ /** 各圖案出現的機率 */
14
+ rates;
15
+ // 預先計算的區間,用於高效查找
16
+ ranges;
17
+ /** 事件監聽器 */
18
+ eventListener;
19
+ /** 模式專屬的變數儲存空間 */
20
+ variable;
21
+ /** 機率總和 */
22
+ /**
23
+ * 建立一個新的模式。
24
+ * @param active - 是否啟用此模式。
25
+ * @param name - 模式名稱。
26
+ * @param rates - 各圖案的機率設定。
27
+ * @param eventListener - 事件監聽器。
28
+ */
29
+ constructor(active, name, rates, eventListener, variable) {
30
+ this.active = active;
31
+ this.name = name;
32
+ this.rates = rates;
33
+ this.eventListener = eventListener ?? {};
34
+ this.variable = variable ?? {};
35
+ // 預先計算機率區間
36
+ this.ranges = [];
37
+ let acc = 0;
38
+ // 遍歷定義的圖案以確保順序一致
39
+ for (const pattern of pattern_1.patterns) {
40
+ const rate = rates[pattern.name];
41
+ if (rate !== undefined) {
42
+ acc += rate;
43
+ this.ranges.push({ threshold: acc, pattern });
44
+ }
45
+ }
46
+ if (acc > 100) {
47
+ console.warn(`模式 "${name}" 的機率總和超過 100%,請檢查設定。`);
48
+ }
49
+ }
50
+ }
51
+ exports.Mode = Mode;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 定義遊戲中可用的圖案及其分數。
3
+ */
4
+ export declare const patterns: readonly [{
5
+ readonly name: "gss";
6
+ readonly scores: [800, 400, 180];
7
+ }, {
8
+ readonly name: "hhh";
9
+ readonly scores: [1500, 800, 300];
10
+ }, {
11
+ readonly name: "hentai";
12
+ readonly scores: [2500, 1200, 500];
13
+ }, {
14
+ readonly name: "handson";
15
+ readonly scores: [2900, 1450, 690];
16
+ }, {
17
+ readonly name: "kachu";
18
+ readonly scores: [12000, 8000, 1250];
19
+ }, {
20
+ readonly name: "rrr";
21
+ readonly scores: [20000, 12000, 2500];
22
+ }];
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.patterns = void 0;
4
+ /**
5
+ * 定義遊戲中可用的圖案及其分數。
6
+ */
7
+ exports.patterns = [
8
+ {
9
+ name: "gss",
10
+ scores: [800, 400, 180],
11
+ },
12
+ {
13
+ name: "hhh",
14
+ scores: [1500, 800, 300],
15
+ },
16
+ {
17
+ name: "hentai",
18
+ scores: [2500, 1200, 500],
19
+ },
20
+ {
21
+ name: "handson",
22
+ scores: [2900, 1450, 690],
23
+ },
24
+ {
25
+ name: "kachu",
26
+ scores: [12000, 8000, 1250],
27
+ },
28
+ {
29
+ name: "rrr",
30
+ scores: [20000, 12000, 2500],
31
+ },
32
+ ];
package/dist/test.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/test.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const index_1 = __importDefault(require("./index"));
7
+ index_1.default.addEventListener("gameStart", (game) => {
8
+ console.log("Game Started!");
9
+ console.log(`Total Rounds: ${game.times}\n`);
10
+ });
11
+ index_1.default.addEventListener("roundStart", (game) => {
12
+ console.log(`--- Round ${game.rounds} Start ---`);
13
+ });
14
+ index_1.default.addEventListener("rollSlots", (game) => {
15
+ const { modes, ranges } = game.getCurrentConfig();
16
+ console.log(`Active Modes: ${modes.map((m) => m.name).join(", ")}`);
17
+ console.log(`Probability Ranges: ${ranges
18
+ .map((r) => `${r.pattern.name}<=${r.threshold}`)
19
+ .join(", ")}`);
20
+ });
21
+ index_1.default.addEventListener("roundEnd", (game) => {
22
+ console.log(game.patterns.map((p) => (p ? p.name : "null")).join(" | "));
23
+ console.log(`Margin Score: ${game.marginScore}`);
24
+ console.log(`Score: ${game.score}\n`);
25
+ });
26
+ index_1.default.init();
27
+ while (index_1.default.isRunning()) {
28
+ index_1.default.play();
29
+ }
30
+ console.log("Game Over");
31
+ console.log(`Final Score: ${index_1.default.score}`);
32
+ console.log(`Active Modes at end: ${index_1.default
33
+ .getCurrentConfig()
34
+ .modes.map((m) => m.name)
35
+ .join(", ")}`);
@@ -0,0 +1,18 @@
1
+ import { patterns } from "src/pattern";
2
+ /**
3
+ * 拉霸遊戲的事件類型。
4
+ */
5
+ export type LaBaGEvent = "gameOver" | "gameStart" | "roundStart" | "roundEnd" | "rollSlots" | "calculateScore";
6
+ /**
7
+ * 代表一個圖案及其對應的分數。
8
+ */
9
+ export type Pattern = {
10
+ /** 圖案名稱 */
11
+ name: string;
12
+ /** 對應的分數陣列 */
13
+ scores: number[];
14
+ };
15
+ /**
16
+ * 圖案名稱的型別。
17
+ */
18
+ export type PatternName = (typeof patterns)[number]["name"];
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1 +1,7 @@
1
- export declare function RandInt(min: number, max: number): number;
1
+ /**
2
+ * 產生一個介於 min 和 max 之間的隨機整數(包含 min 和 max)。
3
+ * @param min - 最小值。
4
+ * @param max - 最大值。
5
+ * @returns 介於 min 和 max 之間的隨機整數。
6
+ */
7
+ export declare const randInt: (min: number, max: number) => number;
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RandInt = RandInt;
4
- function RandInt(min, max) {
5
- return Math.floor(Math.random() * (max - min + 1)) + min;
6
- }
3
+ exports.randInt = void 0;
4
+ /**
5
+ * 產生一個介於 min max 之間的隨機整數(包含 min 和 max)。
6
+ * @param min - 最小值。
7
+ * @param max - 最大值。
8
+ * @returns 介於 min 和 max 之間的隨機整數。
9
+ */
10
+ const randInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
11
+ exports.randInt = randInt;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "labag",
3
- "version": "1.2.1",
3
+ "version": "2.0.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "keywords": [],
12
12
  "author": "",
13
- "license": "ISC",
13
+ "license": "MIT",
14
14
  "type": "commonjs",
15
15
  "devDependencies": {
16
16
  "typescript": "^5.8.3"
package/src/index.ts CHANGED
@@ -1,188 +1,210 @@
1
- import { LaBaG, OneDataType, AllDataType } from "./types/LaBaG";
2
- import { Mode, ModeNames } from "./types/Mode";
3
- import { RandInt } from "./utils/RandInt";
4
- import { PlayLaBaG } from "./types/PlayLaBaG";
5
- import { JsonLaBaG } from "./types/JsonLaBaG";
6
- import { P, PData } from "./types/P";
7
- import { parseScore, verifyScore } from './utils/data';
1
+ import { LaBaG } from "./labag";
2
+ import { Mode } from "./mode";
3
+ import { randInt } from "./utils/randInt";
8
4
 
9
- const PDatas: Record<string, PData> = {
10
- Gss: {
11
- name: "咖波",
12
- code: "A",
13
- rates: { Normal: 36, SuperHHH: 19, GreenWei: 36, PiKaChu: 36 },
14
- scores: [800, 400, 180],
15
- },
16
- Hhh: {
17
- name: "阿禾",
18
- code: "B",
19
- rates: { Normal: 24, SuperHHH: 5, GreenWei: 24, PiKaChu: 24 },
20
- scores: [1500, 800, 300],
21
- },
22
- Hentai: {
23
- name: "猥褻男",
24
- code: "C",
25
- rates: { Normal: 17, SuperHHH: 19, GreenWei: 17, PiKaChu: 17 },
26
- scores: [2500, 1200, 500],
27
- },
28
- Handsun: {
29
- name: "文傑",
30
- code: "D",
31
- rates: { Normal: 12, SuperHHH: 19, GreenWei: 12, PiKaChu: 12 },
32
- scores: [2900, 1450, 690],
33
- },
34
- Kachu: {
35
- name: "皮卡丘",
36
- code: "E",
37
- rates: { Normal: 8, SuperHHH: 19, GreenWei: 8, PiKaChu: 8 },
38
- scores: [12000, 8000, 1250],
39
- },
40
- Rrr: {
41
- name: "館長",
42
- code: "F",
43
- rates: { Normal: 3, SuperHHH: 19, GreenWei: 3, PiKaChu: 3 },
44
- scores: [20000, 12000, 2500],
45
- },
46
- };
5
+ const labag = new LaBaG();
47
6
 
48
- Object.values(PDatas).forEach((pd: PData) => {
49
- new P(pd.name, pd.code, pd.scores, pd.rates);
50
- });
51
-
52
- const Modes: Record<Exclude<ModeNames, "Normal">, Mode> = {
53
- // 超級阿禾
54
- SuperHHH: {
55
- InMode: false,
56
- Rate: 15,
57
- Times: 0,
58
- Score: 0,
59
- RandNum: 0,
60
- Random(): void {
61
- this.RandNum = RandInt(1, 100);
7
+ const modes: ConstructorParameters<typeof Mode>[] = [
8
+ [
9
+ false,
10
+ "superhhh",
11
+ {
12
+ gss: 19,
13
+ hhh: 5,
14
+ hentai: 19,
15
+ handson: 19,
16
+ kachu: 19,
17
+ rrr: 19,
62
18
  },
63
- Judge(Game: LaBaG): void {
64
- if (
65
- !Game.GameRunning() ||
66
- this.RandNum === undefined ||
67
- this.Times === undefined ||
68
- this.Rate === undefined ||
69
- this.Score === undefined
70
- ) {
71
- return;
72
- }
73
-
74
- this.Score = 0; // Reset score
75
- if (this.InMode) {
76
- this.Times -= 1;
19
+ {
20
+ gameStart: (_, mode) => {
21
+ mode.active = false;
22
+ mode.variable.times = 0;
23
+ },
24
+ roundStart: (_, mode) => {
25
+ if (!mode.active) return;
26
+ mode.variable.score = 0;
27
+ mode.variable.times -= 1;
28
+ },
29
+ rollSlots: (_, mode) => {
30
+ mode.variable.randNum = randInt(1, 100);
31
+ },
32
+ roundEnd: (game, mode) => {
33
+ const { patterns } = game;
34
+ const { variable } = mode;
77
35
 
78
- if (Game.Ps.every((p) => p?.code === "B")) {
79
- this.Times += 2;
36
+ let hhhCount = 0;
37
+ let allHHH = true;
38
+ for (const p of patterns) {
39
+ if (p?.name === "hhh") hhhCount++;
40
+ else allHHH = false;
80
41
  }
81
- if (this.Times <= 0) {
82
- this.InMode = false;
83
- Game.JudgeMode();
84
- Game.ModeToScreen = true;
85
- }
86
- } else {
87
- if (this.RandNum <= this.Rate && Game.Ps.some((p) => p?.code === "B")) {
88
- this.InMode = true;
89
- this.Times += 6;
90
- Game.ModeToScreen = true;
91
- if (Modes.PiKaChu.InMode) {
92
- Modes.PiKaChu.InMode = false;
42
+
43
+ if (mode.active) {
44
+ if (allHHH) {
45
+ variable.times += 2;
93
46
  }
94
- // 超級阿禾加倍
95
- if (Game.Ps.every((p) => p?.code === "B")) {
96
- this.Score = Math.round((Game.Score * Game.ScoreTime) / 2);
97
- Game.Score += this.Score;
47
+ if (variable.times <= 0) {
48
+ mode.active = false;
49
+ }
50
+ } else {
51
+ if (variable.randNum <= variable.rate && hhhCount > 0) {
52
+ mode.active = true;
53
+ variable.times += 6;
54
+
55
+ for (let i = 0; i < patterns.length; i++) {
56
+ if (patterns[i]?.name === "hhh") {
57
+ patterns[i] = variable.pattern;
58
+ }
59
+ }
98
60
  }
99
61
  }
100
- }
62
+ },
101
63
  },
102
- },
103
-
104
- GreenWei: {
105
- InMode: false,
106
- Rate: 35,
107
- Times: 0,
108
- Score: 0, // 咖波累積數
109
- RandNum: 0,
110
- Random(): void {
111
- this.RandNum = RandInt(1, 100);
64
+ {
65
+ times: 0,
66
+ rate: 15,
67
+ score: 0,
68
+ randNum: 0,
69
+ pattern: {
70
+ name: "superhhh",
71
+ scores: [1500, 800, 300],
72
+ },
112
73
  },
113
- Judge(Game: LaBaG): void {
114
- if (
115
- !Game.GameRunning() ||
116
- this.RandNum === undefined ||
117
- this.Times === undefined ||
118
- this.Rate === undefined ||
119
- this.Score === undefined
120
- ) {
121
- return;
122
- }
123
-
124
- if (this.InMode) {
125
- this.Times -= 1;
126
-
127
- if (Game.Ps.every((p) => p?.code === "A")) {
128
- this.Times += 1;
74
+ ],
75
+ [
76
+ false,
77
+ "greenwei",
78
+ {
79
+ gss: 36,
80
+ hhh: 24,
81
+ hentai: 17,
82
+ handson: 12,
83
+ kachu: 8,
84
+ rrr: 3,
85
+ },
86
+ {
87
+ gameStart: (_, mode) => {
88
+ mode.active = false;
89
+ mode.variable.times = 0;
90
+ },
91
+ roundStart: (_, mode) => {
92
+ if (!mode.active) return;
93
+ mode.variable.times -= 1;
94
+ },
95
+ rollSlots: (_, mode) => {
96
+ mode.variable.randNum = randInt(1, 100);
97
+ },
98
+ calculateScore: (game, mode) => {
99
+ if (mode.active) {
100
+ game.marginScore = Math.round(game.marginScore * 3);
129
101
  }
130
- if (this.Times <= 0) {
131
- this.InMode = false;
132
- Game.JudgeMode();
133
- Game.ModeToScreen = true;
102
+ },
103
+ roundEnd: (game, mode) => {
104
+ const { patterns } = game;
105
+ const { variable } = mode;
106
+
107
+ let gssCount = 0;
108
+ let allGSS = true;
109
+ for (const p of patterns) {
110
+ if (p?.name === "gss") gssCount++;
111
+ else allGSS = false;
134
112
  }
135
- } else {
136
- if (
137
- this.RandNum <= this.Rate &&
138
- Game.Ps.every((p) => p?.code === "A")
139
- ) {
140
- this.InMode = true;
141
- this.Times += 2;
142
- Game.ModeToScreen = true;
143
- if (Modes.PiKaChu.InMode) {
144
- Modes.PiKaChu.InMode = false;
113
+
114
+ variable.count += gssCount;
115
+
116
+ if (mode.active) {
117
+ if (allGSS) {
118
+ variable.times += 1;
119
+ }
120
+ if (variable.times <= 0) {
121
+ mode.active = false;
145
122
  }
146
- return;
147
- } else if (this.Score >= 20) {
148
- // 咖波累積數達到 20
149
- this.InMode = true;
150
- this.Times += 2;
151
- this.Score = 0;
152
- Game.ModeToScreen = true;
153
- if (Modes.PiKaChu.InMode) {
154
- Modes.PiKaChu.InMode = false;
123
+ } else {
124
+ let activated = false;
125
+ if (variable.randNum <= variable.rate && allGSS) {
126
+ activated = true;
127
+ variable.times += 2;
128
+ } else if (variable.count >= 20) {
129
+ activated = true;
130
+ variable.times += 2;
131
+ variable.count -= 20;
132
+ }
133
+
134
+ if (activated) {
135
+ mode.active = true;
136
+ for (let i = 0; i < patterns.length; i++) {
137
+ if (patterns[i]?.name === "gss") {
138
+ patterns[i] = variable.pattern;
139
+ }
140
+ }
155
141
  }
156
- return;
157
142
  }
158
- }
143
+ },
159
144
  },
160
- },
161
-
162
- PiKaChu: {
163
- InMode: false,
164
- Times: 0,
165
- Judge(Game: LaBaG) {
166
- if (!Game.GameRunning() && this.Times !== undefined) {
167
- // 關掉其他模式
168
- Modes.SuperHHH.InMode = false;
169
- Modes.GreenWei.InMode = false;
170
- if (Game.Ps.some((p) => p?.code === "E")) {
171
- this.InMode = true;
172
- Game.Played -= 5;
173
- this.Times += 1;
174
- Game.ModeToScreen = true;
175
- } else {
176
- this.InMode = false;
145
+ {
146
+ times: 0,
147
+ rate: 35,
148
+ randNum: 0,
149
+ count: 0,
150
+ pattern: {
151
+ name: "greenwei",
152
+ scores: [800, 400, 180],
153
+ },
154
+ },
155
+ ],
156
+ [
157
+ false,
158
+ "pikachu",
159
+ {
160
+ gss: 36,
161
+ hhh: 24,
162
+ hentai: 17,
163
+ handson: 12,
164
+ kachu: 8,
165
+ rrr: 3,
166
+ },
167
+ {
168
+ gameStart: (_, mode) => {
169
+ mode.active = false;
170
+ mode.variable.times = 0;
171
+ },
172
+ roundEnd: (game, mode) => {
173
+ if (
174
+ !game.isRunning() &&
175
+ game.patterns.some((p) => p && p.name === "kachu")
176
+ ) {
177
+ mode.active = true;
178
+ game.played -= 5;
179
+ mode.variable.times += 1;
177
180
  }
178
- }
181
+ },
179
182
  },
180
- },
181
- };
183
+ {
184
+ times: 0,
185
+ pattern: {
186
+ name: "pikachu",
187
+ scores: [12000, 8000, 1250],
188
+ },
189
+ },
190
+ ],
191
+ [
192
+ true,
193
+ "normal",
194
+ {
195
+ gss: 36,
196
+ hhh: 24,
197
+ hentai: 17,
198
+ handson: 12,
199
+ kachu: 8,
200
+ rrr: 3,
201
+ },
202
+ ],
203
+ ];
204
+
205
+ for (const modeArgs of modes) {
206
+ const mode = new Mode(...modeArgs);
207
+ labag.addMode(mode);
208
+ }
182
209
 
183
- export {
184
- Modes,
185
- PDatas,
186
- parseScore,
187
- verifyScore,
188
- };
210
+ export default labag;