From 668bf9a226d9856e3ce1dfd77ea9429548dd92b0 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 29 Jan 2024 14:14:00 +0900 Subject: [PATCH] wip --- .../backend/src/core/GlobalEventService.ts | 2 + packages/backend/src/core/MahjongService.ts | 40 +++++++++++++++++-- .../api/stream/channels/mahjong-room.ts | 8 ++++ .../frontend/src/pages/mahjong/room.game.vue | 27 ++++++++++--- packages/misskey-mahjong/src/engine.master.ts | 34 +++++++++++++++- packages/misskey-mahjong/src/engine.player.ts | 14 +++++++ 6 files changed, 114 insertions(+), 11 deletions(-) diff --git a/packages/backend/src/core/GlobalEventService.ts b/packages/backend/src/core/GlobalEventService.ts index 629ef1b01d..dcf643a7a5 100644 --- a/packages/backend/src/core/GlobalEventService.ts +++ b/packages/backend/src/core/GlobalEventService.ts @@ -226,6 +226,8 @@ export interface MahjongRoomEventTypes { target: Mahjong.Common.House; tile: Mahjong.Common.Tile; }; + endKyoku: { + }; } //#endregion diff --git a/packages/backend/src/core/MahjongService.ts b/packages/backend/src/core/MahjongService.ts index 9e962dc22b..ddc2d2cc56 100644 --- a/packages/backend/src/core/MahjongService.ts +++ b/packages/backend/src/core/MahjongService.ts @@ -300,7 +300,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { this.waitForTurn(room, userId, engine); } else if (res.type === 'kanned') { // TODO - } else if (res.type === 'ronned') { + } else if (res.type === 'endKyoku') { // TODO } } @@ -415,7 +415,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { this.answer(room, engine, currentAnswers); return; } - }, 2000); + }, 1000); this.globalEventService.publishMahjongRoomStream(room.id, 'dahai', { house: house, tile }); } else { @@ -445,6 +445,38 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { await this.dahai(room, engine, myHouse, tile); } + @bindThis + public async commit_kakan(roomId: MiMahjongGame['id'], user: MiUser) { + const room = await this.getRoom(roomId); + if (room == null) return; + if (room.gameState == null) return; + + const engine = new Mahjong.MasterGameEngine(room.gameState); + const myHouse = user.id === room.user1Id ? engine.state.user1House : user.id === room.user2Id ? engine.state.user2House : user.id === room.user3Id ? engine.state.user3House : engine.state.user4House; + + await this.clearTurnWaitingTimer(room.id); + + const res = engine.commit_kakan(myHouse); + + this.globalEventService.publishMahjongRoomStream(room.id, 'kakanned', { }); + } + + @bindThis + public async commit_hora(roomId: MiMahjongGame['id'], user: MiUser) { + const room = await this.getRoom(roomId); + if (room == null) return; + if (room.gameState == null) return; + + const engine = new Mahjong.MasterGameEngine(room.gameState); + const myHouse = user.id === room.user1Id ? engine.state.user1House : user.id === room.user2Id ? engine.state.user2House : user.id === room.user3Id ? engine.state.user3House : engine.state.user4House; + + await this.clearTurnWaitingTimer(room.id); + + const res = engine.commit_hora(myHouse); + + this.globalEventService.publishMahjongRoomStream(room.id, 'horad', { }); + } + @bindThis public async commit_ron(roomId: MiMahjongGame['id'], user: MiUser) { const room = await this.getRoom(roomId); @@ -504,7 +536,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { } /** - * プレイヤーの行動を待つ(打牌もしくはツモ和了) + * プレイヤーの行動(打牌、加槓、ツモ和了)を待つ * 制限時間が過ぎたらツモ切り * NOTE: 時間切れチェックが行われたときにタイミングによっては次のwaitingが始まっている場合があることを考慮し、Setに一意のIDを格納する構造としている * @param room @@ -536,7 +568,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { } /** - * プレイヤーが打牌またはツモ和了したら呼ぶ + * プレイヤーが行動(打牌、加槓、ツモ和了)したら呼ぶ * @param roomId */ @bindThis diff --git a/packages/backend/src/server/api/stream/channels/mahjong-room.ts b/packages/backend/src/server/api/stream/channels/mahjong-room.ts index e7a0c81abd..51f953443a 100644 --- a/packages/backend/src/server/api/stream/channels/mahjong-room.ts +++ b/packages/backend/src/server/api/stream/channels/mahjong-room.ts @@ -39,6 +39,7 @@ class MahjongRoomChannel extends Channel { case 'updateSettings': this.updateSettings(body.key, body.value); break; case 'addAi': this.addAi(); break; case 'dahai': this.dahai(body.tile, body.riichi); break; + case 'hora': this.hora(); break; case 'ron': this.ron(); break; case 'pon': this.pon(); break; case 'nop': this.nop(); break; @@ -74,6 +75,13 @@ class MahjongRoomChannel extends Channel { this.mahjongService.commit_dahai(this.roomId!, this.user, tile, riichi); } + @bindThis + private async hora() { + if (this.user == null) return; + + this.mahjongService.commit_hora(this.roomId!, this.user); + } + @bindThis private async ron() { if (this.user == null) return; diff --git a/packages/frontend/src/pages/mahjong/room.game.vue b/packages/frontend/src/pages/mahjong/room.game.vue index 9105992e2d..68e9542d74 100644 --- a/packages/frontend/src/pages/mahjong/room.game.vue +++ b/packages/frontend/src/pages/mahjong/room.game.vue @@ -79,7 +79,7 @@ SPDX-License-Identifier: AGPL-3.0-only Ron Pon Skip - Tsumo + Tsumo Riichi @@ -227,6 +227,26 @@ function riichi() { }); } +function kakan() { + if (!isMyTurn.value) return; + + engine.value.commit_kakan(engine.value.myHouse); + triggerRef(engine); + + props.connection!.send('kakan', { + }); +} + +function hora() { + if (!isMyTurn.value) return; + + engine.value.commit_hora(engine.value.myHouse); + triggerRef(engine); + + props.connection!.send('hora', { + }); +} + function ron() { engine.value.commit_ron(engine.value.state.canRonSource, engine.value.myHouse); triggerRef(engine); @@ -236,9 +256,6 @@ function ron() { } function pon() { - engine.value.commit_pon(engine.value.state.canPonSource, engine.value.myHouse); - triggerRef(engine); - props.connection!.send('pon', { }); } @@ -336,8 +353,6 @@ function onStreamPonned(log) { // return; //} - if (log.target === engine.value.myHouse) return; - engine.value.commit_pon(log.source, log.target); triggerRef(engine); diff --git a/packages/misskey-mahjong/src/engine.master.ts b/packages/misskey-mahjong/src/engine.master.ts index b581ba9191..539b1d25d9 100644 --- a/packages/misskey-mahjong/src/engine.master.ts +++ b/packages/misskey-mahjong/src/engine.master.ts @@ -13,6 +13,10 @@ export type MasterState = { user2House: House; user3House: House; user4House: House; + + round: 'e' | 's' | 'w' | 'n'; + kyoku: number; + tiles: Tile[]; /** @@ -122,6 +126,8 @@ export class MasterGameEngine { user2House: 's', user3House: 'w', user4House: 'n', + round: 'e', + kyoku: 1, tiles, handTiles: { e: eHandTiles, @@ -198,6 +204,12 @@ export class MasterGameEngine { } } + private endKyoku() { + const newState = MasterGameEngine.createInitialState(); + newState.kyoku = this.state.kyoku + 1; + newState.points = this.state.points; + } + public commit_dahai(house: House, tile: Tile, riichi = false) { if (this.state.turn !== house) throw new Error('Not your turn'); @@ -311,6 +323,21 @@ export class MasterGameEngine { }; } + public commit_kakan(house: House) { + } + + /** + * ツモ和了 + * @param house + */ + public commit_hora(house: House) { + if (this.state.turn !== house) throw new Error('Not your turn'); + + const yakus = Utils.getYakus(this.state.handTiles[house], null); + + this.endKyoku(); + } + public commit_resolveCallAndRonInterruption(answers: { pon: boolean; cii: boolean; @@ -328,7 +355,10 @@ export class MasterGameEngine { if (this.state.ronAsking != null && answers.ron.length > 0) { // TODO - return; + this.endKyoku(); + return { + type: 'endKyoku', + }; } if (this.state.kanAsking != null && answers.kan) { @@ -401,6 +431,8 @@ export class MasterGameEngine { user2House: this.state.user2House, user3House: this.state.user3House, user4House: this.state.user4House, + round: this.state.round, + kyoku: this.state.kyoku, tilesCount: this.state.tiles.length, handTiles: { e: house === 'e' ? this.state.handTiles.e : this.state.handTiles.e.map(() => null), diff --git a/packages/misskey-mahjong/src/engine.player.ts b/packages/misskey-mahjong/src/engine.player.ts index f1c9a6cb3a..3d2881048f 100644 --- a/packages/misskey-mahjong/src/engine.player.ts +++ b/packages/misskey-mahjong/src/engine.player.ts @@ -12,6 +12,10 @@ export type PlayerState = { user2House: House; user3House: House; user4House: House; + + round: 'e' | 's' | 'w' | 'n'; + kyoku: number; + tilesCount: number; /** @@ -130,6 +134,16 @@ export class PlayerGameEngine { } } + public commit_kakan(house: House, tile: Tile) { + console.log('commit_kakan', this.state.turn, house, tile); + if (this.state.turn !== house) throw new PlayerGameEngine.InvalidOperationError(); + } + + public commit_hora(house: House) { + console.log('commit_hora', this.state.turn, house); + if (this.state.turn !== house) throw new PlayerGameEngine.InvalidOperationError(); + } + /** * ロンします * @param source 牌を捨てた人