Add a simple save system
This commit is contained in:
parent
d4dda5b3e4
commit
39309aa9e7
31
src/App.tsx
31
src/App.tsx
|
|
@ -1,10 +1,12 @@
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from './components/CustomTabs';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from './components/CustomTabs';
|
||||||
import { useGameTick } from './hooks/useGameTick';
|
import { useGameTick } from './hooks/useGameTick';
|
||||||
import Field from './components/Field';
|
import Field from './components/Field';
|
||||||
import Warehouse from './components/Warehouse';
|
import Warehouse from './components/Warehouse';
|
||||||
import Market from './components/Market';
|
import Market from './components/Market';
|
||||||
import { ActionCooldown } from './components/ActionCooldown';
|
import { ActionCooldown } from './components/ActionCooldown';
|
||||||
|
import { useGameStore } from './store/useGameStore';
|
||||||
|
import { hasSaveInSlot } from './utils/saveSystem';
|
||||||
|
|
||||||
const appContainerStyle: React.CSSProperties = {
|
const appContainerStyle: React.CSSProperties = {
|
||||||
maxWidth: '1200px',
|
maxWidth: '1200px',
|
||||||
|
|
@ -20,6 +22,33 @@ const tabsListStyles: React.CSSProperties = {
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
useGameTick();
|
useGameTick();
|
||||||
|
const { saveToSlot, loadFromSlot } = useGameStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
const slot = {
|
||||||
|
'1': 1,
|
||||||
|
'2': 2,
|
||||||
|
'3': 3,
|
||||||
|
'!': 1,
|
||||||
|
'@': 2,
|
||||||
|
'#': 3
|
||||||
|
}[e.key] ?? null
|
||||||
|
|
||||||
|
if (slot !== null) {
|
||||||
|
if (e.shiftKey) {
|
||||||
|
saveToSlot(slot);
|
||||||
|
console.log(`Game saved to slot ${slot}`);
|
||||||
|
} else if (hasSaveInSlot(slot)) {
|
||||||
|
loadFromSlot(slot);
|
||||||
|
console.log(`Game loaded from slot ${slot}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('keydown', handleKeyDown)
|
||||||
|
return () => window.removeEventListener('keydown', handleKeyDown)
|
||||||
|
}, [saveToSlot, loadFromSlot])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import {
|
||||||
MARKET_ITEMS
|
MARKET_ITEMS
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import { GameState, PlotState } from '../types';
|
import { GameState, PlotState } from '../types';
|
||||||
|
import { saveGame, loadGame } from '../utils/saveSystem';
|
||||||
|
|
||||||
const initializeField = (size: number): PlotState[][] => {
|
const initializeField = (size: number): PlotState[][] => {
|
||||||
return Array(size).fill(0).map(() =>
|
return Array(size).fill(0).map(() =>
|
||||||
|
|
@ -31,6 +32,8 @@ export const useGameStore = create<GameState & {
|
||||||
setActionCooldown: (cooldown: number) => void;
|
setActionCooldown: (cooldown: number) => void;
|
||||||
buyItem: (itemId: string) => void;
|
buyItem: (itemId: string) => void;
|
||||||
sellItem: (itemId: string) => void;
|
sellItem: (itemId: string) => void;
|
||||||
|
saveToSlot: (slot: number) => void;
|
||||||
|
loadFromSlot: (slot: number) => void;
|
||||||
}>((set, get) => ({
|
}>((set, get) => ({
|
||||||
cash: INITIAL_CASH,
|
cash: INITIAL_CASH,
|
||||||
inventory: INITIAL_INVENTORY,
|
inventory: INITIAL_INVENTORY,
|
||||||
|
|
@ -40,6 +43,7 @@ export const useGameStore = create<GameState & {
|
||||||
plots: initializeField(INITIAL_FIELD_SIZE),
|
plots: initializeField(INITIAL_FIELD_SIZE),
|
||||||
gameSpeed: INITIAL_GAME_SPEED,
|
gameSpeed: INITIAL_GAME_SPEED,
|
||||||
actionCooldown: 0,
|
actionCooldown: 0,
|
||||||
|
tickCount: 0,
|
||||||
|
|
||||||
assignCrop: (row, col, cropId) => {
|
assignCrop: (row, col, cropId) => {
|
||||||
set(produce(state => {
|
set(produce(state => {
|
||||||
|
|
@ -137,11 +141,6 @@ export const useGameStore = create<GameState & {
|
||||||
|
|
||||||
tick: () => {
|
tick: () => {
|
||||||
set(produce(state => {
|
set(produce(state => {
|
||||||
// Update cooldown
|
|
||||||
if (state.actionCooldown > 0) {
|
|
||||||
state.actionCooldown = Math.max(0, state.actionCooldown - (COOLDOWN_DURATION / 20));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update plots
|
// Update plots
|
||||||
state.plots.forEach((row: PlotState[], rowIndex: number) => {
|
state.plots.forEach((row: PlotState[], rowIndex: number) => {
|
||||||
row.forEach((plot: PlotState, colIndex: number) => {
|
row.forEach((plot: PlotState, colIndex: number) => {
|
||||||
|
|
@ -162,6 +161,8 @@ export const useGameStore = create<GameState & {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
state.tickCount = state.tickCount + 1;
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -228,5 +229,18 @@ export const useGameStore = create<GameState & {
|
||||||
state.cash += item.sellPrice;
|
state.cash += item.sellPrice;
|
||||||
state.inventory[itemId] -= 1;
|
state.inventory[itemId] -= 1;
|
||||||
}));
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
saveToSlot: (slot: number) => {
|
||||||
|
const state = get();
|
||||||
|
const { plant, water, harvest, tick, assignCrop, upgradeField, setGameSpeed, setActionCooldown, buyItem, sellItem, saveToSlot, loadFromSlot, ...gameState } = state;
|
||||||
|
saveGame(slot, gameState);
|
||||||
|
},
|
||||||
|
|
||||||
|
loadFromSlot: (slot: number) => {
|
||||||
|
const savedState = loadGame(slot);
|
||||||
|
if (savedState) {
|
||||||
|
set(savedState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
29
src/utils/saveSystem.ts
Normal file
29
src/utils/saveSystem.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { GameState } from '../types';
|
||||||
|
|
||||||
|
const SAVE_SLOT_PREFIX = 'dionysian_idle_save_';
|
||||||
|
|
||||||
|
export const saveGame = (slot: number, state: GameState) => {
|
||||||
|
try {
|
||||||
|
const saveData = JSON.stringify(state);
|
||||||
|
localStorage.setItem(`${SAVE_SLOT_PREFIX}${slot}`, saveData);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to save game:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loadGame = (slot: number): GameState | null => {
|
||||||
|
try {
|
||||||
|
const saveData = localStorage.getItem(`${SAVE_SLOT_PREFIX}${slot}`);
|
||||||
|
if (!saveData) return null;
|
||||||
|
return JSON.parse(saveData);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load game:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hasSaveInSlot = (slot: number): boolean => {
|
||||||
|
return !!localStorage.getItem(`${SAVE_SLOT_PREFIX}${slot}`);
|
||||||
|
};
|
||||||
Loading…
Reference in a new issue