generated from nhcarrigan/template
feat: initial elysium idle game prototype
Sets up the full monorepo with pnpm workspaces. Includes shared types package, Hono API with Discord OAuth/JWT auth, Prisma v6 + MongoDB Atlas, and React + Vite frontend with game loop, five tabs, and Discord-linked save/load.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import type { Boss } from "@elysium/types";
|
||||
import { useGame } from "../../context/GameContext.js";
|
||||
|
||||
interface BossCardProps {
|
||||
boss: Boss;
|
||||
prestigeCount: number;
|
||||
}
|
||||
|
||||
const BossCard = ({ boss, prestigeCount }: BossCardProps): React.JSX.Element => {
|
||||
const { attackBoss } = useGame();
|
||||
const hpPercent = (boss.currentHp / boss.maxHp) * 100;
|
||||
const isLocked = boss.prestigeRequirement > prestigeCount;
|
||||
|
||||
return (
|
||||
<div className={`boss-card boss-${boss.status}`}>
|
||||
<div className="boss-info">
|
||||
<h3>{boss.name}</h3>
|
||||
<p>{boss.description}</p>
|
||||
{isLocked && boss.status === "locked" && (
|
||||
<p className="prestige-lock">🔒 Requires Prestige {boss.prestigeRequirement}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{boss.status !== "locked" && boss.status !== "defeated" && (
|
||||
<div className="boss-hp">
|
||||
<div className="hp-bar">
|
||||
<div
|
||||
className="hp-fill"
|
||||
style={{ width: `${hpPercent.toFixed(1)}%` }}
|
||||
/>
|
||||
</div>
|
||||
<span className="hp-text">
|
||||
{boss.currentHp.toLocaleString()} / {boss.maxHp.toLocaleString()} HP
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="boss-rewards">
|
||||
<span>🪙 {boss.goldReward.toLocaleString()}</span>
|
||||
{boss.essenceReward > 0 && <span>✨ {boss.essenceReward.toLocaleString()}</span>}
|
||||
{boss.crystalReward > 0 && <span>💎 {boss.crystalReward.toLocaleString()}</span>}
|
||||
</div>
|
||||
|
||||
{boss.status === "available" || boss.status === "in_progress" ? (
|
||||
<button
|
||||
className="attack-button"
|
||||
onClick={() => { void attackBoss(boss.id); }}
|
||||
type="button"
|
||||
>
|
||||
⚔️ Attack
|
||||
</button>
|
||||
) : null}
|
||||
|
||||
{boss.status === "defeated" && (
|
||||
<span className="boss-badge defeated">☠️ Defeated</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const BossPanel = (): React.JSX.Element => {
|
||||
const { state } = useGame();
|
||||
|
||||
if (!state) return <section className="panel"><p>Loading...</p></section>;
|
||||
|
||||
return (
|
||||
<section className="panel boss-panel">
|
||||
<h2>Boss Encounters</h2>
|
||||
<div className="boss-list">
|
||||
{state.bosses.map((boss) => (
|
||||
<BossCard
|
||||
key={boss.id}
|
||||
boss={boss}
|
||||
prestigeCount={state.prestige.count}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user