UNPKG

slanted-gamedev-toolz

Version:

A slanted mix of tools for your brilliant ideas in game design.

234 lines (233 loc) 12.1 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useCallback, useState, useEffect, useMemo, useRef, } from 'react'; import { Typography, Box, Stack, Button, Divider } from '@mui/material'; import { CardBasic } from '../components/CardBasic'; import ElectricBoltIcon from '@mui/icons-material/ElectricBolt'; import { convertMS } from '../hooks/useCardTimeData'; import { genTimeProbe } from '../util/generateCard'; import { useSaveObjectLocalStorage } from '../hooks/useSaveObjectLocalStorage'; const dateOptions = { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', }; const gameOptionsDef = { isCloningFree: true, cardCapacity: 2, }; export const IdleHistoryBoard = ({ cards = [], timeTargets = [], }) => { const [gameOptions, setGameOptions] = useState(gameOptionsDef); const [localCards, setLocalCards] = useState([]); const [quarks, setQuarks] = useState(0); const [selectedTimeProbe, setSelectedTimeProbe] = useState(undefined); const [createdProbesCount, setCreatedProbesCount] = useState(0); const [deadProbesCount, setDeadProbesCount] = useState(0); const [darkQuarks, setDarkQuarks] = useState(0); const [jumpedDistance, setJumpedDistance] = useState(0); const [gameLog, setGameLog] = useState(['waiting.....']); const displayQuarks = quarks - darkQuarks; const [gameData, setGameData] = useState({}); const [isCollecting, setIsCollecting] = useState(false); const {} = useSaveObjectLocalStorage(); const addQuarks = useCallback((dateCreated, amount, timeRate) => { setGameData((prev) => ({ ...prev, [dateCreated.getTime()]: amount * timeRate, })); }, [setGameData]); useEffect(() => { return function cleanup() { console.log('cleanup', isCollecting); }; }, []); // Card Actions const activeCards = localCards.filter((card) => card.isDestroyed === false); const deadCards = localCards.filter((card) => card.isDestroyed === true); const lastDeadCards = useMemo(() => { return deadCards.slice(-2).reverse(); }, [deadCards]); const spawnCards = (cards) => { const created = cards[0].dateCreated; // look if card exists in localCards. if so return if (localCards.find((card) => { return card.dateCreated.getTime() === created.getTime(); })) { return; } setLocalCards((prev) => [...prev, ...cards]); }; const purchaseForQuarks = (cost) => { if (displayQuarks < cost) return false; addGameLog(`lost ${convertMS(cost).dateString}${convertMS(cost).timeString} quarks in replication process... `); setDarkQuarks((prev) => prev + cost); return true; }; const replicateCard = (card, modifier) => { const isAtProbeMax = activeCards.length >= gameOptions.cardCapacity; if (isAtProbeMax) { addGameLog(`error... failed to replicate... maximum ${gameOptions.cardCapacity}/${gameOptions.cardCapacity} probes`); return; } const cardCost = gameOptions.isCloningFree ? 0 : calcReplicateCost(card.lifeDuration, card.timeRate); const canAfford = purchaseForQuarks(cardCost); if (canAfford) { addGameLog(`job complete.... replicated ${card.name}`); let newCard = { ...card, }; newCard.dateCreated = new Date(); newCard.isDestroyed = false; newCard.description = []; const mutateScale = 1 + Math.random(); if (modifier === 'isMutateTimeRate') { const mutationName = `${Math.round(mutateScale * 100)}% Speed`; const newTimeRate = Math.round(card.timeRate * mutateScale * 100) / 100; addGameLog(`mutating time rate.. ${card.name} ${card.timeRate}>${newTimeRate}`); newCard.name = mutationName; newCard.timeRate = newTimeRate; newCard.description.push(`mutated time travel rate...`); } if (modifier === 'isMutateDurability') { const mutationName = `${Math.round(mutateScale * 100)}% Duration`; const newDurability = Math.round(card.lifeDuration * mutateScale * 100) / 100; addGameLog(`mutating Durability rate.. ${card.name} ${card.timeRate}>${newDurability}`); newCard.name = mutationName; newCard.lifeDuration = newDurability; newCard.description.push(`mutated Durability...`); } const cards = [newCard]; spawnCards([...cards]); setCreatedProbesCount((prev) => prev + 1); } else { addGameLog(`insufficient quarks - required: ${convertMS(cardCost).dateString}${convertMS(cardCost).timeString}`); } }; const destroyCardFromLocalCards = useCallback((dateCreated) => { const cardToDestroy = localCards.filter((obj) => { return obj.dateCreated === dateCreated; })[0]; const index = localCards.findIndex((obj) => { return obj.dateCreated === dateCreated; }); if (!cardToDestroy) console.error('Failed to destroy card'); localCards[index].isDestroyed = true; addGameLog(`destroyed: ${cardToDestroy.name} x${cardToDestroy.timeRate}`); setDeadProbesCount((prev) => prev + 1); }, [localCards]); const destroyCard = useCallback((dateCreated) => { console.log('-- destroyCard --'); setDeadProbesCount((prev) => prev + 1); }, []); // Util const getAdjustedDate = () => { const currentTimeAsMs = Date.now(); const adjustedTimeAsMs = currentTimeAsMs + jumpedDistance; return new Date(adjustedTimeAsMs); }; const getAdjustedDateStr = () => { return getAdjustedDate().toLocaleDateString('en-US', dateOptions); }; // Board Actions const jumpWarp = useCallback(() => { const currentTimeAsMs = getAdjustedDate().getTime(); setDeadProbesCount(0); setCreatedProbesCount(1); const adjustedTimeAsMs = currentTimeAsMs + jumpedDistance; const adjustedDateDestination = new Date(adjustedTimeAsMs).toLocaleDateString('en-US', dateOptions); addGameLog(`${getAdjustedDateStr()} >>> ${adjustedDateDestination}`); addGameLog(`Jumping ahead...`); addGameLog(`Processing...`); if (!selectedTimeProbe) return; setDarkQuarks((prev) => prev + displayQuarks); setJumpedDistance((prev) => prev + displayQuarks); setQuarks((probedMs) => 0); setLocalCards([]); setTimeout(() => { selectedTimeProbe.dateCreated = new Date(); setLocalCards([selectedTimeProbe]); }, 250); }, [displayQuarks, jumpedDistance]); const jumpBtnText = `${convertMS(displayQuarks).dateString} ${convertMS(displayQuarks).timeString} `; // Update gameData useEffect(() => { const localCardsInGameData = Object.values(gameData); const sum = localCardsInGameData.reduce((accumulator, value) => { return accumulator + value; }, 0); setQuarks(Math.round(sum)); }, [gameData]); // GAME LOG const start = useCallback(() => { addGameLog(`Traveling an normal speed.`); addGameLog(`time travel probe activated....`); addGameLog(`initializing....`); const cards = [genTimeProbe()]; spawnCards([...cards]); setCreatedProbesCount((prev) => prev + 1); }, []); // autostart // useEffect(() => { // start(); // setCreatedProbesCount((prev) => prev + 1); // }, []); const addGameLog = useCallback((text) => { setGameLog((prev) => { return [...prev, text]; }); logRef.current?.scrollIntoView(); }, [gameLog]); const logRef = useRef(); const displayGameLog = useMemo(() => { return (_jsxs(Box, { sx: { width: '100%', textAlign: 'center', height: '75px', overflow: 'auto', }, children: [gameLog.map((log, i) => { const isTopLog = true; return (_jsx(Box, { sx: centerFlexbox, children: _jsx(Typography, { variant: isTopLog ? 'body1' : 'caption', sx: { color: isTopLog ? 'lightgreen' : 'inherit' }, children: log }) }, log + i)); }), _jsx(Box, { ref: logRef })] })); }, [gameLog]); const gameStartedDate = useRef(new Date()); const jumpedText = 'traveled'; const postJumpText = '-1h 0-1m 0-1s -1 years, 364 days'; const chargeText = jumpBtnText == postJumpText ? jumpedText : jumpBtnText; const nowMs = Date.now(); const adjustedTimeAsMs = nowMs + jumpedDistance; const targetDateMs = gameStartedDate.current.getTime() + 60000; const targetDateGoal = new Date(targetDateMs).toLocaleDateString('en-US', dateOptions); const reachedGoal = adjustedTimeAsMs > targetDateMs; useEffect(() => { if (reachedGoal) setGameOptions({ ...gameOptions, cardCapacity: 3 }); }, [reachedGoal]); return (_jsxs(Stack, { spacing: 1, direction: "column", children: [_jsx(Typography, { sx: { pt: 2 }, variant: "h2", children: getAdjustedDateStr() }), _jsx(Typography, { sx: { pt: 2 }, variant: "h5", children: reachedGoal ? 'Reached Target Point - More Soon' : `Target Date: ${targetDateGoal}` }), _jsx(Divider, { sx: { width: '100%', my: '10px' } }), displayGameLog, _jsx(Typography, { variant: "h4", children: `Probes: ${activeCards.length}/${gameOptions.cardCapacity}` }), _jsxs(Typography, { variant: "h6", children: [`${activeCards.length} collecting: `, _jsx(ElectricBoltIcon, { sx: { position: 'relative', top: '5px' } })] }), _jsxs(Box, { children: [isCollecting && _jsx(Typography, { variant: "h5", children: "Warp Distance" }), _jsxs(Typography, { variant: "h6", children: [isCollecting ? `` : `${localCards.length === 0 ? 'Launch a time probe to begin collecting time units.' : ''}`, _jsx(ElectricBoltIcon, { sx: { position: 'relative', top: '5px' } }), ":", ' ', chargeText] })] }), _jsx(Typography, { variant: "caption", children: `total jumped: ${convertMS(jumpedDistance).dateString} ${convertMS(jumpedDistance).timeString} ` }), _jsxs(Box, { sx: { display: 'flex', flexWrap: 'wrap', justifyContent: 'center' }, children: [localCards.length === 0 && (_jsx(Button, { variant: "contained", color: "success", onClick: start, children: "Launch Probe at 1x normal time rate...." })), activeCards.map((card, i) => { const { name, description, lifeDuration, dateCreated, timeRate, creates, counterSpeedMs, minTimeRate, maxTimeRate, rateSliderStep, rateReturn, completed, } = card; return (_jsx(CardBasic, { name: name, description: description, lifeDuration: lifeDuration, dateCreated: dateCreated, timeRate: timeRate, creates: creates, counterSpeedMs: counterSpeedMs, minTimeRate: minTimeRate, maxTimeRate: maxTimeRate, rateSliderStep: rateSliderStep, rateReturn: rateReturn, addQuarks: addQuarks, duplicate: (modifier) => replicateCard(card, modifier), destroyCard: () => destroyCard(card.dateCreated), selectCard: () => setSelectedTimeProbe(card), selectedCard: selectedTimeProbe, gameOptions: gameOptions, localCards: localCards, activeCards: activeCards, jumpWarp: jumpWarp }, name + i)); })] }), _jsx(Divider, { sx: { width: '100%', my: '10px' } })] })); }; export const calcReplicateCost = (lifeDuration, timeRate) => { return (lifeDuration / 5) * (timeRate / 50); }; const centerFlexbox = { display: 'flex', flexDirection: 'column', justifyContent: 'space-between', alignItems: 'center', };