labag 1.2.2 → 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/index.d.ts CHANGED
@@ -1,9 +1,3 @@
1
- import { LaBaG, OneDataType, AllDataType } from "./types/LaBaG";
2
- import { Mode, ModeNames } from "./types/Mode";
3
- import { PlayLaBaG } from "./types/PlayLaBaG";
4
- import { JsonLaBaG } from "./types/JsonLaBaG";
5
- import { P, PData } from "./types/P";
6
- import { parseScore, verifyScore } from './utils/data';
7
- declare const PDatas: Record<string, PData>;
8
- declare const Modes: Record<Exclude<ModeNames, "Normal">, Mode>;
9
- export { OneDataType, AllDataType, LaBaG, PlayLaBaG, JsonLaBaG, Modes, ModeNames, P, PData, PDatas, parseScore, verifyScore, };
1
+ import { LaBaG } from "./labag";
2
+ declare const labag: LaBaG;
3
+ export default labag;
package/dist/index.js CHANGED
@@ -1,178 +1,208 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.verifyScore = exports.parseScore = exports.PDatas = exports.P = exports.Modes = exports.JsonLaBaG = exports.PlayLaBaG = void 0;
4
- const RandInt_1 = require("./utils/RandInt");
5
- const PlayLaBaG_1 = require("./types/PlayLaBaG");
6
- Object.defineProperty(exports, "PlayLaBaG", { enumerable: true, get: function () { return PlayLaBaG_1.PlayLaBaG; } });
7
- const JsonLaBaG_1 = require("./types/JsonLaBaG");
8
- Object.defineProperty(exports, "JsonLaBaG", { enumerable: true, get: function () { return JsonLaBaG_1.JsonLaBaG; } });
9
- const P_1 = require("./types/P");
10
- Object.defineProperty(exports, "P", { enumerable: true, get: function () { return P_1.P; } });
11
- const data_1 = require("./utils/data");
12
- Object.defineProperty(exports, "parseScore", { enumerable: true, get: function () { return data_1.parseScore; } });
13
- Object.defineProperty(exports, "verifyScore", { enumerable: true, get: function () { return data_1.verifyScore; } });
14
- const PDatas = {
15
- Gss: {
16
- name: "咖波",
17
- code: "A",
18
- rates: { Normal: 36, SuperHHH: 19, GreenWei: 36, PiKaChu: 36 },
19
- scores: [800, 400, 180],
20
- },
21
- Hhh: {
22
- name: "阿禾",
23
- code: "B",
24
- rates: { Normal: 24, SuperHHH: 5, GreenWei: 24, PiKaChu: 24 },
25
- scores: [1500, 800, 300],
26
- },
27
- Hentai: {
28
- name: "猥褻男",
29
- code: "C",
30
- rates: { Normal: 17, SuperHHH: 19, GreenWei: 17, PiKaChu: 17 },
31
- scores: [2500, 1200, 500],
32
- },
33
- Handsun: {
34
- name: "文傑",
35
- code: "D",
36
- rates: { Normal: 12, SuperHHH: 19, GreenWei: 12, PiKaChu: 12 },
37
- scores: [2900, 1450, 690],
38
- },
39
- Kachu: {
40
- name: "皮卡丘",
41
- code: "E",
42
- rates: { Normal: 8, SuperHHH: 19, GreenWei: 8, PiKaChu: 8 },
43
- scores: [12000, 8000, 1250],
44
- },
45
- Rrr: {
46
- name: "館長",
47
- code: "F",
48
- rates: { Normal: 3, SuperHHH: 19, GreenWei: 3, PiKaChu: 3 },
49
- scores: [20000, 12000, 2500],
50
- },
51
- };
52
- exports.PDatas = PDatas;
53
- Object.values(PDatas).forEach((pd) => {
54
- new P_1.P(pd.name, pd.code, pd.scores, pd.rates);
55
- });
56
- const Modes = {
57
- // 超級阿禾
58
- SuperHHH: {
59
- InMode: false,
60
- Rate: 15,
61
- Times: 0,
62
- Score: 0,
63
- RandNum: 0,
64
- Random() {
65
- this.RandNum = (0, RandInt_1.RandInt)(1, 100);
3
+ const labag_1 = require("./labag");
4
+ const mode_1 = require("./mode");
5
+ const randInt_1 = require("./utils/randInt");
6
+ const labag = new labag_1.LaBaG();
7
+ const modes = [
8
+ [
9
+ false,
10
+ "superhhh",
11
+ {
12
+ gss: 19,
13
+ hhh: 5,
14
+ hentai: 19,
15
+ handson: 19,
16
+ kachu: 19,
17
+ rrr: 19,
66
18
  },
67
- Judge(Game) {
68
- if (!Game.GameRunning() ||
69
- this.RandNum === undefined ||
70
- this.Times === undefined ||
71
- this.Rate === undefined ||
72
- this.Score === undefined) {
73
- return;
74
- }
75
- this.Score = 0; // Reset score
76
- if (this.InMode) {
77
- this.Times -= 1;
78
- if (Game.Ps.every((p) => p?.code === "B")) {
79
- this.Times += 2;
80
- }
81
- if (this.Times <= 0) {
82
- this.InMode = false;
83
- Game.JudgeMode();
84
- Game.ModeToScreen = true;
19
+ {
20
+ gameStart: (_, mode) => {
21
+ mode.active = false;
22
+ mode.variable.times = 0;
23
+ },
24
+ roundStart: (_, mode) => {
25
+ if (!mode.active)
26
+ return;
27
+ mode.variable.score = 0;
28
+ mode.variable.times -= 1;
29
+ },
30
+ rollSlots: (_, mode) => {
31
+ mode.variable.randNum = (0, randInt_1.randInt)(1, 100);
32
+ },
33
+ roundEnd: (game, mode) => {
34
+ const { patterns } = game;
35
+ const { variable } = mode;
36
+ let hhhCount = 0;
37
+ let allHHH = true;
38
+ for (const p of patterns) {
39
+ if (p?.name === "hhh")
40
+ hhhCount++;
41
+ else
42
+ allHHH = false;
85
43
  }
86
- }
87
- else {
88
- if (this.RandNum <= this.Rate && Game.Ps.some((p) => p?.code === "B")) {
89
- this.InMode = true;
90
- this.Times += 6;
91
- Game.ModeToScreen = true;
92
- if (Modes.PiKaChu.InMode) {
93
- Modes.PiKaChu.InMode = false;
44
+ if (mode.active) {
45
+ if (allHHH) {
46
+ variable.times += 2;
47
+ }
48
+ if (variable.times <= 0) {
49
+ mode.active = false;
94
50
  }
95
- // 超級阿禾加倍
96
- if (Game.Ps.every((p) => p?.code === "B")) {
97
- this.Score = Math.round((Game.Score * Game.ScoreTime) / 2);
98
- Game.Score += this.Score;
51
+ }
52
+ else {
53
+ if (variable.randNum <= variable.rate && hhhCount > 0) {
54
+ mode.active = true;
55
+ variable.times += 6;
56
+ for (let i = 0; i < patterns.length; i++) {
57
+ if (patterns[i]?.name === "hhh") {
58
+ patterns[i] = variable.pattern;
59
+ }
60
+ }
99
61
  }
100
62
  }
101
- }
63
+ },
102
64
  },
103
- },
104
- GreenWei: {
105
- InMode: false,
106
- Rate: 35,
107
- Times: 0,
108
- Score: 0, // 咖波累積數
109
- RandNum: 0,
110
- Random() {
111
- this.RandNum = (0, RandInt_1.RandInt)(1, 100);
65
+ {
66
+ times: 0,
67
+ rate: 15,
68
+ score: 0,
69
+ randNum: 0,
70
+ pattern: {
71
+ name: "superhhh",
72
+ scores: [1500, 800, 300],
73
+ },
112
74
  },
113
- Judge(Game) {
114
- if (!Game.GameRunning() ||
115
- this.RandNum === undefined ||
116
- this.Times === undefined ||
117
- this.Rate === undefined ||
118
- this.Score === undefined) {
119
- return;
120
- }
121
- if (this.InMode) {
122
- this.Times -= 1;
123
- if (Game.Ps.every((p) => p?.code === "A")) {
124
- this.Times += 1;
75
+ ],
76
+ [
77
+ false,
78
+ "greenwei",
79
+ {
80
+ gss: 36,
81
+ hhh: 24,
82
+ hentai: 17,
83
+ handson: 12,
84
+ kachu: 8,
85
+ rrr: 3,
86
+ },
87
+ {
88
+ gameStart: (_, mode) => {
89
+ mode.active = false;
90
+ mode.variable.times = 0;
91
+ },
92
+ roundStart: (_, mode) => {
93
+ if (!mode.active)
94
+ return;
95
+ mode.variable.times -= 1;
96
+ },
97
+ rollSlots: (_, mode) => {
98
+ mode.variable.randNum = (0, randInt_1.randInt)(1, 100);
99
+ },
100
+ calculateScore: (game, mode) => {
101
+ if (mode.active) {
102
+ game.marginScore = Math.round(game.marginScore * 3);
125
103
  }
126
- if (this.Times <= 0) {
127
- this.InMode = false;
128
- Game.JudgeMode();
129
- Game.ModeToScreen = true;
104
+ },
105
+ roundEnd: (game, mode) => {
106
+ const { patterns } = game;
107
+ const { variable } = mode;
108
+ let gssCount = 0;
109
+ let allGSS = true;
110
+ for (const p of patterns) {
111
+ if (p?.name === "gss")
112
+ gssCount++;
113
+ else
114
+ allGSS = false;
130
115
  }
131
- }
132
- else {
133
- if (this.RandNum <= this.Rate &&
134
- Game.Ps.every((p) => p?.code === "A")) {
135
- this.InMode = true;
136
- this.Times += 2;
137
- Game.ModeToScreen = true;
138
- if (Modes.PiKaChu.InMode) {
139
- Modes.PiKaChu.InMode = false;
116
+ variable.count += gssCount;
117
+ if (mode.active) {
118
+ if (allGSS) {
119
+ variable.times += 1;
120
+ }
121
+ if (variable.times <= 0) {
122
+ mode.active = false;
140
123
  }
141
- return;
142
124
  }
143
- else if (this.Score >= 20) {
144
- // 咖波累積數達到 20
145
- this.InMode = true;
146
- this.Times += 2;
147
- this.Score = 0;
148
- Game.ModeToScreen = true;
149
- if (Modes.PiKaChu.InMode) {
150
- Modes.PiKaChu.InMode = false;
125
+ else {
126
+ let activated = false;
127
+ if (variable.randNum <= variable.rate && allGSS) {
128
+ activated = true;
129
+ variable.times += 2;
130
+ }
131
+ else if (variable.count >= 20) {
132
+ activated = true;
133
+ variable.times += 2;
134
+ variable.count -= 20;
135
+ }
136
+ if (activated) {
137
+ mode.active = true;
138
+ for (let i = 0; i < patterns.length; i++) {
139
+ if (patterns[i]?.name === "gss") {
140
+ patterns[i] = variable.pattern;
141
+ }
142
+ }
151
143
  }
152
- return;
153
144
  }
154
- }
145
+ },
155
146
  },
156
- },
157
- PiKaChu: {
158
- InMode: false,
159
- Times: 0,
160
- Judge(Game) {
161
- if (!Game.GameRunning() && this.Times !== undefined) {
162
- // 關掉其他模式
163
- Modes.SuperHHH.InMode = false;
164
- Modes.GreenWei.InMode = false;
165
- if (Game.Ps.some((p) => p?.code === "E")) {
166
- this.InMode = true;
167
- Game.Played -= 5;
168
- this.Times += 1;
169
- Game.ModeToScreen = true;
170
- }
171
- else {
172
- this.InMode = false;
147
+ {
148
+ times: 0,
149
+ rate: 35,
150
+ randNum: 0,
151
+ count: 0,
152
+ pattern: {
153
+ name: "greenwei",
154
+ scores: [800, 400, 180],
155
+ },
156
+ },
157
+ ],
158
+ [
159
+ false,
160
+ "pikachu",
161
+ {
162
+ gss: 36,
163
+ hhh: 24,
164
+ hentai: 17,
165
+ handson: 12,
166
+ kachu: 8,
167
+ rrr: 3,
168
+ },
169
+ {
170
+ gameStart: (_, mode) => {
171
+ mode.active = false;
172
+ mode.variable.times = 0;
173
+ },
174
+ roundEnd: (game, mode) => {
175
+ if (!game.isRunning() &&
176
+ game.patterns.some((p) => p && p.name === "kachu")) {
177
+ mode.active = true;
178
+ game.played -= 5;
179
+ mode.variable.times += 1;
173
180
  }
174
- }
181
+ },
182
+ },
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,
175
201
  },
176
- },
177
- };
178
- exports.Modes = Modes;
202
+ ],
203
+ ];
204
+ for (const modeArgs of modes) {
205
+ const mode = new mode_1.Mode(...modeArgs);
206
+ labag.addMode(mode);
207
+ }
208
+ exports.default = labag;
@@ -0,0 +1,78 @@
1
+ import { Mode } from "./mode";
2
+ import { Pattern, LaBaGEvent } from "./types";
3
+ /**
4
+ * 拉霸遊戲的主要類別。
5
+ */
6
+ export declare class LaBaG {
7
+ /** 總遊玩次數限制 */
8
+ times: number;
9
+ /** 已遊玩次數 */
10
+ played: number;
11
+ /** 當前進行的輪次 */
12
+ rounds: number;
13
+ /** 當前分數 */
14
+ score: number;
15
+ /** 邊際分數 */
16
+ marginScore: number;
17
+ /** 當前轉出的圖案組合 */
18
+ patterns: [Pattern | null, Pattern | null, Pattern | null];
19
+ /** 遊戲模式列表 */
20
+ modes: Mode[];
21
+ /** 事件監聽器列表 */
22
+ eventListeners: Record<LaBaGEvent, ((game: LaBaG) => void)[]>;
23
+ /**
24
+ * 初始化拉霸遊戲。
25
+ * @param times - 總遊玩次數,預設為 30。
26
+ */
27
+ constructor(times?: number);
28
+ /**
29
+ * 觸發指定事件。
30
+ * @param event - 要觸發的事件名稱。
31
+ */
32
+ private emit;
33
+ /**
34
+ * 新增事件監聽器。
35
+ * @param event - 事件名稱。
36
+ * @param listener - 監聽器函式。
37
+ */
38
+ addEventListener(event: LaBaGEvent, callbackFn: (game: LaBaG) => void): void;
39
+ /**
40
+ * 新增遊戲模式。
41
+ * @param mode - 要新增的模式。
42
+ */
43
+ addMode(mode: Mode): void;
44
+ /**
45
+ * 檢查遊戲是否正在進行中(未達次數上限)。
46
+ * @returns 如果遊戲仍在進行中則返回 true,否則返回 false。
47
+ */
48
+ isRunning(): boolean;
49
+ /**
50
+ * 取得目前遊戲的相關設定
51
+ */
52
+ getCurrentConfig(): {
53
+ modes: Mode[];
54
+ ranges: {
55
+ threshold: number;
56
+ pattern: Pattern;
57
+ }[];
58
+ };
59
+ /**
60
+ * 初始化遊戲狀態。
61
+ */
62
+ init(): void;
63
+ /**
64
+ * 新的一小輪開始。
65
+ */
66
+ private roundStart;
67
+ /**
68
+ * 轉動拉霸機,產生隨機圖案。
69
+ */
70
+ private rollSlots;
71
+ /**
72
+ * 計算分數。
73
+ */
74
+ private calculateScore;
75
+ private roundEnd;
76
+ private gameOver;
77
+ play(): void;
78
+ }
package/dist/labag.js ADDED
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LaBaG = void 0;
4
+ const pattern_1 = require("./pattern");
5
+ const randInt_1 = require("./utils/randInt");
6
+ /**
7
+ * 拉霸遊戲的主要類別。
8
+ */
9
+ class LaBaG {
10
+ /** 總遊玩次數限制 */
11
+ times;
12
+ /** 已遊玩次數 */
13
+ played;
14
+ /** 當前進行的輪次 */
15
+ rounds;
16
+ /** 當前分數 */
17
+ score;
18
+ /** 邊際分數 */
19
+ marginScore;
20
+ /** 當前轉出的圖案組合 */
21
+ patterns;
22
+ /** 遊戲模式列表 */
23
+ modes;
24
+ /** 事件監聽器列表 */
25
+ eventListeners;
26
+ /**
27
+ * 初始化拉霸遊戲。
28
+ * @param times - 總遊玩次數,預設為 30。
29
+ */
30
+ constructor(times = 30) {
31
+ this.times = times;
32
+ this.played = 0;
33
+ this.rounds = 0;
34
+ this.score = 0;
35
+ this.marginScore = 0;
36
+ this.patterns = [null, null, null];
37
+ this.modes = [];
38
+ this.eventListeners = {
39
+ gameOver: [],
40
+ gameStart: [],
41
+ roundStart: [],
42
+ roundEnd: [],
43
+ rollSlots: [],
44
+ calculateScore: [],
45
+ };
46
+ }
47
+ /**
48
+ * 觸發指定事件。
49
+ * @param event - 要觸發的事件名稱。
50
+ */
51
+ emit(event) {
52
+ this.eventListeners[event].forEach((fn) => fn(this));
53
+ }
54
+ /**
55
+ * 新增事件監聽器。
56
+ * @param event - 事件名稱。
57
+ * @param listener - 監聽器函式。
58
+ */
59
+ addEventListener(event, callbackFn) {
60
+ this.eventListeners[event].push(callbackFn);
61
+ }
62
+ /**
63
+ * 新增遊戲模式。
64
+ * @param mode - 要新增的模式。
65
+ */
66
+ addMode(mode) {
67
+ this.modes.push(mode);
68
+ // 註冊特定模式的監聽器
69
+ Object.entries(mode.eventListener).forEach(([event, listener]) => {
70
+ if (listener) {
71
+ this.addEventListener(event, (game) => listener(game, mode));
72
+ }
73
+ });
74
+ }
75
+ /**
76
+ * 檢查遊戲是否正在進行中(未達次數上限)。
77
+ * @returns 如果遊戲仍在進行中則返回 true,否則返回 false。
78
+ */
79
+ isRunning() {
80
+ return this.played < this.times;
81
+ }
82
+ /**
83
+ * 取得目前遊戲的相關設定
84
+ */
85
+ getCurrentConfig() {
86
+ const activeModes = this.modes.filter((m) => m.active);
87
+ if (activeModes.length === 0) {
88
+ console.warn("目前沒有啟用中的模式,無法轉動拉霸機。");
89
+ return { modes: activeModes, ranges: [] };
90
+ }
91
+ // 合併所有啟用中模式的機率設定
92
+ const combinedRates = {
93
+ gss: 0,
94
+ hhh: 0,
95
+ hentai: 0,
96
+ handson: 0,
97
+ kachu: 0,
98
+ rrr: 0,
99
+ };
100
+ activeModes.forEach((mode) => {
101
+ Object.entries(mode.rates).forEach(([patternName, rate]) => {
102
+ combinedRates[patternName] += rate;
103
+ });
104
+ });
105
+ // 預先計算合併後的區間
106
+ const ranges = [];
107
+ let acc = 0;
108
+ for (const pattern of pattern_1.patterns) {
109
+ const rate = combinedRates[pattern.name];
110
+ if (rate !== undefined) {
111
+ acc += rate;
112
+ ranges.push({ threshold: acc, pattern });
113
+ }
114
+ }
115
+ return { modes: activeModes, ranges };
116
+ }
117
+ /**
118
+ * 初始化遊戲狀態。
119
+ */
120
+ init() {
121
+ this.played = 0;
122
+ this.score = 0;
123
+ this.marginScore = 0;
124
+ this.patterns = [null, null, null];
125
+ this.rounds = 0;
126
+ this.emit("gameStart");
127
+ }
128
+ /**
129
+ * 新的一小輪開始。
130
+ */
131
+ roundStart() {
132
+ this.played += 1;
133
+ this.rounds += 1;
134
+ this.marginScore = 0;
135
+ this.emit("roundStart");
136
+ }
137
+ /**
138
+ * 轉動拉霸機,產生隨機圖案。
139
+ */
140
+ rollSlots() {
141
+ const { ranges } = this.getCurrentConfig();
142
+ const rangesAcc = ranges.length > 0 ? ranges[ranges.length - 1].threshold : 0;
143
+ // 產生 3 個隨機數字
144
+ const randomNums = [
145
+ (0, randInt_1.randInt)(1, rangesAcc),
146
+ (0, randInt_1.randInt)(1, rangesAcc),
147
+ (0, randInt_1.randInt)(1, rangesAcc),
148
+ ];
149
+ randomNums.forEach((num, index) => {
150
+ // 根據預先計算的區間找到對應的圖案
151
+ const match = ranges.find((r) => num <= r.threshold);
152
+ if (match) {
153
+ this.patterns[index] = match.pattern;
154
+ }
155
+ else {
156
+ this.patterns[index] = null;
157
+ }
158
+ });
159
+ this.emit("rollSlots");
160
+ }
161
+ /**
162
+ * 計算分數。
163
+ */
164
+ calculateScore() {
165
+ const [p1, p2, p3] = this.patterns;
166
+ if (!p1 || !p2 || !p3) {
167
+ console.warn("圖案未正確生成,無法計算分數。");
168
+ return;
169
+ }
170
+ if (p1.name === p2.name && p2.name === p3.name) {
171
+ // 三個圖案相同
172
+ this.marginScore += p1.scores[0];
173
+ }
174
+ else if (p1.name === p2.name ||
175
+ p2.name === p3.name ||
176
+ p1.name === p3.name) {
177
+ // 兩個圖案相同
178
+ if (p1.name === p2.name) {
179
+ this.marginScore += p1.scores[1];
180
+ this.marginScore += p3.scores[2];
181
+ }
182
+ else if (p2.name === p3.name) {
183
+ this.marginScore += p2.scores[1];
184
+ this.marginScore += p1.scores[2];
185
+ }
186
+ else {
187
+ this.marginScore += p1.scores[1];
188
+ this.marginScore += p2.scores[2];
189
+ }
190
+ this.marginScore = Math.round(this.marginScore / 1.4);
191
+ }
192
+ else {
193
+ // 三個圖案皆不同
194
+ this.marginScore += p1.scores[2];
195
+ this.marginScore += p2.scores[2];
196
+ this.marginScore += p3.scores[2];
197
+ this.marginScore = Math.round(this.marginScore / 3);
198
+ }
199
+ this.emit("calculateScore");
200
+ }
201
+ roundEnd() {
202
+ this.score += this.marginScore;
203
+ this.emit("roundEnd");
204
+ }
205
+ gameOver() {
206
+ this.emit("gameOver");
207
+ }
208
+ play() {
209
+ if (!this.isRunning()) {
210
+ console.warn("遊戲次數已達上限,無法繼續遊玩。");
211
+ return;
212
+ }
213
+ this.roundStart();
214
+ this.rollSlots();
215
+ this.calculateScore();
216
+ this.roundEnd();
217
+ if (!this.isRunning()) {
218
+ this.gameOver();
219
+ }
220
+ }
221
+ }
222
+ exports.LaBaG = LaBaG;