auto resolve existance

This commit is contained in:
2026-03-30 16:10:31 +02:00
parent 5858e2808d
commit d2435eee7f
5 changed files with 82 additions and 55 deletions

View File

@@ -1,4 +1,4 @@
<div class="bg-red-100 w-full max-w-[1024px] aspect-square"> <div class="bg-red-100 w-full max-w-[1024px] aspect-square">
<div class="text-lg text-primary-700">{{ chibi().state }}</div> <div class="text-lg text-primary-700">{{ chibi().currentStateName }}</div>
<canvas class="w-full h-full" #canvas></canvas> <canvas class="w-full h-full" #canvas></canvas>
</div> </div>

View File

@@ -29,7 +29,7 @@ export const CHIBIS: Chibi[] = [
constitution: 1000, constitution: 1000,
power: 1000, power: 1000,
maintenanceCals: 0, maintenanceCals: 0,
state: EChibiStateName.Sleeping currentStateName: EChibiStateName.Sleeping
}, },
{ {
id: '238df3e7-3003-4471-91f5-a7ecf3151e18' as ChibiId, id: '238df3e7-3003-4471-91f5-a7ecf3151e18' as ChibiId,
@@ -48,6 +48,6 @@ export const CHIBIS: Chibi[] = [
constitution: 1000, constitution: 1000,
power: 1000, power: 1000,
maintenanceCals: 0, maintenanceCals: 0,
state: EChibiStateName.Idle currentStateName: EChibiStateName.Idle
}, },
]; ];

View File

@@ -13,8 +13,11 @@ export type ChibiInteraction<T = null> = {
payload: T; payload: T;
} }
type ResolutionFunction = (interaction: ChibiInteraction<any>) => ChibiState; type InteractionResolutionFunction = (interaction: ChibiInteraction<any>) => ChibiState;
type InteractionRecord = Partial<Record<EChibiInteraction, ResolutionFunction>>; type InteractionRecord = Partial<Record<EChibiInteraction, InteractionResolutionFunction>>;
type ResolutionFunction = () => ChibiState | undefined;
type ResolutionMap = { [key in EChibiStateName]: ResolutionFunction | undefined }
const MAX_TIME_AWAKE: number = 10; const MAX_TIME_AWAKE: number = 10;
@@ -38,7 +41,6 @@ export class Aperio implements IBrain {
private lastConsumedFoods: string[] = []; private lastConsumedFoods: string[] = [];
private preferredFoods: string[] = []; private preferredFoods: string[] = [];
private state: ChibiState = STATES[this.defaultState];
private interactionMap: InteractionMap = { private interactionMap: InteractionMap = {
[EChibiStateName.Sleeping]: { [EChibiStateName.Sleeping]: {
[EChibiInteraction.WakeUp]: (interaction: ChibiInteraction): ChibiState => this.wakeUp(interaction), [EChibiInteraction.WakeUp]: (interaction: ChibiInteraction): ChibiState => this.wakeUp(interaction),
@@ -58,27 +60,45 @@ export class Aperio implements IBrain {
[EChibiStateName.Depressed]: undefined, [EChibiStateName.Depressed]: undefined,
[EChibiStateName.Tired]: undefined [EChibiStateName.Tired]: undefined
} }
private resolutionMap: ResolutionMap = {
[EChibiStateName.Sleeping]: (): ChibiState | undefined => this.resolveSleeping(),
[EChibiStateName.Awake]: (): ChibiState | undefined => this.resolveAwake(),
[EChibiStateName.Snoring]: undefined,
[EChibiStateName.Nightmare]: undefined,
[EChibiStateName.Grumbling]: (): ChibiState | undefined => this.resolveGrumbling(),
[EChibiStateName.Bored]: undefined,
[EChibiStateName.Idle]: undefined,
[EChibiStateName.Exited]: undefined,
[EChibiStateName.Fighting]: undefined,
[EChibiStateName.Eating]: (): ChibiState | undefined => this.resolveEating(),
[EChibiStateName.Hungry]: undefined,
[EChibiStateName.Depressed]: undefined,
[EChibiStateName.Tired]: undefined
}
get state(): ChibiState {
return STATES[this.chibi.currentStateName];
}
init(chibi: Chibi, randomService: RandomService): void { init(chibi: Chibi, randomService: RandomService): void {
this.randomService = randomService; this.randomService = randomService;
this.chibi = chibi; this.chibi = chibi;
this.state = STATES[chibi.state];
} }
exist(): void { exist(): void {
this.timeInCurrentState++; this.timeInCurrentState++;
//this sucks, resolve should be generic const resolution = this.matchResolution(this.resolutionMap, STATES[this.chibi.currentStateName]);
//stuff into an existMap which contains the resolve functions if (resolution) {
//then find correct function to execute the same way we do for interactions const newState = resolution();
this.resolveAwake(); if (newState && newState != STATES[this.chibi.currentStateName]) {
this.resolveSleeping(); this.changeState(newState);
this.resolveGrumbling(); }
this.resolveEating(); }
} }
resolveInteraction(interaction: ChibiInteraction): void { resolveInteraction(interaction: ChibiInteraction): void {
this.timeSinceLastInteraction = 0; this.timeSinceLastInteraction = 0;
const resolution = this.matchInteraction(this.interactionMap, interaction.name, STATES[this.chibi.state]); const resolution = this.matchInteraction(this.interactionMap, interaction.name, STATES[this.chibi.currentStateName]);
console.log('resolution', resolution); console.log('resolution', resolution);
console.log(`${this.chibi.name} should ${interaction.name} with payload: ${interaction.payload}`); console.log(`${this.chibi.name} should ${interaction.name} with payload: ${interaction.payload}`);
if (resolution) { if (resolution) {
@@ -90,7 +110,7 @@ export class Aperio implements IBrain {
return isState(this.state, EChibiStateName.Awake); return isState(this.state, EChibiStateName.Awake);
} }
matchInteraction(map: InteractionMap, interaction: EChibiInteraction, state: ChibiState): ResolutionFunction | undefined { matchInteraction(map: InteractionMap, interaction: EChibiInteraction, state: ChibiState): InteractionResolutionFunction | undefined {
const directMatch = map?.[state.name]?.[interaction]; const directMatch = map?.[state.name]?.[interaction];
if (directMatch) { if (directMatch) {
return directMatch; return directMatch;
@@ -101,53 +121,61 @@ export class Aperio implements IBrain {
return undefined; return undefined;
} }
matchResolution(map: ResolutionMap, state: ChibiState): ResolutionFunction | undefined {
const directMatch = map?.[state.name];
if (directMatch) {
return directMatch;
}
if (state.parent) {
return this.matchResolution(map, state.parent);
}
return undefined;
}
// resolvers // resolvers
// functions which auitomatically resolve based on the existence cycle // functions which automatically resolve based on the existence cycle
resolveAwake(): void { resolveAwake(): ChibiState | undefined {
if (this.isAwake()) { console.log(`${this.chibi.name} is awake.`);
console.log(`${this.chibi.name} is awake.`); this.timeSinceLastInteraction++;
this.timeSinceLastInteraction++; this.hasBeenAwakeFor++;
this.hasBeenAwakeFor++;
if (this.timeInCurrentState % 10 === 0) { if (this.timeInCurrentState % 10 === 0) {
this.saddenedByNeglect(this.timeSinceLastInteraction, SADNESS_FROM_NEGLECT); this.saddenedByNeglect(this.timeSinceLastInteraction, SADNESS_FROM_NEGLECT);
}
if (this.hasBeenAwakeFor > MAX_TIME_AWAKE) {
this.changeState(STATE_SLEEPING);
}
} }
if (this.hasBeenAwakeFor > MAX_TIME_AWAKE) {
return STATE_SLEEPING;
}
return undefined;
} }
resolveSleeping(): void { resolveSleeping(): ChibiState | undefined {
if (isState(this.state, EChibiStateName.Sleeping)) { console.log(`${this.chibi.name} is sleeping.`);
console.log(`${this.chibi.name} is sleeping.`); this.hasBeenAwakeFor = 0;
this.hasBeenAwakeFor = 0; this.increaseHappyness(HAPPINESS_FROM_SLEEP);
this.increaseHappyness(HAPPINESS_FROM_SLEEP); const awakeChance = this.randomService.obtainRandom(2048);
const awakeChance = this.randomService.obtainRandom(2048); if (awakeChance.matchesChance(1)) {
if (awakeChance.matchesChance(1)) { return STATE_AWAKE;
this.changeState(STATE_AWAKE);
}
} }
return undefined;
} }
resolveGrumbling(): void { resolveGrumbling(): ChibiState | undefined {
if (isState(this.state, EChibiStateName.Grumbling)) { console.log(`${this.chibi.name} is grumbling. ${this.timeInCurrentState}`);
console.log(`${this.chibi.name} is grumbling.`); if (this.timeInCurrentState > MAX_DURATION_GRUMBLE) {
if (this.timeInCurrentState > MAX_DURATION_GRUMBLE) { return STATE_SLEEPING;
this.changeState(STATE_SLEEPING);
}
} }
return undefined;
} }
resolveEating(): void { resolveEating(): ChibiState | undefined {
if (isState(this.state, EChibiStateName.Eating)) { console.log(`${this.chibi.name} is eating. ${this.timeInCurrentState}`);
console.log(`${this.chibi.name} is eating.`); if (this.timeInCurrentState > MAX_DURATION_EATING) {
if (this.timeInCurrentState > MAX_DURATION_EATING) { return STATE_IDLE;
this.changeState(STATES[this.previousState]);
}
} }
return undefined;
} }
@@ -163,8 +191,7 @@ export class Aperio implements IBrain {
private changeState(state: ChibiState): void { private changeState(state: ChibiState): void {
this.previousState = this.state.name; this.previousState = this.state.name;
this.state = state; this.chibi.currentStateName = state.name;
this.chibi.state = this.state.name;
this.timeInCurrentState = 0; this.timeInCurrentState = 0;
} }

View File

@@ -70,7 +70,7 @@ export class InteractionsComponent extends TranslateableComponent implements OnD
} }
public isAwake(): boolean { public isAwake(): boolean {
return isState(STATES[this.chibi().state], EChibiStateName.Awake); return isState(STATES[this.chibi().currentStateName], EChibiStateName.Awake);
} }
public interact(interaction: EChibiInteraction, item?: Food): void { public interact(interaction: EChibiInteraction, item?: Food): void {
@@ -78,7 +78,7 @@ export class InteractionsComponent extends TranslateableComponent implements OnD
this.brain.resolveInteraction({ name: interaction, payload: item } as ChibiInteraction<Food>); this.brain.resolveInteraction({ name: interaction, payload: item } as ChibiInteraction<Food>);
} }
public openFoodPantry(): void { public openFoodPantry(): void {
this.interactionMenuState.set(EInteractionMenuState.Pantry); this.interactionMenuState.set(EInteractionMenuState.Pantry);
} }

View File

@@ -19,7 +19,7 @@ export type Chibi = {
spritePath: string; spritePath: string;
experience: number; experience: number;
unlocked: boolean; unlocked: boolean;
state: EChibiStateName; currentStateName: EChibiStateName;
} & ChibiWellnessStats & ChibiTraits; } & ChibiWellnessStats & ChibiTraits;
export type ChibiWellnessStats = { export type ChibiWellnessStats = {