feat: 实现游戏核心功能与前端界面

- 添加游戏核心系统:战斗、任务、日志、随机数生成等
- 实现前端主界面、HUD、底部导航和各类卡片组件
- 添加用户认证系统与游戏存档持久化
- 配置项目基础架构与开发环境
- 补充文档说明与Docker部署支持
This commit is contained in:
2026-04-28 22:16:58 +08:00
parent 2e1b58bada
commit e783e6e533
124 changed files with 9759 additions and 1 deletions
+45
View File
@@ -0,0 +1,45 @@
import { applyGameAction, buildGameView, createNewGameState } from '@tinywaste/game-core';
import { describe, expect, it } from 'vitest';
import { gameContent } from './index';
describe('TinyWaste gameplay loop', () => {
it('creates a new survivor at the shelter with a starter loadout', () => {
const state = createNewGameState(gameContent, '测试幸存者');
expect(state.player.placeId).toBe('home');
expect(state.player.inventory.some((entry) => entry.itemId === 'shiv')).toBe(true);
expect(state.player.quests.q_tutorial_water.state).toBe('active');
});
it('collects rain water and advances time when performing the base scavenging action', () => {
const state = createNewGameState(gameContent, '测试幸存者');
const initialWater = state.player.inventory.find((entry) => entry.itemId === 'water_dirty')?.count ?? 0;
const initialMinutes = state.world.time.totalMinutes;
const result = applyGameAction(state, gameContent, {
type: 'perform-action',
actionId: 'home_rain_barrel',
});
const currentWater = result.state.player.inventory.find((entry) => entry.itemId === 'water_dirty')?.count ?? 0;
expect(result.state.world.time.totalMinutes).toBeGreaterThan(initialMinutes);
expect(currentWater).toBeGreaterThan(initialWater);
expect(result.state.world.logs.at(-1)?.message).toContain('浑水');
});
it('updates the current place after travel and exposes the new location in the game view', () => {
const state = createNewGameState(gameContent, '测试幸存者');
const initialView = buildGameView(state, gameContent);
const result = applyGameAction(state, gameContent, {
type: 'travel',
toPlaceId: initialView.map.edges[0]?.to ?? 'roadside',
});
const view = buildGameView(result.state, gameContent);
expect(result.state.player.placeId).toBe('roadside');
expect(view.header.placeName).toBe('近郊土路');
expect(view.map.places.find((place) => place.current)?.id).toBe('roadside');
});
});
File diff suppressed because it is too large Load Diff