Skip to content

Commit

Permalink
add other battle watch
Browse files Browse the repository at this point in the history
  • Loading branch information
vraja-nayaka committed Oct 17, 2024
1 parent bf8d7c7 commit 5928e40
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
.max {
color: #00ffc4;
margin-left: 8px;
font-weight: 500;
font-size: 12px;
}

.arrowLeft {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,11 @@ export const CharacterStatsForm = ({ onValuesChange }: CharacterStatsFormProps)
disabled={values[name] >= maxCount || availablePoints === 0}
/>

<Text size="xs" weight="medium" className={styles.max}>
{maxCount} max
</Text>
<Button color="transparent" className={styles.max}>
<Text size="xs" weight="medium">
{maxCount} max
</Text>
</Button>
</div>
<Text size="xs" className={styles.description}>
{description}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,19 @@ type GameOverCardProps = {
state: State;
participantsMap: Record<string, Player>;
isAlive: boolean;
isShowOtherBattle: boolean;
className?: string;
};

const GameOverCard = ({ bid, className, state, totalParticipants, participantsMap, isAlive }: GameOverCardProps) => {
const GameOverCard = ({
bid,
className,
state,
totalParticipants,
participantsMap,
isAlive,
isShowOtherBattle,
}: GameOverCardProps) => {
const { account } = useAccount();
const { getFormattedBalanceValue } = useBalanceFormat();
const isTournamentOver = 'gameIsOver' in state;
Expand All @@ -25,7 +34,7 @@ const GameOverCard = ({ bid, className, state, totalParticipants, participantsMa
const getMyResultStatus = () => {
if (!account) return null;
if (isDraw && state.gameIsOver.winners.includes(account.decodedAddress)) return 'It’s a draw';
if (!isAlive) return 'You lose';
if (!isAlive && (!isShowOtherBattle || isTournamentOver)) return 'You lose';
if (isTournamentOver && state.gameIsOver.winners[0] === account.decodedAddress) return 'You win';
return null;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

.historyItem {
display: flex;
cursor: pointer;
}

.players {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import { useState } from 'react';
import { useAtomValue } from 'jotai';
import { useAtom, useSetAtom } from 'jotai';

import { BattleHistoryCard, BattleCard, PlayersList, List } from '@/features/game/components';
import { Segmented } from '@/components';
import { BattleState, Player } from '@/app/utils';
import { UserSkullIcon, UserSmileIcon } from '@/features/game/assets/images';
import { PlayerStatus } from '@/features/game/types';
import { battleHistoryAtom } from '@/features/game/store';
import { battleHistoryAtom, otherPairBattleWatchAtom } from '@/features/game/store';
import styles from './battle-tabs.module.scss';

type Tabs = 'players' | 'history';

type BattleTabsProps = {
battleState: BattleState;
participantsMap: Record<string, Player>;
me: Player;
player: Player | null;
opponent: Player | null;
isAlive: boolean;
};

export const BattleTabs = ({ battleState, participantsMap, me, opponent, isAlive }: BattleTabsProps) => {
export const BattleTabs = ({ battleState, participantsMap, player, opponent, isAlive }: BattleTabsProps) => {
const { participants, defeated_participants, battle_name } = battleState;
const [selectedTab, setSelectedTab] = useState<Tabs>('players');

const battleHistory = useAtomValue(battleHistoryAtom);
const [battleHistory, setBattleHistory] = useAtom(battleHistoryAtom);
const setOtherPairBattleWatch = useSetAtom(otherPairBattleWatchAtom);

const showOtherBattles = !isAlive;
const showPlayersList = selectedTab === 'players';
Expand Down Expand Up @@ -88,7 +89,28 @@ export const BattleTabs = ({ battleState, participantsMap, me, opponent, isAlive
const player2 = participantsMap[player_2];

return (
<div key={key} className={styles.historyItem}>
<div
key={key}
className={styles.historyItem}
onClick={() => {
setOtherPairBattleWatch(key);
setBattleHistory([
{
player: {
action: 'Attack',
health: player1.player_settings.health,
isDodged: false,
receivedDamage: 0,
},
opponent: {
action: 'Attack',
health: player1.player_settings.health,
isDodged: false,
receivedDamage: 0,
},
},
]);
}}>
<BattleCard
{...player1.player_settings}
name={player1.user_name}
Expand All @@ -114,10 +136,11 @@ export const BattleTabs = ({ battleState, participantsMap, me, opponent, isAlive
maxLength={6}
items={
(opponent &&
player &&
battleHistory?.map((history, index) => {
return (
<div key={index} className={styles.historyItem}>
<BattleHistoryCard {...me.player_settings} {...history.player} name={me.user_name} />
<BattleHistoryCard {...player.player_settings} {...history.player} name={player.user_name} />
<BattleHistoryCard
{...opponent.player_settings}
{...history.opponent}
Expand Down
19 changes: 11 additions & 8 deletions frontend/apps/tamagotchi-battle-new/src/features/game/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { atom, useAtom, useSetAtom } from 'jotai';
import { BattleHistory } from './types';
import { useEventRoundActionSubscription } from '@/app/utils/sails/events';
import { BattleState, Pair, Player } from '@/app/utils';
import { battleHistoryAtom, battleHistoryStorage } from './store';
import { battleHistoryAtom, battleHistoryStorage, otherPairBattleWatchAtom } from './store';
import { MAX_HEALTH, TIME_LEFT_GAP } from './consts';
import { useAccount } from '@gear-js/react-hooks';

Expand All @@ -26,16 +26,16 @@ export function useRestGameState() {

export type UsePrepareBattleHistoryParams = {
pair: Pair;
me: Player;
player: Player;
opponent: Player | null;
turnEndCallback: () => void;
};

export function usePrepareBattleHistory({ pair, me, opponent, turnEndCallback }: UsePrepareBattleHistoryParams) {
export function usePrepareBattleHistory({ pair, player, opponent, turnEndCallback }: UsePrepareBattleHistoryParams) {
const setBattleHistory = useSetAtom(battleHistoryAtom);
const { lastMoves, resetLastMoves } = useEventRoundActionSubscription(pair);

const myFullDefence = me?.player_settings.defence === 100;
const myFullDefence = player?.player_settings.defence === 100;
const opponentFullDefence = opponent?.player_settings.defence === 100;

useEffect(() => {
Expand Down Expand Up @@ -123,9 +123,11 @@ export function useTimer({ remainingTime, shouldGoOn = true }: UseTimerParams) {

export function useParticipants(battleState?: BattleState | null) {
const { account } = useAccount();
const [otherPairBattleWatch] = useAtom(otherPairBattleWatchAtom);

const { pairs, players_to_pairs } = battleState || {};
const pairId = players_to_pairs?.find(([address]) => account?.decodedAddress === address)?.[1];
const pairId =
otherPairBattleWatch ?? players_to_pairs?.find(([address]) => account?.decodedAddress === address)?.[1];
const pair = pairs?.find(([number]) => pairId === number)?.[1];

const { participants, defeated_participants } = battleState || {};
Expand All @@ -143,10 +145,11 @@ export function useParticipants(battleState?: BattleState | null) {
{} as Record<string, Player>,
);

const opponentsAddress = account?.decodedAddress === player_1 ? player_2 : player_1;
const playerAddress = otherPairBattleWatch !== null ? player_1 : account?.decodedAddress;
const opponentsAddress = playerAddress === player_1 ? player_2 : player_1;

const me = participantsMap[account?.decodedAddress || ''];
const player = playerAddress ? participantsMap[playerAddress] : null;
const opponent = opponentsAddress ? participantsMap[opponentsAddress] : null;

return { participantsMap, allParticipants, me, opponent, isAlive, pair };
return { participantsMap, allParticipants, player, opponent, isAlive, pair };
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ export const battleHistoryStorage = getStorage<BattleHistory[]>(BATTLE_HISTORY_L

export const characterAtom = atom<Character | null>(characterStorage.get());
export const battleHistoryAtom = atom<BattleHistory[] | null>(battleHistoryStorage.get());

export const otherPairBattleWatchAtom = atom<number | null>(null);
55 changes: 34 additions & 21 deletions frontend/apps/tamagotchi-battle-new/src/pages/game.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import clsx from 'clsx';
import { useAtomValue, useSetAtom } from 'jotai';
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
import { useNavigate } from 'react-router-dom';
import { Button } from '@gear-js/vara-ui';
import { useAccount } from '@gear-js/react-hooks';
Expand Down Expand Up @@ -32,7 +32,7 @@ import {
useStartNextFightMessage,
} from '@/app/utils';
import { ROUTES } from '@/app/consts';
import { battleHistoryAtom, battleHistoryStorage } from '@/features/game/store';
import { battleHistoryAtom, battleHistoryStorage, otherPairBattleWatchAtom } from '@/features/game/store';
import { useParticipants, usePending } from '@/features/game/hooks';
import styles from './game.module.scss';

Expand All @@ -57,7 +57,10 @@ export default function GamePage() {

const [isShowTurnEndCard, setIsShowTurnEndCard] = useState(false);

const { allParticipants, isAlive, me, opponent, participantsMap, pair } = useParticipants(battleState);
const [otherPairBattleWatch] = useAtom(otherPairBattleWatchAtom);
const isShowOtherBattle = Boolean(battleState?.pairs.some(([pairId]) => pairId === otherPairBattleWatch));

const { allParticipants, isAlive, player, opponent, participantsMap, pair } = useParticipants(battleState);

const { admin, state, waiting_player, bid } = battleState || {};

Expand Down Expand Up @@ -117,17 +120,26 @@ export default function GamePage() {
return (
<>
<Background>
<CharacterStats align="left" characterView={me.appearance} name={me.user_name} {...me.player_settings} />
<div className={clsx(styles.character, styles.left)}>
<Character {...me.appearance} />
{player && (
<>
<CharacterStats
align="left"
characterView={player.appearance}
name={player.user_name}
{...player.player_settings}
/>
<div className={clsx(styles.character, styles.left)}>
<Character {...player.appearance} />

<SphereAnimation
className={styles.fireSphere}
type={tappedButton || (showAnimation ? lastTurnHistory?.player.action : undefined)}
/>
</div>
<SphereAnimation
className={styles.fireSphere}
type={tappedButton || (showAnimation ? lastTurnHistory?.player.action : undefined)}
/>
</div>
</>
)}

{opponent && !showAnimation && <Timer remainingTime={timeLeft} isYourTurn={tappedButton === null} />}
{player && opponent && !showAnimation && <Timer remainingTime={timeLeft} isYourTurn={tappedButton === null} />}

{opponent && (
<>
Expand All @@ -150,7 +162,7 @@ export default function GamePage() {
{lastTurnHistory && showAnimation && <FireballCanvas lastTurnHistory={lastTurnHistory} />}

{showWaitingForOpponent ||
(!!opponent && !isTournamentOver && (
(!!opponent && !!player && !isTournamentOver && !isShowOtherBattle && (
<div className={styles.buttons}>
<GameButton
onClick={onAttackClick}
Expand All @@ -166,7 +178,7 @@ export default function GamePage() {
text="Reflect"
icon={<DefenceButtonIcon />}
pending={tappedButton === 'Reflect' || pending}
turnsBlocked={me.reflect_reload}
turnsBlocked={player.reflect_reload}
disabled={showWaitingForOpponent}
/>
<GameButton
Expand All @@ -175,13 +187,13 @@ export default function GamePage() {
text="Ultimate"
icon={<UltimateButtonIcon />}
pending={tappedButton === 'Ultimate' || pending}
turnsBlocked={me.ultimate_reload}
turnsBlocked={player.ultimate_reload}
disabled={showWaitingForOpponent}
/>
</div>
))}

{showStartNextBattle && !isTournamentOver && (
{showStartNextBattle && !isTournamentOver && !isShowOtherBattle && (
<Button
color="primary"
className={styles.nextButton}
Expand All @@ -197,13 +209,13 @@ export default function GamePage() {

{showWaitingForOpponent && <GameSpinner text="Please wait for your opponent" />}

{opponent && pair && (
<BattleHistorySinc me={me} opponent={opponent} turnEndCallback={turnEndCallback} pair={pair} />
{player && opponent && pair && (
<BattleHistorySinc player={player} opponent={opponent} turnEndCallback={turnEndCallback} pair={pair} />
)}

{isShowTurnEndCard && lastTurnHistory && opponent && !isTournamentOver && (
{isShowTurnEndCard && lastTurnHistory && player && opponent && !isTournamentOver && (
<div className={clsx(styles.historyItem, styles.endTurnHistory)}>
<BattleHistoryCard {...me.player_settings} {...lastTurnHistory.player} name={me.user_name} />
<BattleHistoryCard {...player.player_settings} {...lastTurnHistory.player} name={player.user_name} />
<BattleHistoryCard
{...opponent.player_settings}
{...lastTurnHistory.opponent}
Expand All @@ -221,6 +233,7 @@ export default function GamePage() {
state={state}
participantsMap={participantsMap}
isAlive={isAlive}
isShowOtherBattle={isShowOtherBattle}
/>

{isAdmin ? (
Expand All @@ -245,7 +258,7 @@ export default function GamePage() {
<BattleTabs
battleState={battleState}
participantsMap={participantsMap}
me={me}
player={player}
opponent={opponent}
isAlive={isAlive}
/>
Expand Down
6 changes: 3 additions & 3 deletions frontend/apps/tamagotchi-battle-new/src/pages/waiting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ export default function WaitingPage() {
}

const { participants, battle_name, admin } = battleState;
const me = participants.find(([address]) => address === account.decodedAddress)?.[1];
const player = participants.find(([address]) => address === account.decodedAddress)?.[1];

if (!me) {
if (!player) {
return <div>Character not found</div>;
}

const { appearance, player_settings, user_name } = me;
const { appearance, player_settings, user_name } = player;

const items = participants?.map(([address, { user_name }]) => ({ name: user_name, address }));
const isAdmin = account.decodedAddress === admin;
Expand Down

0 comments on commit 5928e40

Please sign in to comment.