feat(creatures): add creature types, data, ECS components, and core systems
Phase 5.1-5.5: Creatures & Ecology foundation - 3 species data (Crystallid, Acidophile, Reagent) with real chemistry - ECS components: Creature, AI, Metabolism, LifeCycle - AI FSM system: idle → wander → feed → flee → attack - Metabolism: energy drain, feeding from resources, starvation damage - Life cycle: egg → youth → mature → aging → natural death - Population dynamics: counting, reproduction, initial spawning - Species registry with numeric/string ID lookup - 51 tests passing (272 total) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
126
src/creatures/types.ts
Normal file
126
src/creatures/types.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Creature Types — data definitions for the creature/ecology system
|
||||
*
|
||||
* Three species in Catalytic Wastes:
|
||||
* - Crystallids: slow, sturdy, eat minerals, excrete silicon
|
||||
* - Acidophiles: medium speed, eat minerals, excrete acid
|
||||
* - Reagents: fast, paired, predatory, explosive
|
||||
*/
|
||||
|
||||
/** Species identifier (stored as numeric ID in ECS components) */
|
||||
export enum SpeciesId {
|
||||
Crystallid = 0,
|
||||
Acidophile = 1,
|
||||
Reagent = 2,
|
||||
}
|
||||
|
||||
/** AI behavior state (FSM) */
|
||||
export enum AIState {
|
||||
Idle = 0,
|
||||
Wander = 1,
|
||||
Feed = 2,
|
||||
Flee = 3,
|
||||
Attack = 4,
|
||||
}
|
||||
|
||||
/** Life cycle stage */
|
||||
export enum LifeStage {
|
||||
Egg = 0,
|
||||
Youth = 1,
|
||||
Mature = 2,
|
||||
Aging = 3,
|
||||
}
|
||||
|
||||
/** Diet type — what a creature can feed on */
|
||||
export type DietType = 'mineral' | 'acid' | 'creature';
|
||||
|
||||
/** Species definition loaded from creatures.json */
|
||||
export interface SpeciesData {
|
||||
id: string;
|
||||
name: string;
|
||||
nameRu: string;
|
||||
speciesId: SpeciesId;
|
||||
description: string;
|
||||
descriptionRu: string;
|
||||
|
||||
/** Visual */
|
||||
color: string; // hex color string
|
||||
radius: number; // base radius in pixels
|
||||
radiusYouth: number; // smaller when young
|
||||
|
||||
/** Stats */
|
||||
health: number;
|
||||
speed: number; // pixels per second
|
||||
damage: number; // damage per attack
|
||||
armor: number; // damage reduction (0-1)
|
||||
|
||||
/** Metabolism */
|
||||
diet: DietType;
|
||||
dietTiles: string[]; // tile names this species feeds on
|
||||
excretionElement: number; // atomic number of excreted element (0 = none)
|
||||
energyMax: number; // max energy capacity
|
||||
energyPerFeed: number; // energy gained per feeding
|
||||
energyDrainPerSecond: number; // passive energy loss rate
|
||||
hungerThreshold: number; // below this → seek food (0-1 fraction of max)
|
||||
|
||||
/** Behavior */
|
||||
aggressionRadius: number; // distance to detect threats
|
||||
fleeRadius: number; // distance to start fleeing
|
||||
wanderRadius: number; // max wander distance from home
|
||||
attackRange: number; // melee attack range
|
||||
attackCooldown: number; // ms between attacks
|
||||
|
||||
/** Life cycle durations (ms) */
|
||||
eggDuration: number;
|
||||
youthDuration: number;
|
||||
matureDuration: number;
|
||||
agingDuration: number;
|
||||
|
||||
/** Reproduction */
|
||||
reproductionEnergy: number; // energy cost to reproduce
|
||||
offspringCount: number; // eggs per reproduction event
|
||||
|
||||
/** Population */
|
||||
maxPopulation: number; // per-species cap
|
||||
spawnWeight: number; // relative spawn density (0-1)
|
||||
preferredTiles: string[]; // tiles where this species spawns
|
||||
}
|
||||
|
||||
/** Runtime creature state (non-ECS, for string data lookup) */
|
||||
export interface CreatureInfo {
|
||||
speciesId: SpeciesId;
|
||||
speciesDataId: string; // key into species registry
|
||||
}
|
||||
|
||||
/** Creature species registry */
|
||||
export class SpeciesRegistry {
|
||||
private byId = new Map<string, SpeciesData>();
|
||||
private byNumericId = new Map<SpeciesId, SpeciesData>();
|
||||
|
||||
constructor(data: SpeciesData[]) {
|
||||
for (const species of data) {
|
||||
this.byId.set(species.id, species);
|
||||
this.byNumericId.set(species.speciesId, species);
|
||||
}
|
||||
}
|
||||
|
||||
/** Get species by string ID */
|
||||
get(id: string): SpeciesData | undefined {
|
||||
return this.byId.get(id);
|
||||
}
|
||||
|
||||
/** Get species by numeric ID (from ECS component) */
|
||||
getByNumericId(id: SpeciesId): SpeciesData | undefined {
|
||||
return this.byNumericId.get(id);
|
||||
}
|
||||
|
||||
/** Get all species */
|
||||
getAll(): SpeciesData[] {
|
||||
return [...this.byId.values()];
|
||||
}
|
||||
|
||||
/** Get species count */
|
||||
get count(): number {
|
||||
return this.byId.size;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user