- Gefällter Baum → 1–2 tree_seed im Stockpile (zufällig) - Neues Gebäude forester_hut (50 wood): Log-Hütten-Grafik, Klick öffnet Info-Panel - Zonenmarkierung: Edit-Zone-Tool, Radius 5 Tiles, halbtransparente Overlay-Anzeige - Neuer JobType 'forester': Nisse pflanzen Setzlinge auf markierten Zonen-Tiles - Chop-Priorisierung: Zonen-Bäume werden vor natürlichen Bäumen gefällt - Nisse-Panel & Info-Panel zeigen forester-Priorität-Button Closes #25 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
173 lines
5.3 KiB
TypeScript
173 lines
5.3 KiB
TypeScript
export enum TileType {
|
|
DEEP_WATER = 0,
|
|
SHALLOW_WATER = 1,
|
|
SAND = 2,
|
|
GRASS = 3,
|
|
DARK_GRASS = 4,
|
|
FOREST = 5,
|
|
ROCK = 6,
|
|
FLOOR = 7,
|
|
WALL = 8,
|
|
TILLED_SOIL = 9,
|
|
WATERED_SOIL = 10,
|
|
}
|
|
|
|
/** Tiles that are always impassable regardless of what is on them. */
|
|
export const IMPASSABLE = new Set<number>([
|
|
TileType.DEEP_WATER,
|
|
TileType.SHALLOW_WATER,
|
|
TileType.WALL,
|
|
])
|
|
|
|
/**
|
|
* Terrain tiles whose passability depends on whether a resource
|
|
* (tree or rock) is currently placed on them.
|
|
* An empty FOREST tile is walkable forest floor; a ROCK tile without a
|
|
* rock resource is just rocky ground.
|
|
*/
|
|
export const RESOURCE_TERRAIN = new Set<number>([TileType.FOREST, TileType.ROCK])
|
|
|
|
/** Tiles on which tree seedlings may be planted. */
|
|
export const PLANTABLE_TILES = new Set<TileType>([TileType.GRASS, TileType.DARK_GRASS])
|
|
|
|
export type ItemId = 'wood' | 'stone' | 'wheat_seed' | 'carrot_seed' | 'wheat' | 'carrot' | 'tree_seed'
|
|
|
|
export type BuildingType = 'floor' | 'wall' | 'chest' | 'bed' | 'stockpile_zone' | 'forester_hut'
|
|
|
|
export type CropKind = 'wheat' | 'carrot'
|
|
|
|
export type JobType = 'chop' | 'mine' | 'farm' | 'forester'
|
|
|
|
export type AIState = 'idle' | 'walking' | 'working' | 'sleeping'
|
|
|
|
export interface JobPriorities {
|
|
chop: number // 0 = disabled, 1 = highest, 4 = lowest
|
|
mine: number
|
|
farm: number
|
|
forester: number // plant tree seedlings in forester zones
|
|
}
|
|
|
|
export interface VillagerJob {
|
|
type: JobType
|
|
targetId: string
|
|
tileX: number
|
|
tileY: number
|
|
carrying: Partial<Record<ItemId, number>>
|
|
}
|
|
|
|
export interface VillagerState {
|
|
id: string
|
|
name: string
|
|
x: number
|
|
y: number
|
|
bedId: string | null
|
|
job: VillagerJob | null
|
|
priorities: JobPriorities
|
|
energy: number
|
|
aiState: AIState
|
|
}
|
|
|
|
export interface ResourceNodeState {
|
|
id: string
|
|
tileX: number
|
|
tileY: number
|
|
kind: 'tree' | 'rock'
|
|
hp: number
|
|
}
|
|
|
|
export interface BuildingState {
|
|
id: string
|
|
tileX: number
|
|
tileY: number
|
|
kind: BuildingType
|
|
ownerId: string
|
|
}
|
|
|
|
export interface CropState {
|
|
id: string
|
|
tileX: number
|
|
tileY: number
|
|
kind: CropKind
|
|
stage: number
|
|
maxStage: number
|
|
stageTimerMs: number
|
|
watered: boolean
|
|
}
|
|
|
|
export interface PlayerState {
|
|
id: string
|
|
x: number
|
|
y: number
|
|
inventory: Partial<Record<ItemId, number>>
|
|
}
|
|
|
|
export interface TreeSeedlingState {
|
|
id: string
|
|
tileX: number
|
|
tileY: number
|
|
/** Growth stage: 0 = sprout, 1 = sapling, 2 = mature (converts to resource). */
|
|
stage: number
|
|
/** Time remaining until next stage advance, in milliseconds. */
|
|
stageTimerMs: number
|
|
/** The tile type that was under the seedling when planted (GRASS or DARK_GRASS). */
|
|
underlyingTile: TileType
|
|
}
|
|
|
|
/**
|
|
* The set of tiles assigned to one forester hut's planting zone.
|
|
* Tiles are stored as "tileX,tileY" key strings.
|
|
*/
|
|
export interface ForesterZoneState {
|
|
buildingId: string
|
|
/** Tile keys "tileX,tileY" that the player has marked for planting. */
|
|
tiles: string[]
|
|
}
|
|
|
|
export interface WorldState {
|
|
seed: number
|
|
tiles: number[]
|
|
resources: Record<string, ResourceNodeState>
|
|
buildings: Record<string, BuildingState>
|
|
crops: Record<string, CropState>
|
|
villagers: Record<string, VillagerState>
|
|
stockpile: Partial<Record<ItemId, number>>
|
|
/** Planted tree seedlings, keyed by ID. */
|
|
treeSeedlings: Record<string, TreeSeedlingState>
|
|
/**
|
|
* Recovery timers for DARK_GRASS tiles, keyed by "tileX,tileY".
|
|
* Value is remaining milliseconds until the tile reverts to GRASS.
|
|
*/
|
|
tileRecovery: Record<string, number>
|
|
/** Forester zone definitions, keyed by forester_hut building ID. */
|
|
foresterZones: Record<string, ForesterZoneState>
|
|
}
|
|
|
|
export interface GameStateData {
|
|
version: number
|
|
world: WorldState
|
|
player: PlayerState
|
|
}
|
|
|
|
export type GameAction =
|
|
| { type: 'PLAYER_MOVE'; x: number; y: number }
|
|
| { type: 'HARVEST_RESOURCE'; resourceId: string; rewards: Partial<Record<ItemId, number>> }
|
|
| { type: 'CHANGE_TILE'; tileX: number; tileY: number; tile: TileType }
|
|
| { type: 'PLACE_BUILDING'; building: BuildingState; costs: Partial<Record<ItemId, number>> }
|
|
| { type: 'REMOVE_BUILDING'; buildingId: string }
|
|
| { type: 'ADD_ITEMS'; items: Partial<Record<ItemId, number>> }
|
|
| { type: 'PLANT_CROP'; crop: CropState; seedItem: ItemId }
|
|
| { type: 'WATER_CROP'; cropId: string }
|
|
| { type: 'HARVEST_CROP'; cropId: string; rewards: Partial<Record<ItemId, number>> }
|
|
| { type: 'SPAWN_VILLAGER'; villager: VillagerState }
|
|
| { type: 'VILLAGER_SET_JOB'; villagerId: string; job: VillagerJob | null }
|
|
| { type: 'VILLAGER_SET_AI'; villagerId: string; aiState: AIState }
|
|
| { type: 'VILLAGER_HARVEST_RESOURCE'; villagerId: string; resourceId: string }
|
|
| { type: 'VILLAGER_HARVEST_CROP'; villagerId: string; cropId: string }
|
|
| { type: 'VILLAGER_DEPOSIT'; villagerId: string }
|
|
| { type: 'UPDATE_PRIORITIES'; villagerId: string; priorities: JobPriorities }
|
|
| { type: 'PLANT_TREE_SEED'; seedling: TreeSeedlingState }
|
|
| { type: 'REMOVE_TREE_SEEDLING'; seedlingId: string }
|
|
| { type: 'SPAWN_RESOURCE'; resource: ResourceNodeState }
|
|
| { type: 'TILE_RECOVERY_START'; tileX: number; tileY: number }
|
|
| { type: 'FORESTER_ZONE_UPDATE'; buildingId: string; tiles: string[] }
|