slanted-gamedev-toolz
Version:
A slanted mix of tools for your brilliant ideas in game design.
234 lines (233 loc) • 12.1 kB
JavaScript
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',
};