import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { UnitType, usePlayer } from "../providers/PlayerProvider"; import styles from "../styles/Army.module.css"; import { calculateBalance, toReadable } from "./Counter"; import PixelatedQuote from "./PixelatedQuote"; const PRECISION = BigInt(10000); const PRICE_FACTOR = BigInt(11500); const base_cost: Record = { 0: BigInt(380000), 1: BigInt(3420000), 2: BigInt(30096000), 3: BigInt(255816000), }; const profits: Record = { 0: BigInt(2533), 1: BigInt(27863), 2: BigInt(306493), 3: BigInt(3371423), }; function calculateUnitPrice( unit: UnitType, currentLevel: number, units: number ) { let rollingPriceCalculation = base_cost[unit]; let price = BigInt(0); // Each level costs 15% more than previous for (let i = 0; i < currentLevel + units; i++) { if (i >= currentLevel) { price += rollingPriceCalculation; } rollingPriceCalculation = (rollingPriceCalculation * PRICE_FACTOR) / PRECISION; } return price; } function calculateProfitPerSecond(unit: UnitType, level: number) { // Each next unit scales progressivelly better return BigInt(level) * profits[unit]; } const unitTypeToCss: Record = { 0: styles.moloch_denier, 1: styles.apprentice, 2: styles.anointed, 3: styles.champion, }; const unitTypeToName: Record = { 0: "Moloch denier", 1: "Apprentice", 2: "Anointed", 3: "Champion", }; const defaultAvailabilityMap: Record = { 0: false, 1: false, 2: false, 3: false, }; const unitDiscoveredAt: Record = { 0: BigInt(0), 1: BigInt(300_0000), 2: BigInt(2800_0000), 3: BigInt(24000_0000), }; const unitAvailableToDiscoverAt: Record = { 0: BigInt(0), 1: BigInt(200_0000), 2: BigInt(2000_0000), 3: BigInt(25000_0000), }; interface UnitProps { addUnit: (unitType: UnitType) => void; unitType: UnitType; canPurchase: boolean; isShrouded: boolean; n_units: number; } const Unit = ({ addUnit, unitType, canPurchase, isShrouded, n_units, }: UnitProps) => { const [unitPrice, unitProfit] = useMemo(() => { return [ toReadable(calculateUnitPrice(unitType, n_units, 1)), toReadable(calculateProfitPerSecond(unitType, n_units)), ]; }, [n_units, unitType]); return (
addUnit(unitType)} className={`${styles.armyUnit} ${canPurchase ? "" : styles.isUnavailable }`} >
{isShrouded ? "???????" : unitTypeToName[unitType]} {isShrouded ? null : ( {unitPrice} GELD )} {n_units > 0 ? ( {n_units} ) : null} {n_units > 0 ? ( {unitProfit} per sec ) : null}
); }; const Army = () => { const { army, addUnit, isRegistered, player, balance } = usePlayer(); const [canPurchase, setCanPurchase] = useState>( defaultAvailabilityMap ); const [isShrouded, setIsShrouded] = useState>( defaultAvailabilityMap ); const [canKnowAbout, setCanKnowAbout] = useState>( defaultAvailabilityMap ); const balanceCount = useRef(BigInt(balance ?? 0)); const setAvailabilities = useCallback(() => { if (isRegistered) { const totalMinted = (player?.total_minted ?? BigInt(0)) + (balanceCount.current - (balance ?? BigInt(0))); const n_units: Record = { 0: army?.moloch_denier.level ?? 0, 1: army?.apprentice.level ?? 0, 2: army?.anointed.level ?? 0, 3: army?.champion.level ?? 0, }; const inShroud = { 0: totalMinted < unitDiscoveredAt[0], 1: totalMinted < unitDiscoveredAt[1], 2: totalMinted < unitDiscoveredAt[2], 3: totalMinted < unitDiscoveredAt[3], }; const isKnown = { 0: totalMinted >= unitAvailableToDiscoverAt[0], 1: totalMinted >= unitAvailableToDiscoverAt[1], 2: totalMinted >= unitAvailableToDiscoverAt[2], 3: totalMinted >= unitAvailableToDiscoverAt[3], }; const canActuallyBuy = { 0: balanceCount.current >= calculateUnitPrice(0, n_units[0], 1) && isKnown[0] && !inShroud[0], 1: balanceCount.current >= calculateUnitPrice(1, n_units[1], 1) && isKnown[1] && !inShroud[1], 2: balanceCount.current >= calculateUnitPrice(2, n_units[2], 1) && isKnown[2] && !inShroud[2], 3: balanceCount.current >= calculateUnitPrice(3, n_units[3], 1) && isKnown[3] && !inShroud[3], }; setCanPurchase(canActuallyBuy); setIsShrouded(inShroud); setCanKnowAbout(isKnown); } else { setCanPurchase(defaultAvailabilityMap); setIsShrouded(defaultAvailabilityMap); setCanKnowAbout(defaultAvailabilityMap); } }, [army, balance, isRegistered, player?.total_minted]); useEffect(() => { const tickInterval = setInterval(() => { balanceCount.current = calculateBalance( balance ?? BigInt(0), army?.profit_per_second ?? BigInt(0), player?.last_raided_at ?? BigInt(0) ); setAvailabilities(); }, 100); return () => clearInterval(tickInterval); }, [ balance, army?.profit_per_second, player?.last_raided_at, setAvailabilities, ]); return ( <>
{canKnowAbout[0] && ( )} {canKnowAbout[1] && ( )} {canKnowAbout[2] && ( )} {canKnowAbout[3] && ( )}
); }; export default Army;