diff --git a/src/app/components/interaction-canvas/interaction-canvas.component.html b/src/app/components/interaction-canvas/interaction-canvas.component.html index d0490da..897a351 100644 --- a/src/app/components/interaction-canvas/interaction-canvas.component.html +++ b/src/app/components/interaction-canvas/interaction-canvas.component.html @@ -1,4 +1,4 @@
-
{{ chibi().state }}
+
{{ chibi().currentStateName }}
diff --git a/src/app/dexie/entities/chibis.ts b/src/app/dexie/entities/chibis.ts index 1034dba..a0b33d2 100644 --- a/src/app/dexie/entities/chibis.ts +++ b/src/app/dexie/entities/chibis.ts @@ -29,7 +29,7 @@ export const CHIBIS: Chibi[] = [ constitution: 1000, power: 1000, maintenanceCals: 0, - state: EChibiStateName.Sleeping + currentStateName: EChibiStateName.Sleeping }, { id: '238df3e7-3003-4471-91f5-a7ecf3151e18' as ChibiId, @@ -48,6 +48,6 @@ export const CHIBIS: Chibi[] = [ constitution: 1000, power: 1000, maintenanceCals: 0, - state: EChibiStateName.Idle + currentStateName: EChibiStateName.Idle }, ]; \ No newline at end of file diff --git a/src/app/logic/chibi-behaviour/brains/aperio.brain.ts b/src/app/logic/chibi-behaviour/brains/aperio.brain.ts index b6b5349..575a78a 100644 --- a/src/app/logic/chibi-behaviour/brains/aperio.brain.ts +++ b/src/app/logic/chibi-behaviour/brains/aperio.brain.ts @@ -13,8 +13,11 @@ export type ChibiInteraction = { payload: T; } -type ResolutionFunction = (interaction: ChibiInteraction) => ChibiState; -type InteractionRecord = Partial>; +type InteractionResolutionFunction = (interaction: ChibiInteraction) => ChibiState; +type InteractionRecord = Partial>; + +type ResolutionFunction = () => ChibiState | undefined; +type ResolutionMap = { [key in EChibiStateName]: ResolutionFunction | undefined } const MAX_TIME_AWAKE: number = 10; @@ -38,7 +41,6 @@ export class Aperio implements IBrain { private lastConsumedFoods: string[] = []; private preferredFoods: string[] = []; - private state: ChibiState = STATES[this.defaultState]; private interactionMap: InteractionMap = { [EChibiStateName.Sleeping]: { [EChibiInteraction.WakeUp]: (interaction: ChibiInteraction): ChibiState => this.wakeUp(interaction), @@ -58,27 +60,45 @@ export class Aperio implements IBrain { [EChibiStateName.Depressed]: 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 { this.randomService = randomService; this.chibi = chibi; - this.state = STATES[chibi.state]; } exist(): void { this.timeInCurrentState++; - //this sucks, resolve should be generic - //stuff into an existMap which contains the resolve functions - //then find correct function to execute the same way we do for interactions - this.resolveAwake(); - this.resolveSleeping(); - this.resolveGrumbling(); - this.resolveEating(); + const resolution = this.matchResolution(this.resolutionMap, STATES[this.chibi.currentStateName]); + if (resolution) { + const newState = resolution(); + if (newState && newState != STATES[this.chibi.currentStateName]) { + this.changeState(newState); + } + } } resolveInteraction(interaction: ChibiInteraction): void { 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(`${this.chibi.name} should ${interaction.name} with payload: ${interaction.payload}`); if (resolution) { @@ -90,7 +110,7 @@ export class Aperio implements IBrain { 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]; if (directMatch) { return directMatch; @@ -101,53 +121,61 @@ export class Aperio implements IBrain { 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 - // functions which auitomatically resolve based on the existence cycle + // functions which automatically resolve based on the existence cycle - resolveAwake(): void { - if (this.isAwake()) { - console.log(`${this.chibi.name} is awake.`); - this.timeSinceLastInteraction++; - this.hasBeenAwakeFor++; + resolveAwake(): ChibiState | undefined { + console.log(`${this.chibi.name} is awake.`); + this.timeSinceLastInteraction++; + this.hasBeenAwakeFor++; - if (this.timeInCurrentState % 10 === 0) { - this.saddenedByNeglect(this.timeSinceLastInteraction, SADNESS_FROM_NEGLECT); - } - - if (this.hasBeenAwakeFor > MAX_TIME_AWAKE) { - this.changeState(STATE_SLEEPING); - } + if (this.timeInCurrentState % 10 === 0) { + this.saddenedByNeglect(this.timeSinceLastInteraction, SADNESS_FROM_NEGLECT); } + + if (this.hasBeenAwakeFor > MAX_TIME_AWAKE) { + return STATE_SLEEPING; + } + return undefined; } - resolveSleeping(): void { - if (isState(this.state, EChibiStateName.Sleeping)) { - console.log(`${this.chibi.name} is sleeping.`); - this.hasBeenAwakeFor = 0; - this.increaseHappyness(HAPPINESS_FROM_SLEEP); - const awakeChance = this.randomService.obtainRandom(2048); - if (awakeChance.matchesChance(1)) { - this.changeState(STATE_AWAKE); - } + resolveSleeping(): ChibiState | undefined { + console.log(`${this.chibi.name} is sleeping.`); + this.hasBeenAwakeFor = 0; + this.increaseHappyness(HAPPINESS_FROM_SLEEP); + const awakeChance = this.randomService.obtainRandom(2048); + if (awakeChance.matchesChance(1)) { + return STATE_AWAKE; } + return undefined; } - resolveGrumbling(): void { - if (isState(this.state, EChibiStateName.Grumbling)) { - console.log(`${this.chibi.name} is grumbling.`); - if (this.timeInCurrentState > MAX_DURATION_GRUMBLE) { - this.changeState(STATE_SLEEPING); - } + resolveGrumbling(): ChibiState | undefined { + console.log(`${this.chibi.name} is grumbling. ${this.timeInCurrentState}`); + if (this.timeInCurrentState > MAX_DURATION_GRUMBLE) { + return STATE_SLEEPING; } + + return undefined; } - resolveEating(): void { - if (isState(this.state, EChibiStateName.Eating)) { - console.log(`${this.chibi.name} is eating.`); - if (this.timeInCurrentState > MAX_DURATION_EATING) { - this.changeState(STATES[this.previousState]); - } + resolveEating(): ChibiState | undefined { + console.log(`${this.chibi.name} is eating. ${this.timeInCurrentState}`); + if (this.timeInCurrentState > MAX_DURATION_EATING) { + return STATE_IDLE; } + return undefined; } @@ -163,8 +191,7 @@ export class Aperio implements IBrain { private changeState(state: ChibiState): void { this.previousState = this.state.name; - this.state = state; - this.chibi.state = this.state.name; + this.chibi.currentStateName = state.name; this.timeInCurrentState = 0; } diff --git a/src/app/pages/interactions/interactions.component.ts b/src/app/pages/interactions/interactions.component.ts index 99d17de..938fbdd 100644 --- a/src/app/pages/interactions/interactions.component.ts +++ b/src/app/pages/interactions/interactions.component.ts @@ -70,7 +70,7 @@ export class InteractionsComponent extends TranslateableComponent implements OnD } 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 { @@ -78,7 +78,7 @@ export class InteractionsComponent extends TranslateableComponent implements OnD this.brain.resolveInteraction({ name: interaction, payload: item } as ChibiInteraction); } - + public openFoodPantry(): void { this.interactionMenuState.set(EInteractionMenuState.Pantry); } diff --git a/src/app/types/chibi/chibi.ts b/src/app/types/chibi/chibi.ts index a237bb4..e3568e9 100644 --- a/src/app/types/chibi/chibi.ts +++ b/src/app/types/chibi/chibi.ts @@ -19,7 +19,7 @@ export type Chibi = { spritePath: string; experience: number; unlocked: boolean; - state: EChibiStateName; + currentStateName: EChibiStateName; } & ChibiWellnessStats & ChibiTraits; export type ChibiWellnessStats = {