Skip to content

Commit

Permalink
🐛 fix: fix empty plays limitation
Browse files Browse the repository at this point in the history
  • Loading branch information
omidnikrah committed Jan 1, 2025
1 parent c4cd3de commit c82ab77
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 86 deletions.
5 changes: 4 additions & 1 deletion apps/backend/src/modules/game/dto/player-fill-hand.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { GameState, HandPosition, Player } from '@gol-ya-pooch/shared';
import { IsString } from 'class-validator';
import { IsArray, IsString } from 'class-validator';

export class PlayerFillHandDTO {
@IsString()
Expand All @@ -13,4 +13,7 @@ export class PlayerFillHandDTO {

@IsString()
direction: HandPosition;

@IsArray()
filledHands: Player['id'][];
}
30 changes: 17 additions & 13 deletions apps/backend/src/modules/game/game.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,16 +228,26 @@ export class GameGateway
@SubscribeMessage(Events.REQUEST_EMPTY_PLAY)
async handleRequestEmptyPlay(@MessageBody() data: RequestEmptyPlayDTO) {
const { gameId, playerId } = data;
this.server.to(gameId).emit(Events.REQUEST_EMPTY_PLAY, playerId);

const canEmptyPlay = await this.gameService.validateEmptyPlay(gameId);

if (canEmptyPlay) {
this.server.to(gameId).emit(Events.REQUEST_EMPTY_PLAY, playerId);
} else {
this.server.to(gameId).emit(Events.REACH_EMPTY_PLAYS_LIMIT, {
message: 'خالی بازی‌هاتون تموم شده.',
});
}
}

@SubscribeMessage(Events.PLAYER_FILL_HAND)
async handlePlayerFillHand(@MessageBody() data: PlayerFillHandDTO) {
const { gameId, fromPlayerId, toPlayerId, direction } = data;
const { gameId, fromPlayerId, toPlayerId, direction, filledHands } = data;
this.server.to(gameId).emit(Events.PLAYER_FILL_HAND, {
fromPlayerId,
toPlayerId,
direction,
filledHands,
});
}

Expand All @@ -248,7 +258,7 @@ export class GameGateway
) {
const { gameId, playerId, hand } = data;

const { canEmptyPlay, hasObjectInHand, objectLocation } =
const { hasObjectInHand, objectLocation } =
await this.gameService.emptyPlayerHand(gameId, playerId, hand);

if (hasObjectInHand) {
Expand All @@ -264,15 +274,9 @@ export class GameGateway
return;
}

if (canEmptyPlay) {
this.server.to(gameId).emit(Events.PLAYER_EMPTY_HAND, {
playerId,
hand,
});
} else {
this.server.to(gameId).emit(Events.REACH_EMPTY_HANDS_LIMIT, {
message: 'خالی بازی‌هاتون تموم شده.',
});
}
this.server.to(gameId).emit(Events.PLAYER_EMPTY_HAND, {
playerId,
hand,
});
}
}
35 changes: 17 additions & 18 deletions apps/backend/src/modules/game/game.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,42 +269,24 @@ export class GameService {
playerId: Player['id'],
hand: HandPosition | 'both',
): Promise<{
canEmptyPlay: boolean;
hasObjectInHand: boolean;
objectLocation: IObjectLocation;
}> {
const gameState = await this.getGameState(gameId);

if (gameState.emptyPlays <= 0) {
return {
objectLocation: null,
canEmptyPlay: false,
hasObjectInHand: false,
};
}

const hasObjectInHand =
gameState.objectLocation.playerId === playerId &&
(hand === 'both' || gameState.objectLocation.hand === hand);

if (hasObjectInHand) {
return {
objectLocation: gameState.objectLocation,
canEmptyPlay: false,
hasObjectInHand: true,
};
}

gameState.emptyPlays--;

await this.redisClient.set(
`game:${gameState.gameId}`,
JSON.stringify(gameState),
);

return {
objectLocation: null,
canEmptyPlay: true,
hasObjectInHand: false,
};
}
Expand Down Expand Up @@ -369,6 +351,23 @@ export class GameService {
};
}

async validateEmptyPlay(gameId: GameState['gameId']): Promise<boolean> {
const gameState = await this.getGameState(gameId);

console.log(gameState.emptyPlays);

if (gameState.emptyPlays === 0) return false;

gameState.emptyPlays--;

await this.redisClient.set(
`game:${gameState.gameId}`,
JSON.stringify(gameState),
);

return true;
}

async getRoomInfo(gameId: GameState['gameId']): Promise<PublicGameState> {
const gameState = await this.getGameState(gameId);

Expand Down
1 change: 1 addition & 0 deletions apps/frontend/src/enums/Toasts.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export enum Toasts {
REQUESTED_EMPTY_PLAY = 'REQUESTED_EMPTY_PLAY',
SPREAD_OBJECT = 'SPREAD_OBJECT',
}
15 changes: 11 additions & 4 deletions apps/frontend/src/hooks/useGameControls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ export const useGameControls = () => {
const playerSiblingsInfo = isItemInArray(teamMembers!, 'id', player.id);
let toPlayerId = '';

dismissToastByName(Toasts.SPREAD_OBJECT);

switch (hand) {
case 'left':
if (playerSiblingsInfo.hasLeft) {
Expand Down Expand Up @@ -87,6 +89,7 @@ export const useGameControls = () => {
fromPlayerId: player?.id,
toPlayerId,
direction: hand,
filledHands: filledHands.current,
});
} else {
showToast('دست این بازیکن رو پر کردی');
Expand All @@ -95,7 +98,10 @@ export const useGameControls = () => {
};

const handleEmitPlaying = (hand: HandPosition) => {
if (requestedPlayerIdToEmptyPlay === player?.id) {
if (
requestedPlayerIdToEmptyPlay === player?.id &&
phase === GamePhases.PLAYING
) {
playEmptyPlayingSound();
setIsPlaying(true);

Expand Down Expand Up @@ -215,15 +221,15 @@ export const useGameControls = () => {
},
);

on(Events.REACH_EMPTY_HANDS_LIMIT, (data: { message: string }) => {
on(Events.REACH_EMPTY_PLAYS_LIMIT, (data: { message: string }) => {
showToast(data.message, 3000);
});

return () => {
off(Events.GAME_STATE_UPDATED);
off(Events.PLAYER_RECEIVE_OBJECT);
off(Events.GUESS_LOCATION_RESULT);
off(Events.REACH_EMPTY_HANDS_LIMIT);
off(Events.REACH_EMPTY_PLAYS_LIMIT);
};
}, []);

Expand All @@ -232,13 +238,14 @@ export const useGameControls = () => {
phase === GamePhases.SPREADING_OBJECT &&
player?.id === gameState?.gameMaster
) {
showToast('اوستا گل رو پخش کن');
showToast('اوستا گل رو پخش کن', 5000, true, Toasts.SPREAD_OBJECT);
}
}, [phase, player, gameState]);

useEffect(() => {
on(Events.PLAYER_FILL_HAND, (data: PlayerFillHand) => {
setHandFillingData(data);
filledHands.current = data.filledHands;
setTimeout(() => {
setHandFillingData(null);

Expand Down
100 changes: 51 additions & 49 deletions apps/frontend/src/pages/GameRoom/components/Player/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -225,69 +225,71 @@ export const Player = ({ team, data, isJoined, position }: IPlayer) => {
)}
/>
)}
{gameState?.currentTurn === team && position !== 'bottom' && (
<>
<div className="z-10 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center flex-col w-[310px] absolute siblings-container pointer-events-none">
{gameState.gameSize > 2 && (
<div className="z-10 absolute top-0 flex shrink-0 opacity-0 group-hover:opacity-100 transition-opacity -translate-y-12 gap-1 siblings-container">
{gameState?.currentTurn === team &&
position !== 'bottom' &&
phase === GamePhases.PLAYING && (
<>
<div className="z-10 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center flex-col w-[310px] absolute siblings-container pointer-events-none">
{gameState.gameSize > 2 && (
<div className="z-10 absolute top-0 flex shrink-0 opacity-0 group-hover:opacity-100 transition-opacity -translate-y-12 gap-1 siblings-container">
<button
type="button"
className="relative flex items-center justify-center appearance-none border-none border-0 hover:scale-110 transition-all hover:!opacity-100 sibling-item cursor-pointer pointer-events-auto"
onClick={() => handleEmptyHand('left')}
>
<img src="/images/btn-shape-right.svg" alt="" />
<span className="absolute -mt-1.5 text-white font-bold text-sm">
چپت پوچ
</span>
</button>
<button
type="button"
className="relative flex items-center justify-center appearance-none border-none border-0 hover:scale-110 transition-all hover:!opacity-100 sibling-item cursor-pointer pointer-events-auto"
onClick={() => handleEmptyHand('both')}
>
<img src="/images/btn-shape-center.svg" alt="" />
<span className="absolute -mt-1.5 text-white font-bold text-sm">
جفت پوچ
</span>
</button>
<button
type="button"
className="relative flex items-center justify-center appearance-none border-none border-0 hover:scale-110 transition-all hover:!opacity-100 sibling-item cursor-pointer pointer-events-auto"
onClick={() => handleEmptyHand('right')}
>
<img src="/images/btn-shape-left.svg" alt="" />
<span className="absolute -mt-1.5 text-white font-bold text-sm">
راستت پوچ
</span>
</button>
</div>
)}
<div className="w-full flex justify-between pointer-events-none">
<button
type="button"
className="relative flex items-center justify-center appearance-none border-none border-0 hover:scale-110 transition-all hover:!opacity-100 sibling-item cursor-pointer pointer-events-auto"
onClick={() => handleEmptyHand('left')}
className="rounded-full appearance-none border-none border-0 hover:scale-110 transition-all hover:!opacity-100 sibling-item pointer-events-auto"
onClick={() => handleGuessObject('left')}
>
<img src="/images/btn-shape-right.svg" alt="" />
<span className="absolute -mt-1.5 text-white font-bold text-sm">
چپت پوچ
</span>
<img src="/images/left-gol-btn.svg" alt="" />
</button>
<button
type="button"
className="relative flex items-center justify-center appearance-none border-none border-0 hover:scale-110 transition-all hover:!opacity-100 sibling-item cursor-pointer pointer-events-auto"
onClick={() => handleEmptyHand('both')}
className="rounded-full appearance-none border-none border-0 hover:scale-110 transition-all hover:!opacity-100 sibling-item pointer-events-auto"
onClick={() => handleGuessObject('right')}
>
<img src="/images/btn-shape-center.svg" alt="" />
<span className="absolute -mt-1.5 text-white font-bold text-sm">
جفت پوچ
</span>
</button>
<button
type="button"
className="relative flex items-center justify-center appearance-none border-none border-0 hover:scale-110 transition-all hover:!opacity-100 sibling-item cursor-pointer pointer-events-auto"
onClick={() => handleEmptyHand('right')}
>
<img src="/images/btn-shape-left.svg" alt="" />
<span className="absolute -mt-1.5 text-white font-bold text-sm">
راستت پوچ
</span>
<img src="/images/right-gol-btn.svg" alt="" />
</button>
</div>
)}
<div className="w-full flex justify-between pointer-events-none">
<button
type="button"
className="rounded-full appearance-none border-none border-0 hover:scale-110 transition-all hover:!opacity-100 sibling-item pointer-events-auto"
onClick={() => handleGuessObject('left')}
className="rounded-full appearance-none border-none border-0 translate-y-[-29px] hover:scale-110 transition-all hover:!opacity-100 sibling-item pointer-events-auto"
onClick={handleRequestEmptyPlay}
>
<img src="/images/left-gol-btn.svg" alt="" />
</button>
<button
type="button"
className="rounded-full appearance-none border-none border-0 hover:scale-110 transition-all hover:!opacity-100 sibling-item pointer-events-auto"
onClick={() => handleGuessObject('right')}
>
<img src="/images/right-gol-btn.svg" alt="" />
<img src="/images/empty-play-btn.svg" alt="" />
</button>
</div>
<button
type="button"
className="rounded-full appearance-none border-none border-0 translate-y-[-29px] hover:scale-110 transition-all hover:!opacity-100 sibling-item pointer-events-auto"
onClick={handleRequestEmptyPlay}
>
<img src="/images/empty-play-btn.svg" alt="" />
</button>
</div>
</>
)}
</>
)}
</div>
);
};
2 changes: 1 addition & 1 deletion libs/shared/src/constants/events.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const Events = {
REQUEST_EMPTY_HAND: 'game:opponent:requestEmptyHand',
REQUEST_EMPTY_PLAY: 'game:opponent:requestEmptyPlay',

REACH_EMPTY_HANDS_LIMIT: 'game:team:reachEmptyHandsLimit',
REACH_EMPTY_PLAYS_LIMIT: 'game:team:reachEmptyPlaysLimit',

PLAYER_JOINED: 'game:player:joined',
PLAYER_LEFT: 'game:player:left',
Expand Down
1 change: 1 addition & 0 deletions libs/shared/src/interfaces/game.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,5 @@ export interface PlayerFillHand {
fromPlayerId: Player['id'];
toPlayerId: Player['id'];
direction: HandPosition;
filledHands: Player['id'][];
}

0 comments on commit c82ab77

Please sign in to comment.