/** * @file Companion panel component for managing active companions. * @copyright nhcarrigan * @license Naomi's Public License * @author Naomi Carrigan */ /* eslint-disable react/no-multi-comp -- Sub-component is tightly coupled to the panel */ /* eslint-disable max-lines-per-function -- Complex companion card with conditional renders */ /* eslint-disable complexity -- Companion card has many conditional render paths */ import { COMPANIONS, type Companion } from "@elysium/types"; import { useGame } from "../../context/gameContext.js"; import { cdnImage } from "../../utils/cdn.js"; import type { JSX } from "react"; const bonusLabels: Record = { bossDamage: "Boss Damage", clickGold: "Click Gold", essenceIncome: "Essence Income", passiveGold: "Passive Gold", questTime: "Quest Time", }; const unlockLabels: Record = { apotheosis: "apotheosis", lifetimeBosses: "lifetime bosses defeated", lifetimeGold: "lifetime gold earned", lifetimeQuests: "lifetime quests completed", prestige: "prestige(s)", transcendence: "transcendence(s)", }; interface CompanionCardProperties { readonly companion: Companion; readonly isUnlocked: boolean; readonly isActive: boolean; readonly onSelect: ()=> void; readonly formatNumber: (n: number)=> string; readonly currentProgress: number; } /** * Renders a single companion card. * @param props - The companion card properties. * @param props.companion - The companion data. * @param props.isUnlocked - Whether this companion is unlocked. * @param props.isActive - Whether this companion is currently active. * @param props.onSelect - Callback when the companion is selected/deselected. * @param props.formatNumber - The number formatting utility function. * @param props.currentProgress - The player's current progress toward the unlock threshold. * @returns The JSX element. */ const CompanionCard = ({ companion, isUnlocked, isActive, onSelect, formatNumber, currentProgress, }: CompanionCardProperties): JSX.Element => { const bonusSign = companion.bonus.type === "questTime" ? "-" : "+"; const bonusPercent = Math.round(companion.bonus.value * 100); const bonusLabel = bonusLabels[companion.bonus.type] ?? companion.bonus.type; return (
{companion.name}
{companion.name} {companion.title}
{isActive ? {"Active"} : null}

{companion.description}

{bonusLabel} {bonusSign} {bonusPercent} {"%"}
{isUnlocked ? :

{"🔒 Unlock: "} {companion.unlock.type === "lifetimeGold" ? formatNumber(companion.unlock.threshold) : String(companion.unlock.threshold)}{" "} {unlockLabels[companion.unlock.type] ?? companion.unlock.type}

{companion.unlock.type === "lifetimeGold" ? formatNumber(currentProgress) : String(currentProgress)} {" / "} {companion.unlock.type === "lifetimeGold" ? formatNumber(companion.unlock.threshold) : String(companion.unlock.threshold)}
}
); }; /** * Renders the companion panel with all companions. * @returns The JSX element. */ const CompanionPanel = (): JSX.Element => { const { formatNumber, setActiveCompanion, state } = useGame(); if (state === null) { return (

{"Loading..."}

); } const unlockedIds = state.companions?.unlockedCompanionIds ?? []; const activeId = state.companions?.activeCompanionId ?? null; const progressByUnlockType: Record = { apotheosis: state.apotheosis?.count ?? 0, lifetimeBosses: state.player.lifetimeBossesDefeated, // eslint-disable-next-line stylistic/max-len -- Long expression; splitting would reduce readability lifetimeGold: state.player.lifetimeGoldEarned + state.player.totalGoldEarned, lifetimeQuests: state.player.lifetimeQuestsCompleted, prestige: state.prestige.count, transcendence: state.transcendence?.count ?? 0, }; function handleSelect(companionId: string): void { setActiveCompanion(activeId === companionId ? null : companionId); } const activeCompanion = activeId === null ? undefined : COMPANIONS.find((companion) => { return companion.id === activeId; }); return (

{"👥 Companions"}

{"Companions provide powerful bonuses while active." + " You can only have one companion active at a time."} {activeId === null ? null : <> {" Currently active: "} {activeCompanion?.name ?? activeId} {"."} }

{COMPANIONS.map((companion) => { function handleCompanionSelect(): void { handleSelect(companion.id); } return ( ); })}
); }; export { CompanionPanel };