diff --git a/locales/index.d.ts b/locales/index.d.ts index ed9e9f9bb9..8a87c1f8f9 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -9661,6 +9661,32 @@ export interface Locale extends ILocale { * 飜 */ "fan": string; + "_fanNames": { + /** + * 満貫 + */ + "mangan": string; + /** + * 跳満 + */ + "haneman": string; + /** + * 倍満 + */ + "baiman": string; + /** + * 三倍満 + */ + "sanbaiman": string; + /** + * 役満 + */ + "yakuman": string; + /** + * 数え役満 + */ + "kazoeyakuman": string; + }; "_yakus": { /** * 立直 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 87e7c7566c..ab493d190f 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2574,6 +2574,13 @@ _mahjong: dora: "ドラ" redDora: "赤ドラ" fan: "飜" + _fanNames: + mangan: "満貫" + haneman: "跳満" + baiman: "倍満" + sanbaiman: "三倍満" + yakuman: "役満" + kazoeyakuman: "数え役満" _yakus: "riichi": "立直" "ippatsu": "一発" diff --git a/packages/backend/src/core/GlobalEventService.ts b/packages/backend/src/core/GlobalEventService.ts index 243e13e6c5..3d7c3d052a 100644 --- a/packages/backend/src/core/GlobalEventService.ts +++ b/packages/backend/src/core/GlobalEventService.ts @@ -6,7 +6,7 @@ import { Inject, Injectable } from '@nestjs/common'; import * as Redis from 'ioredis'; import * as Reversi from 'misskey-reversi'; -import * as Mahjong from 'misskey-mahjong'; +import * as Mmj from 'misskey-mahjong'; import type { MiChannel } from '@/models/Channel.js'; import type { MiUser } from '@/models/User.js'; import type { MiUserProfile } from '@/models/UserProfile.js'; @@ -209,30 +209,30 @@ export interface MahjongRoomEventTypes { room: Packed<'MahjongRoomDetailed'>; }; tsumo: { - house: Mahjong.House; - tile: Mahjong.Tile; + house: Mmj.House; + tile: Mmj.Tile; }; dahai: { - house: Mahjong.House; - tile: Mahjong.Tile; + house: Mmj.House; + tile: Mmj.Tile; riichi: boolean; }; dahaiAndTsumo: { - dahaiHouse: Mahjong.House; - dahaiTile: Mahjong.Tile; - tsumoTile: Mahjong.Tile; + dahaiHouse: Mmj.House; + dahaiTile: Mmj.Tile; + tsumoTile: Mmj.Tile; riichi: boolean; }; ponned: { - caller: Mahjong.House; - callee: Mahjong.House; - tile: Mahjong.Tile; + caller: Mmj.House; + callee: Mmj.House; + tile: Mmj.Tile; }; kanned: { - caller: Mahjong.House; - callee: Mahjong.House; - tile: Mahjong.Tile; - rinsyan: Mahjong.Tile; + caller: Mmj.House; + callee: Mmj.House; + tile: Mmj.Tile; + rinsyan: Mmj.Tile; }; ronned: { }; diff --git a/packages/backend/src/core/MahjongService.ts b/packages/backend/src/core/MahjongService.ts index f72e4731d6..498563ac6b 100644 --- a/packages/backend/src/core/MahjongService.ts +++ b/packages/backend/src/core/MahjongService.ts @@ -7,7 +7,7 @@ import { Inject, Injectable } from '@nestjs/common'; import * as Redis from 'ioredis'; import { ModuleRef } from '@nestjs/core'; import { IsNull, LessThan, MoreThan } from 'typeorm'; -import * as Mahjong from 'misskey-mahjong'; +import * as Mmj from 'misskey-mahjong'; import type { MiMahjongGame, MahjongGamesRepository, @@ -55,7 +55,7 @@ type Room = { isStarted?: boolean; timeLimitForEachTurn: number; - gameState?: Mahjong.MasterState; + gameState?: Mmj.MasterState; }; type CallingAnswers = { @@ -77,12 +77,12 @@ type NextKyokuConfirmation = { user4: boolean; }; -function getUserIdOfHouse(room: Room, engine: Mahjong.MasterGameEngine, house: Mahjong.House): MiUser['id'] { - return engine.state.user1House === house ? room.user1Id : engine.state.user2House === house ? room.user2Id : engine.state.user3House === house ? room.user3Id : room.user4Id; +function getUserIdOfHouse(room: Room, mj: Mmj.MasterGameEngine, house: Mmj.House): MiUser['id'] { + return mj.user1House === house ? room.user1Id : mj.user2House === house ? room.user2Id : mj.user3House === house ? room.user3Id : room.user4Id; } -function getHouseOfUserId(room: Room, engine: Mahjong.MasterGameEngine, userId: MiUser['id']): Mahjong.House { - return userId === room.user1Id ? engine.state.user1House : userId === room.user2Id ? engine.state.user2House : userId === room.user3Id ? engine.state.user3House : engine.state.user4House; +function getHouseOfUserId(room: Room, mj: Mmj.MasterGameEngine, userId: MiUser['id']): Mmj.House { + return userId === room.user1Id ? mj.user1House : userId === room.user2Id ? mj.user2House : userId === room.user3Id ? mj.user3House : mj.user4House; } @Injectable() @@ -278,7 +278,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { throw new Error('Not ready'); } - room.gameState = Mahjong.MasterGameEngine.createInitialState(); + room.gameState = Mmj.MasterGameEngine.createInitialState(); room.isStarted = true; await this.saveRoom(room); @@ -291,11 +291,11 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { @bindThis public async packRoom(room: Room, me: MiUser) { if (room.gameState) { - const engine = new Mahjong.MasterGameEngine(room.gameState); + const mj = new Mmj.MasterGameEngine(room.gameState); const myIndex = room.user1Id === me.id ? 1 : room.user2Id === me.id ? 2 : room.user3Id === me.id ? 3 : 4; return { ...room, - gameState: engine.createPlayerState(myIndex), + gameState: mj.createPlayerState(myIndex), }; } else { return { @@ -305,52 +305,56 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { } @bindThis - private async answer(room: Room, engine: Mahjong.MasterGameEngine, answers: CallingAnswers) { - const res = engine.commit_resolveCallingInterruption({ + private async answer(room: Room, mj: Mmj.MasterGameEngine, answers: CallingAnswers) { + const res = mj.commit_resolveCallingInterruption({ pon: answers.pon ?? false, cii: answers.cii ?? false, kan: answers.kan ?? false, - ron: [...(answers.ron.e ? ['e'] : []), ...(answers.ron.s ? ['s'] : []), ...(answers.ron.w ? ['w'] : []), ...(answers.ron.n ? ['n'] : [])] as Mahjong.House[], + ron: [...(answers.ron.e ? ['e'] : []), ...(answers.ron.s ? ['s'] : []), ...(answers.ron.w ? ['w'] : []), ...(answers.ron.n ? ['n'] : [])] as Mmj.House[], }); - room.gameState = engine.state; + room.gameState = mj.getState(); await this.saveRoom(room); switch (res.type) { case 'tsumo': this.globalEventService.publishMahjongRoomStream(room.id, 'tsumo', { house: res.house, tile: res.tile }); - this.waitForTurn(room, res.turn, engine); + this.waitForTurn(room, res.turn, mj); break; case 'ponned': this.globalEventService.publishMahjongRoomStream(room.id, 'ponned', { caller: res.caller, callee: res.callee, tiles: res.tiles }); - this.waitForTurn(room, res.turn, engine); + this.waitForTurn(room, res.turn, mj); break; case 'kanned': this.globalEventService.publishMahjongRoomStream(room.id, 'kanned', { caller: res.caller, callee: res.callee, tiles: res.tiles, rinsyan: res.rinsyan }); - this.waitForTurn(room, res.turn, engine); + this.waitForTurn(room, res.turn, mj); + break; + case 'ciied': + this.globalEventService.publishMahjongRoomStream(room.id, 'ciied', { caller: res.caller, callee: res.callee, tiles: res.tiles }); + this.waitForTurn(room, res.turn, mj); break; case 'ronned': this.globalEventService.publishMahjongRoomStream(room.id, 'ronned', { callers: res.callers, callee: res.callee, handTiles: { - e: engine.state.handTiles.e, - s: engine.state.handTiles.s, - w: engine.state.handTiles.w, - n: engine.state.handTiles.n, + e: mj.handTiles.e, + s: mj.handTiles.s, + w: mj.handTiles.w, + n: mj.handTiles.n, }, }); - this.endKyoku(room, engine); + this.endKyoku(room, mj); break; case 'ryukyoku': this.globalEventService.publishMahjongRoomStream(room.id, 'ryukyoku', { }); - this.endKyoku(room, engine); + this.endKyoku(room, mj); break; } } @bindThis - private async endKyoku(room: Room, engine: Mahjong.MasterGameEngine) { + private async endKyoku(room: Room, mj: Mmj.MasterGameEngine) { const confirmation: NextKyokuConfirmation = { user1: false, user2: false, @@ -370,18 +374,18 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { if (allConfirmed || (Date.now() - waitingStartedAt > NEXT_KYOKU_CONFIRMATION_TIMEOUT_MS)) { await this.redisClient.del(`mahjong:gameNextKyokuConfirmation:${room.id}`); clearInterval(interval); - this.nextKyoku(room, engine); + this.nextKyoku(room, mj); } }, 2000); } @bindThis - private async dahai(room: Room, engine: Mahjong.MasterGameEngine, house: Mahjong.House, tile: Mahjong.TileId, riichi = false) { - const res = engine.commit_dahai(house, tile, riichi); - room.gameState = engine.state; + private async dahai(room: Room, mj: Mmj.MasterGameEngine, house: Mmj.House, tile: Mmj.TileId, riichi = false) { + const res = mj.commit_dahai(house, tile, riichi); + room.gameState = mj.getState(); await this.saveRoom(room); - const aiHouses = [[1, room.user1Ai], [2, room.user2Ai], [3, room.user3Ai], [4, room.user4Ai]].filter(([id, ai]) => ai).map(([id, ai]) => engine.getHouse(id)); + const aiHouses = [[1, room.user1Ai], [2, room.user2Ai], [3, room.user3Ai], [4, room.user4Ai]].filter(([id, ai]) => ai).map(([id, ai]) => mj.getHouse(id)); if (res.asking) { const answers: CallingAnswers = { @@ -397,13 +401,13 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { }; // リーチ中はポン、チー、カンできない - if (res.canPonHouse != null && engine.state.riichis[res.canPonHouse]) { + if (res.canPonHouse != null && mj.riichis[res.canPonHouse]) { answers.pon = false; } - if (res.canCiiHouse != null && engine.state.riichis[res.canCiiHouse]) { + if (res.canCiiHouse != null && mj.riichis[res.canCiiHouse]) { answers.cii = false; } - if (res.canKanHouse != null && engine.state.riichis[res.canKanHouse]) { + if (res.canKanHouse != null && mj.riichis[res.canKanHouse]) { answers.kan = false; } @@ -445,7 +449,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { console.log(allAnswered ? 'ask all answerd' : 'ask timeout'); await this.redisClient.del(`mahjong:gameCallingAsking:${room.id}`); clearInterval(interval); - this.answer(room, engine, currentAnswers); + this.answer(room, mj, currentAnswers); return; } }, 1000); @@ -454,7 +458,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { } else { this.globalEventService.publishMahjongRoomStream(room.id, 'dahaiAndTsumo', { dahaiHouse: house, dahaiTile: tile, tsumoTile: res.tsumoTile, riichi }); - this.waitForTurn(room, res.next, engine); + this.waitForTurn(room, res.next, mj); } } @@ -476,52 +480,52 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { } @bindThis - public async commit_dahai(roomId: MiMahjongGame['id'], user: MiUser, tile: Mahjong.TileId, riichi = false) { + public async commit_dahai(roomId: MiMahjongGame['id'], user: MiUser, tile: Mmj.TileId, riichi = false) { const room = await this.getRoom(roomId); if (room == null) return; if (room.gameState == null) return; - const engine = new Mahjong.MasterGameEngine(room.gameState); - const myHouse = getHouseOfUserId(room, engine, user.id); + const mj = new Mmj.MasterGameEngine(room.gameState); + const myHouse = getHouseOfUserId(room, mj, user.id); await this.clearTurnWaitingTimer(room.id); - await this.dahai(room, engine, myHouse, tile, riichi); + await this.dahai(room, mj, myHouse, tile, riichi); } @bindThis - public async commit_ankan(roomId: MiMahjongGame['id'], user: MiUser, tile: Mahjong.TileId) { + public async commit_ankan(roomId: MiMahjongGame['id'], user: MiUser, tile: Mmj.TileId) { const room = await this.getRoom(roomId); if (room == null) return; if (room.gameState == null) return; - const engine = new Mahjong.MasterGameEngine(room.gameState); - const myHouse = getHouseOfUserId(room, engine, user.id); + const mj = new Mmj.MasterGameEngine(room.gameState); + const myHouse = getHouseOfUserId(room, mj, user.id); await this.clearTurnWaitingTimer(room.id); - const res = engine.commit_ankan(myHouse, tile); - room.gameState = engine.state; + const res = mj.commit_ankan(myHouse, tile); + room.gameState = mj.getState(); await this.saveRoom(room); this.globalEventService.publishMahjongRoomStream(room.id, 'ankanned', { house: myHouse, tiles: res.tiles, rinsyan: res.rinsyan }); - this.waitForTurn(room, myHouse, engine); + this.waitForTurn(room, myHouse, mj); } @bindThis - public async commit_kakan(roomId: MiMahjongGame['id'], user: MiUser, tile: Mahjong.TileId) { + public async commit_kakan(roomId: MiMahjongGame['id'], user: MiUser, tile: Mmj.TileId) { const room = await this.getRoom(roomId); if (room == null) return; if (room.gameState == null) return; - const engine = new Mahjong.MasterGameEngine(room.gameState); - const myHouse = getHouseOfUserId(room, engine, user.id); + const mj = new Mmj.MasterGameEngine(room.gameState); + const myHouse = getHouseOfUserId(room, mj, user.id); await this.clearTurnWaitingTimer(room.id); - const res = engine.commit_kakan(myHouse, tile); - room.gameState = engine.state; + const res = mj.commit_kakan(myHouse, tile); + room.gameState = mj.getState(); await this.saveRoom(room); this.globalEventService.publishMahjongRoomStream(room.id, 'kakanned', { house: myHouse, tiles: res.tiles, rinsyan: res.rinsyan, from: res.from }); @@ -533,13 +537,13 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { if (room == null) return; if (room.gameState == null) return; - const engine = new Mahjong.MasterGameEngine(room.gameState); - const myHouse = getHouseOfUserId(room, engine, user.id); + const mj = new Mmj.MasterGameEngine(room.gameState); + const myHouse = getHouseOfUserId(room, mj, user.id); await this.clearTurnWaitingTimer(room.id); - const res = engine.commit_tsumoHora(myHouse); - room.gameState = engine.state; + const res = mj.commit_tsumoHora(myHouse); + room.gameState = mj.getState(); await this.saveRoom(room); this.globalEventService.publishMahjongRoomStream(room.id, 'tsumoHora', { house: myHouse, handTiles: res.handTiles, tsumoTile: res.tsumoTile }); @@ -551,8 +555,8 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { if (room == null) return; if (room.gameState == null) return; - const engine = new Mahjong.MasterGameEngine(room.gameState); - const myHouse = getHouseOfUserId(room, engine, user.id); + const mj = new Mmj.MasterGameEngine(room.gameState); + const myHouse = getHouseOfUserId(room, mj, user.id); // TODO: 自分に回答する権利がある状態かバリデーション @@ -618,17 +622,17 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { if (room == null) return; if (room.gameState == null) return; - const engine = new Mahjong.MasterGameEngine(room.gameState); - const myHouse = getHouseOfUserId(room, engine, user.id); + const mj = new Mmj.MasterGameEngine(room.gameState); + const myHouse = getHouseOfUserId(room, mj, user.id); // TODO: この辺の処理はアトミックに行いたいけどJSONサポートはRedis Stackが必要 const current = await this.redisClient.get(`mahjong:gameCallingAsking:${room.id}`); if (current == null) throw new Error('no asking found'); const currentAnswers = JSON.parse(current) as CallingAnswers; - if (engine.state.ponAsking?.caller === myHouse) currentAnswers.pon = false; - if (engine.state.ciiAsking?.caller === myHouse) currentAnswers.cii = false; - if (engine.state.kanAsking?.caller === myHouse) currentAnswers.kan = false; - if (engine.state.ronAsking != null && engine.state.ronAsking.callers.includes(myHouse)) currentAnswers.ron[myHouse] = false; + if (mj.askings.pon?.caller === myHouse) currentAnswers.pon = false; + if (mj.askings.cii?.caller === myHouse) currentAnswers.cii = false; + if (mj.askings.kan?.caller === myHouse) currentAnswers.kan = false; + if (mj.askings.ron != null && mj.askings.ron.callers.includes(myHouse)) currentAnswers.ron[myHouse] = false; await this.redisClient.set(`mahjong:gameCallingAsking:${room.id}`, JSON.stringify(currentAnswers)); } @@ -638,18 +642,18 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { * NOTE: 時間切れチェックが行われたときにタイミングによっては次のwaitingが始まっている場合があることを考慮し、Setに一意のIDを格納する構造としている * @param room * @param house - * @param engine + * @param mj */ @bindThis - private async waitForTurn(room: Room, house: Mahjong.House, engine: Mahjong.MasterGameEngine) { - const aiHouses = [[1, room.user1Ai], [2, room.user2Ai], [3, room.user3Ai], [4, room.user4Ai]].filter(([id, ai]) => ai).map(([id, ai]) => engine.getHouse(id)); + private async waitForTurn(room: Room, house: Mmj.House, mj: Mmj.MasterGameEngine) { + const aiHouses = [[1, room.user1Ai], [2, room.user2Ai], [3, room.user3Ai], [4, room.user4Ai]].filter(([id, ai]) => ai).map(([id, ai]) => mj.getHouse(id)); - if (engine.state.riichis[house]) { + if (mj.riichis[house]) { // リーチ時はアガリ牌でない限りツモ切り - const horaSets = Mahjong.getHoraSets(engine.handTileTypes[house]); + const horaSets = Mmj.getHoraSets(mj.handTileTypes[house]); if (horaSets.length === 0) { setTimeout(() => { - this.dahai(room, engine, house, engine.state.handTiles[house].at(-1)); + this.dahai(room, mj, house, mj.handTiles[house].at(-1)); }, 500); return; } @@ -657,7 +661,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { if (aiHouses.includes(house)) { setTimeout(() => { - this.dahai(room, engine, house, engine.state.handTiles[house].at(-1)); + this.dahai(room, mj, house, mj.handTiles[house].at(-1)); }, 500); return; } @@ -676,8 +680,8 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { await this.redisClient.srem(`mahjong:gameTurnWaiting:${room.id}`, id); console.log('turn timeout', house, id); clearInterval(interval); - const handTiles = engine.state.handTiles[house]; - await this.dahai(room, engine, house, handTiles.at(-1)); + const handTiles = mj.handTiles[house]; + await this.dahai(room, mj, house, handTiles.at(-1)); return; } }, 2000); diff --git a/packages/frontend/assets/mahjong/logo.png b/packages/frontend/assets/mahjong/logo.png index bacdd21e81..6ebbdbb548 100644 Binary files a/packages/frontend/assets/mahjong/logo.png and b/packages/frontend/assets/mahjong/logo.png differ diff --git a/packages/frontend/assets/mahjong/tile-front.png b/packages/frontend/assets/mahjong/tile-front.png deleted file mode 100644 index e6bc7038e1..0000000000 Binary files a/packages/frontend/assets/mahjong/tile-front.png and /dev/null differ diff --git a/packages/frontend/src/pages/mahjong/hand-tiles.vue b/packages/frontend/src/pages/mahjong/hand-tiles.vue new file mode 100644 index 0000000000..ebfb6e8cc1 --- /dev/null +++ b/packages/frontend/src/pages/mahjong/hand-tiles.vue @@ -0,0 +1,184 @@ + + + + + + + diff --git a/packages/frontend/src/pages/mahjong/huro.vue b/packages/frontend/src/pages/mahjong/huro.vue index 1c6da57efb..4988c5aaef 100644 --- a/packages/frontend/src/pages/mahjong/huro.vue +++ b/packages/frontend/src/pages/mahjong/huro.vue @@ -5,38 +5,38 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/mahjong/room.game.vue b/packages/frontend/src/pages/mahjong/room.game.vue index c1f344831a..8b8883756d 100644 --- a/packages/frontend/src/pages/mahjong/room.game.vue +++ b/packages/frontend/src/pages/mahjong/room.game.vue @@ -10,118 +10,100 @@ SPDX-License-Identifier: AGPL-3.0-only
- {{ Mahjong.prevHouse(Mahjong.prevHouse(engine.myHouse)) === 'e' ? i18n.ts._mahjong.east : Mahjong.prevHouse(Mahjong.prevHouse(engine.myHouse)) === 's' ? i18n.ts._mahjong.south : Mahjong.prevHouse(Mahjong.prevHouse(engine.myHouse)) === 'w' ? i18n.ts._mahjong.west : i18n.ts._mahjong.north }} - {{ engine.state.points[Mahjong.prevHouse(Mahjong.prevHouse(engine.myHouse))] }} + {{ Mmj.prevHouse(Mmj.prevHouse(mj.myHouse)) === 'e' ? i18n.ts._mahjong.east : Mmj.prevHouse(Mmj.prevHouse(mj.myHouse)) === 's' ? i18n.ts._mahjong.south : Mmj.prevHouse(Mmj.prevHouse(mj.myHouse)) === 'w' ? i18n.ts._mahjong.west : i18n.ts._mahjong.north }} + {{ mj.points[Mmj.prevHouse(Mmj.prevHouse(mj.myHouse))] }}
- {{ Mahjong.prevHouse(engine.myHouse) === 'e' ? i18n.ts._mahjong.east : Mahjong.prevHouse(engine.myHouse) === 's' ? i18n.ts._mahjong.south : Mahjong.prevHouse(engine.myHouse) === 'w' ? i18n.ts._mahjong.west : i18n.ts._mahjong.north }} - {{ engine.state.points[Mahjong.prevHouse(engine.myHouse)] }} + {{ Mmj.prevHouse(mj.myHouse) === 'e' ? i18n.ts._mahjong.east : Mmj.prevHouse(mj.myHouse) === 's' ? i18n.ts._mahjong.south : Mmj.prevHouse(mj.myHouse) === 'w' ? i18n.ts._mahjong.west : i18n.ts._mahjong.north }} + {{ mj.points[Mmj.prevHouse(mj.myHouse)] }}
- {{ Mahjong.nextHouse(engine.myHouse) === 'e' ? i18n.ts._mahjong.east : Mahjong.nextHouse(engine.myHouse) === 's' ? i18n.ts._mahjong.south : Mahjong.nextHouse(engine.myHouse) === 'w' ? i18n.ts._mahjong.west : i18n.ts._mahjong.north }} - {{ engine.state.points[Mahjong.nextHouse(engine.myHouse)] }} + {{ Mmj.nextHouse(mj.myHouse) === 'e' ? i18n.ts._mahjong.east : Mmj.nextHouse(mj.myHouse) === 's' ? i18n.ts._mahjong.south : Mmj.nextHouse(mj.myHouse) === 'w' ? i18n.ts._mahjong.west : i18n.ts._mahjong.north }} + {{ mj.points[Mmj.nextHouse(mj.myHouse)] }}
- {{ engine.myHouse === 'e' ? i18n.ts._mahjong.east : engine.myHouse === 's' ? i18n.ts._mahjong.south : engine.myHouse === 'w' ? i18n.ts._mahjong.west : i18n.ts._mahjong.north }} - {{ engine.state.points[engine.myHouse] }} + {{ mj.myHouse === 'e' ? i18n.ts._mahjong.east : mj.myHouse === 's' ? i18n.ts._mahjong.south : mj.myHouse === 'w' ? i18n.ts._mahjong.west : i18n.ts._mahjong.north }} + {{ mj.points[mj.myHouse] }}
-
{{ engine.state.tilesCount }}
+
{{ mj.tilesCount }}
-
+
-
+
-
+
- +
- +
- +
- +
-
- +
+
-
- +
+
-
- +
+
-
- +
+
-
-
- - -
-
- - -
-
+
@@ -131,12 +113,12 @@ SPDX-License-Identifier: AGPL-3.0-only :enterFromClass="$style.transition_serif_enterFrom" :leaveToClass="$style.transition_serif_leaveTo" > - - - - - - + + + + + +
@@ -146,12 +128,12 @@ SPDX-License-Identifier: AGPL-3.0-only :enterFromClass="$style.transition_serif_enterFrom" :leaveToClass="$style.transition_serif_leaveTo" > - - - - - - + + + + + +
@@ -161,12 +143,12 @@ SPDX-License-Identifier: AGPL-3.0-only :enterFromClass="$style.transition_serif_enterFrom" :leaveToClass="$style.transition_serif_leaveTo" > - - - - - - + + + + + +
@@ -176,26 +158,26 @@ SPDX-License-Identifier: AGPL-3.0-only :enterFromClass="$style.transition_serif_enterFrom" :leaveToClass="$style.transition_serif_leaveTo" > - - - - - - + + + + + +
- Ron - Pon - Cii - Kan - Skip - Ankan - Kakan + Ron + Pon + Cii + Kan + Skip + Ankan + Kakan Tsumo - Riichi + Riichi
@@ -224,9 +206,10 @@ SPDX-License-Identifier: AGPL-3.0-only