generated from nhcarrigan/template
@@ -12,20 +12,48 @@ const CLASS_ICONS: Record<string, string> = {
|
||||
paladin: "🛡️",
|
||||
};
|
||||
|
||||
const adventurerCost = (adventurer: Adventurer): number =>
|
||||
Math.ceil(10 * Math.pow(1.15, adventurer.count));
|
||||
type BatchSize = 1 | 5 | 10 | 25 | 100 | "max";
|
||||
const BATCH_OPTIONS: BatchSize[] = [1, 5, 10, 25, 100, "max"];
|
||||
|
||||
const computeBatchCost = (adventurer: Adventurer, quantity: number): number => {
|
||||
let total = 0;
|
||||
for (let i = 0; i < quantity; i++) {
|
||||
total += 10 * Math.pow(1.15, adventurer.count + i);
|
||||
}
|
||||
return total;
|
||||
};
|
||||
|
||||
const computeMaxAffordable = (adventurer: Adventurer, gold: number): number => {
|
||||
let total = 0;
|
||||
let quantity = 0;
|
||||
for (let i = 0; i < 100_000; i++) {
|
||||
const cost = 10 * Math.pow(1.15, adventurer.count + i);
|
||||
if (total + cost > gold) break;
|
||||
total += cost;
|
||||
quantity++;
|
||||
}
|
||||
return quantity;
|
||||
};
|
||||
|
||||
interface AdventurerCardProps {
|
||||
adventurer: Adventurer;
|
||||
currentGold: number;
|
||||
batchSize: BatchSize;
|
||||
unlockHint?: string | undefined;
|
||||
formatNumber: (n: number) => string;
|
||||
}
|
||||
|
||||
const AdventurerCard = ({ adventurer, currentGold, unlockHint, formatNumber }: AdventurerCardProps): React.JSX.Element => {
|
||||
const AdventurerCard = ({ adventurer, currentGold, batchSize, unlockHint, formatNumber }: AdventurerCardProps): React.JSX.Element => {
|
||||
const { buyAdventurer } = useGame();
|
||||
const cost = adventurerCost(adventurer);
|
||||
const canAfford = currentGold >= cost;
|
||||
|
||||
const resolvedQuantity =
|
||||
batchSize === "max" ? computeMaxAffordable(adventurer, currentGold) : batchSize;
|
||||
const cost = computeBatchCost(adventurer, resolvedQuantity);
|
||||
const canAfford = resolvedQuantity > 0 && currentGold >= cost;
|
||||
|
||||
const handleBuy = (): void => {
|
||||
buyAdventurer(adventurer.id, resolvedQuantity);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`adventurer-card ${!adventurer.unlocked ? "locked" : ""}`}>
|
||||
@@ -41,10 +69,12 @@ const AdventurerCard = ({ adventurer, currentGold, unlockHint, formatNumber }: A
|
||||
<button
|
||||
className="buy-button"
|
||||
disabled={!canAfford || !adventurer.unlocked}
|
||||
onClick={() => { buyAdventurer(adventurer.id); }}
|
||||
onClick={handleBuy}
|
||||
type="button"
|
||||
>
|
||||
{adventurer.unlocked ? `🪙 ${formatNumber(cost)}` : "🔒 Locked"}
|
||||
{adventurer.unlocked
|
||||
? `🪙 ${formatNumber(Math.ceil(cost))}${batchSize === "max" && resolvedQuantity > 0 ? ` (×${resolvedQuantity})` : ""}`
|
||||
: "🔒 Locked"}
|
||||
</button>
|
||||
{!adventurer.unlocked && unlockHint && (
|
||||
<p className="unlock-hint">📜 Complete: {unlockHint}</p>
|
||||
@@ -56,6 +86,7 @@ const AdventurerCard = ({ adventurer, currentGold, unlockHint, formatNumber }: A
|
||||
export const AdventurerPanel = (): React.JSX.Element => {
|
||||
const { state, formatNumber } = useGame();
|
||||
const [showLocked, setShowLocked] = useState(true);
|
||||
const [batchSize, setBatchSize] = useState<BatchSize>(1);
|
||||
|
||||
if (!state) return <section className="panel"><p>Loading...</p></section>;
|
||||
|
||||
@@ -81,11 +112,24 @@ export const AdventurerPanel = (): React.JSX.Element => {
|
||||
onToggle={() => { setShowLocked((v) => !v); }}
|
||||
/>
|
||||
</div>
|
||||
<div className="batch-selector">
|
||||
{BATCH_OPTIONS.map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
className={`batch-button ${batchSize === option ? "active" : ""}`}
|
||||
onClick={() => { setBatchSize(option); }}
|
||||
type="button"
|
||||
>
|
||||
{option === "max" ? "xMax" : `x${option}`}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="adventurer-list">
|
||||
{visible.map((adventurer) => (
|
||||
<AdventurerCard
|
||||
key={adventurer.id}
|
||||
adventurer={adventurer}
|
||||
batchSize={batchSize}
|
||||
currentGold={state.resources.gold}
|
||||
unlockHint={adventurerUnlockHints.get(adventurer.id)}
|
||||
formatNumber={formatNumber}
|
||||
|
||||
Reference in New Issue
Block a user