This commit is contained in:
syuilo 2024-01-29 14:14:00 +09:00
parent 11404e545e
commit 668bf9a226
6 changed files with 114 additions and 11 deletions

View File

@ -226,6 +226,8 @@ export interface MahjongRoomEventTypes {
target: Mahjong.Common.House; target: Mahjong.Common.House;
tile: Mahjong.Common.Tile; tile: Mahjong.Common.Tile;
}; };
endKyoku: {
};
} }
//#endregion //#endregion

View File

@ -300,7 +300,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit {
this.waitForTurn(room, userId, engine); this.waitForTurn(room, userId, engine);
} else if (res.type === 'kanned') { } else if (res.type === 'kanned') {
// TODO // TODO
} else if (res.type === 'ronned') { } else if (res.type === 'endKyoku') {
// TODO // TODO
} }
} }
@ -415,7 +415,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit {
this.answer(room, engine, currentAnswers); this.answer(room, engine, currentAnswers);
return; return;
} }
}, 2000); }, 1000);
this.globalEventService.publishMahjongRoomStream(room.id, 'dahai', { house: house, tile }); this.globalEventService.publishMahjongRoomStream(room.id, 'dahai', { house: house, tile });
} else { } else {
@ -445,6 +445,38 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit {
await this.dahai(room, engine, myHouse, tile); 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 @bindThis
public async commit_ron(roomId: MiMahjongGame['id'], user: MiUser) { public async commit_ron(roomId: MiMahjongGame['id'], user: MiUser) {
const room = await this.getRoom(roomId); const room = await this.getRoom(roomId);
@ -504,7 +536,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit {
} }
/** /**
* () * ()
* *
* NOTE: 時間切れチェックが行われたときにタイミングによっては次のwaitingが始まっている場合があることを考慮しSetに一意のIDを格納する構造としている * NOTE: 時間切れチェックが行われたときにタイミングによっては次のwaitingが始まっている場合があることを考慮しSetに一意のIDを格納する構造としている
* @param room * @param room
@ -536,7 +568,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit {
} }
/** /**
* * ()
* @param roomId * @param roomId
*/ */
@bindThis @bindThis

View File

@ -39,6 +39,7 @@ class MahjongRoomChannel extends Channel {
case 'updateSettings': this.updateSettings(body.key, body.value); break; case 'updateSettings': this.updateSettings(body.key, body.value); break;
case 'addAi': this.addAi(); break; case 'addAi': this.addAi(); break;
case 'dahai': this.dahai(body.tile, body.riichi); break; case 'dahai': this.dahai(body.tile, body.riichi); break;
case 'hora': this.hora(); break;
case 'ron': this.ron(); break; case 'ron': this.ron(); break;
case 'pon': this.pon(); break; case 'pon': this.pon(); break;
case 'nop': this.nop(); break; case 'nop': this.nop(); break;
@ -74,6 +75,13 @@ class MahjongRoomChannel extends Channel {
this.mahjongService.commit_dahai(this.roomId!, this.user, tile, riichi); 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 @bindThis
private async ron() { private async ron() {
if (this.user == null) return; if (this.user == null) return;

View File

@ -79,7 +79,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton v-if="engine.state.canRonSource != null" primary gradate @click="ron">Ron</MkButton> <MkButton v-if="engine.state.canRonSource != null" primary gradate @click="ron">Ron</MkButton>
<MkButton v-if="engine.state.canPonSource != null" primary @click="pon">Pon</MkButton> <MkButton v-if="engine.state.canPonSource != null" primary @click="pon">Pon</MkButton>
<MkButton v-if="engine.state.canRonSource != null || engine.state.canPonSource != null" @click="skip">Skip</MkButton> <MkButton v-if="engine.state.canRonSource != null || engine.state.canPonSource != null" @click="skip">Skip</MkButton>
<MkButton v-if="isMyTurn && canHora" primary gradate>Tsumo</MkButton> <MkButton v-if="isMyTurn && canHora" primary gradate @click="hora">Tsumo</MkButton>
<MkButton v-if="isMyTurn && canRiichi" primary @click="riichi">Riichi</MkButton> <MkButton v-if="isMyTurn && canRiichi" primary @click="riichi">Riichi</MkButton>
</div> </div>
</template> </template>
@ -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() { function ron() {
engine.value.commit_ron(engine.value.state.canRonSource, engine.value.myHouse); engine.value.commit_ron(engine.value.state.canRonSource, engine.value.myHouse);
triggerRef(engine); triggerRef(engine);
@ -236,9 +256,6 @@ function ron() {
} }
function pon() { function pon() {
engine.value.commit_pon(engine.value.state.canPonSource, engine.value.myHouse);
triggerRef(engine);
props.connection!.send('pon', { props.connection!.send('pon', {
}); });
} }
@ -336,8 +353,6 @@ function onStreamPonned(log) {
// return; // return;
//} //}
if (log.target === engine.value.myHouse) return;
engine.value.commit_pon(log.source, log.target); engine.value.commit_pon(log.source, log.target);
triggerRef(engine); triggerRef(engine);

View File

@ -13,6 +13,10 @@ export type MasterState = {
user2House: House; user2House: House;
user3House: House; user3House: House;
user4House: House; user4House: House;
round: 'e' | 's' | 'w' | 'n';
kyoku: number;
tiles: Tile[]; tiles: Tile[];
/** /**
@ -122,6 +126,8 @@ export class MasterGameEngine {
user2House: 's', user2House: 's',
user3House: 'w', user3House: 'w',
user4House: 'n', user4House: 'n',
round: 'e',
kyoku: 1,
tiles, tiles,
handTiles: { handTiles: {
e: eHandTiles, 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) { public commit_dahai(house: House, tile: Tile, riichi = false) {
if (this.state.turn !== house) throw new Error('Not your turn'); 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: { public commit_resolveCallAndRonInterruption(answers: {
pon: boolean; pon: boolean;
cii: boolean; cii: boolean;
@ -328,7 +355,10 @@ export class MasterGameEngine {
if (this.state.ronAsking != null && answers.ron.length > 0) { if (this.state.ronAsking != null && answers.ron.length > 0) {
// TODO // TODO
return; this.endKyoku();
return {
type: 'endKyoku',
};
} }
if (this.state.kanAsking != null && answers.kan) { if (this.state.kanAsking != null && answers.kan) {
@ -401,6 +431,8 @@ export class MasterGameEngine {
user2House: this.state.user2House, user2House: this.state.user2House,
user3House: this.state.user3House, user3House: this.state.user3House,
user4House: this.state.user4House, user4House: this.state.user4House,
round: this.state.round,
kyoku: this.state.kyoku,
tilesCount: this.state.tiles.length, tilesCount: this.state.tiles.length,
handTiles: { handTiles: {
e: house === 'e' ? this.state.handTiles.e : this.state.handTiles.e.map(() => null), e: house === 'e' ? this.state.handTiles.e : this.state.handTiles.e.map(() => null),

View File

@ -12,6 +12,10 @@ export type PlayerState = {
user2House: House; user2House: House;
user3House: House; user3House: House;
user4House: House; user4House: House;
round: 'e' | 's' | 'w' | 'n';
kyoku: number;
tilesCount: 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 * @param source