feat: v1 prototype — core game systems #30

Merged
naomi merged 84 commits from feat/prototype into main 2026-03-08 15:53:39 -07:00
3 changed files with 23 additions and 17 deletions
Showing only changes of commit 59c417e75e - Show all commits
@@ -19,9 +19,10 @@ interface AdventurerCardProps {
adventurer: Adventurer;
currentGold: number;
unlockHint?: string | undefined;
formatNumber: (n: number) => string;
}
const AdventurerCard = ({ adventurer, currentGold, unlockHint }: AdventurerCardProps): React.JSX.Element => {
const AdventurerCard = ({ adventurer, currentGold, unlockHint, formatNumber }: AdventurerCardProps): React.JSX.Element => {
const { buyAdventurer } = useGame();
const cost = adventurerCost(adventurer);
const canAfford = currentGold >= cost;
@@ -31,9 +32,9 @@ const AdventurerCard = ({ adventurer, currentGold, unlockHint }: AdventurerCardP
<div className="adventurer-icon">{CLASS_ICONS[adventurer.class] ?? "⚔️"}</div>
<div className="adventurer-info">
<h3>{adventurer.name}</h3>
<p>{adventurer.goldPerSecond.toFixed(2)} gold/s each</p>
<p>{formatNumber(adventurer.goldPerSecond)} gold/s each</p>
{adventurer.essencePerSecond > 0 && (
<p>{adventurer.essencePerSecond.toFixed(3)} essence/s each</p>
<p>{formatNumber(adventurer.essencePerSecond)} essence/s each</p>
)}
</div>
<div className="adventurer-count">×{adventurer.count}</div>
@@ -43,7 +44,7 @@ const AdventurerCard = ({ adventurer, currentGold, unlockHint }: AdventurerCardP
onClick={() => { buyAdventurer(adventurer.id); }}
type="button"
>
{adventurer.unlocked ? `🪙 ${cost}` : "🔒 Locked"}
{adventurer.unlocked ? `🪙 ${formatNumber(cost)}` : "🔒 Locked"}
</button>
{!adventurer.unlocked && unlockHint && (
<p className="unlock-hint">📜 Complete: {unlockHint}</p>
@@ -53,7 +54,7 @@ const AdventurerCard = ({ adventurer, currentGold, unlockHint }: AdventurerCardP
};
export const AdventurerPanel = (): React.JSX.Element => {
const { state } = useGame();
const { state, formatNumber } = useGame();
const [showLocked, setShowLocked] = useState(true);
if (!state) return <section className="panel"><p>Loading...</p></section>;
@@ -87,6 +88,7 @@ export const AdventurerPanel = (): React.JSX.Element => {
adventurer={adventurer}
currentGold={state.resources.gold}
unlockHint={adventurerUnlockHints.get(adventurer.id)}
formatNumber={formatNumber}
/>
))}
</div>
@@ -5,7 +5,7 @@ import { useGame } from "../../context/GameContext.js";
const PRESTIGE_THRESHOLD = 1_000_000;
export const PrestigePanel = (): React.JSX.Element => {
const { state, reload } = useGame();
const { state, reload, formatNumber } = useGame();
const [characterName, setCharacterName] = useState("");
const [isPending, setIsPending] = useState(false);
const [result, setResult] = useState<{ runestones: number; count: number } | null>(null);
@@ -42,10 +42,10 @@ export const PrestigePanel = (): React.JSX.Element => {
<div className="prestige-status">
<p>
Total gold earned:{" "}
<strong>{state.player.totalGoldEarned.toLocaleString()}</strong>
<strong>{formatNumber(state.player.totalGoldEarned)}</strong>
</p>
<p>
Required: <strong>{PRESTIGE_THRESHOLD.toLocaleString()}</strong>
Required: <strong>{formatNumber(PRESTIGE_THRESHOLD)}</strong>
</p>
<p>Current prestige count: <strong>{state.prestige.count}</strong></p>
<p>
@@ -82,7 +82,7 @@ export const PrestigePanel = (): React.JSX.Element => {
</div>
) : (
<p className="prestige-locked">
Earn {(PRESTIGE_THRESHOLD - state.player.totalGoldEarned).toLocaleString()} more
Earn {formatNumber(PRESTIGE_THRESHOLD - state.player.totalGoldEarned)} more
gold to unlock prestige.
</p>
)}
+12 -8
View File
@@ -9,9 +9,10 @@ interface UpgradeCardProps {
currentEssence: number;
currentCrystals: number;
unlockHint?: string | undefined;
formatNumber: (n: number) => string;
}
const UpgradeCard = ({ upgrade, currentGold, currentEssence, currentCrystals, unlockHint }: UpgradeCardProps): React.JSX.Element => {
const UpgradeCard = ({ upgrade, currentGold, currentEssence, currentCrystals, unlockHint, formatNumber }: UpgradeCardProps): React.JSX.Element => {
const { buyUpgrade } = useGame();
const canAfford =
currentGold >= upgrade.costGold &&
@@ -27,9 +28,9 @@ const UpgradeCard = ({ upgrade, currentGold, currentEssence, currentCrystals, un
<p className="upgrade-multiplier">×{upgrade.multiplier} multiplier</p>
</div>
<div className="upgrade-cost">
{upgrade.costGold > 0 && <span>🪙 {upgrade.costGold.toLocaleString()}</span>}
{upgrade.costEssence > 0 && <span> {upgrade.costEssence.toLocaleString()}</span>}
{(upgrade.costCrystals ?? 0) > 0 && <span>💎 {upgrade.costCrystals?.toLocaleString()}</span>}
{upgrade.costGold > 0 && <span>🪙 {formatNumber(upgrade.costGold)}</span>}
{upgrade.costEssence > 0 && <span> {formatNumber(upgrade.costEssence)}</span>}
{(upgrade.costCrystals ?? 0) > 0 && <span>💎 {formatNumber(upgrade.costCrystals ?? 0)}</span>}
</div>
<span className="upgrade-locked-label">Locked</span>
{unlockHint && <p className="unlock-hint">{unlockHint}</p>}
@@ -54,9 +55,9 @@ const UpgradeCard = ({ upgrade, currentGold, currentEssence, currentCrystals, un
<p className="upgrade-multiplier">×{upgrade.multiplier} multiplier</p>
</div>
<div className="upgrade-cost">
{upgrade.costGold > 0 && <span>🪙 {upgrade.costGold.toLocaleString()}</span>}
{upgrade.costEssence > 0 && <span> {upgrade.costEssence.toLocaleString()}</span>}
{(upgrade.costCrystals ?? 0) > 0 && <span>💎 {upgrade.costCrystals?.toLocaleString()}</span>}
{upgrade.costGold > 0 && <span>🪙 {formatNumber(upgrade.costGold)}</span>}
{upgrade.costEssence > 0 && <span> {formatNumber(upgrade.costEssence)}</span>}
{(upgrade.costCrystals ?? 0) > 0 && <span>💎 {formatNumber(upgrade.costCrystals ?? 0)}</span>}
</div>
<button
className="buy-button"
@@ -71,7 +72,7 @@ const UpgradeCard = ({ upgrade, currentGold, currentEssence, currentCrystals, un
};
export const UpgradePanel = (): React.JSX.Element => {
const { state } = useGame();
const { state, formatNumber } = useGame();
const [showLocked, setShowLocked] = useState(true);
if (!state) return <section className="panel"><p>Loading...</p></section>;
@@ -116,6 +117,7 @@ export const UpgradePanel = (): React.JSX.Element => {
currentGold={state.resources.gold}
currentEssence={state.resources.essence}
currentCrystals={state.resources.crystals}
formatNumber={formatNumber}
/>
))}
{purchased.map((upgrade) => (
@@ -125,6 +127,7 @@ export const UpgradePanel = (): React.JSX.Element => {
currentGold={state.resources.gold}
currentEssence={state.resources.essence}
currentCrystals={state.resources.crystals}
formatNumber={formatNumber}
/>
))}
{showLocked && locked.map((upgrade) => (
@@ -134,6 +137,7 @@ export const UpgradePanel = (): React.JSX.Element => {
currentGold={state.resources.gold}
currentEssence={state.resources.essence}
currentCrystals={state.resources.crystals}
formatNumber={formatNumber}
unlockHint={upgradeUnlockHints.get(upgrade.id)}
/>
))}