From fc0da039fa1111d3fc5bfdc86c1f35e588aff93d Mon Sep 17 00:00:00 2001 From: Dustlint Date: Sun, 15 Mar 2026 19:26:12 +0100 Subject: [PATCH] pear can eat --- src/app/logic/chibi-behaviour/brain.ts | 5 +- .../chibi-behaviour/brains/aperio.brain.ts | 167 +++++++++++++----- .../interactions/interactions.component.ts | 6 +- 3 files changed, 128 insertions(+), 50 deletions(-) diff --git a/src/app/logic/chibi-behaviour/brain.ts b/src/app/logic/chibi-behaviour/brain.ts index 99ded85..69dd775 100644 --- a/src/app/logic/chibi-behaviour/brain.ts +++ b/src/app/logic/chibi-behaviour/brain.ts @@ -1,7 +1,6 @@ import { Chibi } from "../../types/chibi/chibi"; -import { EChibiInteraction } from "../../types/chibi/chibi-interaction"; -import { Food } from "../../types/food"; import { RandomService } from "../random.service"; +import { ChibiInteraction } from "./brains/aperio.brain"; export interface IBrain { @@ -12,5 +11,5 @@ export interface IBrain { exist(): void; // function which resolves all interactions - resolveInteraction(interaction: EChibiInteraction, item?: Food): void + resolveInteraction(interaction: ChibiInteraction): void } \ 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 2b83ebb..b35614c 100644 --- a/src/app/logic/chibi-behaviour/brains/aperio.brain.ts +++ b/src/app/logic/chibi-behaviour/brains/aperio.brain.ts @@ -1,27 +1,49 @@ import { Chibi } from "../../../types/chibi/chibi"; import { EChibiInteraction } from "../../../types/chibi/chibi-interaction"; -import { ChibiState, isState, STATE_EATING, STATE_GRUMBLING, STATE_IDLE, STATE_SLEEPING, STATES } from "../../../types/chibi/chibi-state"; +import { ChibiState, isState, STATE_AWAKE, STATE_EATING, STATE_GRUMBLING, STATE_IDLE, STATE_SLEEPING, STATES } from "../../../types/chibi/chibi-state"; import { EChibiStateName } from "../../../types/chibi/chibi-state-name"; import { Food } from "../../../types/food"; import { RandomOutcome, RandomService } from "../../random.service"; import { IBrain } from "../brain"; -type ResolutionFunction = (interaction: EChibiInteraction) => ChibiState; +export type ChibiInteraction = { + name: EChibiInteraction; + payload: T; +} + +type ResolutionFunction = (interaction: ChibiInteraction) => ChibiState; type InteractionRecord = Partial>; -const MAX_TIME_AWAKE: number = 3; +const MAX_TIME_AWAKE: number = 10; + +const HAPPINESS_FROM_SLEEP: number = 100; +const SADNESS_FROM_NEGLECT: number = 50; + +const MAX_DURATION_GRUMBLE: number = 1; +const MAX_DURATION_EATING: number = 1; export class Aperio implements IBrain { private randomService!: RandomService; private chibi!: Chibi; + + private readonly defaultState: EChibiStateName = EChibiStateName.Sleeping; + private previousState: EChibiStateName = this.defaultState; + private hasBeenAwakeFor: number = 0; - private state!: ChibiState; + private timeSinceLastInteraction: number = 0; + private timeInCurrentState: number = 0; + private lastConsumedFoods: string[] = []; + private preferredFoods: string[] = []; + + private state: ChibiState = STATES[this.defaultState]; private interactionMap: { [key in EChibiStateName]: InteractionRecord | undefined } = { [EChibiStateName.Sleeping]: { - [EChibiInteraction.WakeUp]: (interaction: EChibiInteraction): ChibiState => this.wakeUp(interaction), + [EChibiInteraction.WakeUp]: (interaction: ChibiInteraction): ChibiState => this.wakeUp(interaction), + }, + [EChibiStateName.Awake]: { + [EChibiInteraction.Feed]: (interaction: ChibiInteraction): ChibiState => this.eat(interaction), }, - [EChibiStateName.Awake]: undefined, [EChibiStateName.Snoring]: undefined, [EChibiStateName.Nightmare]: undefined, [EChibiStateName.Grumbling]: undefined, @@ -35,72 +57,123 @@ export class Aperio implements IBrain { [EChibiStateName.Tired]: undefined } - public readonly defaultState: EChibiStateName = EChibiStateName.Sleeping; - - //needed: some sort of legal interactions map - //uses stateNames as keys - //then submap the interactions - //behind every interaction is a dedicated function - init(chibi: Chibi, randomService: RandomService): void { this.randomService = randomService; this.chibi = chibi; this.state = STATES[chibi.state]; - console.log(this.wakeUp); } exist(): void { - console.log('Brain is braining'); - if (isState(this.state, EChibiStateName.Awake)) { - console.log('is awake'); - this.hasBeenAwakeFor++; - if (this.hasBeenAwakeFor > MAX_TIME_AWAKE) { - this.state = STATE_SLEEPING; - this.chibi.state = EChibiStateName.Sleeping; - this.hasBeenAwakeFor = 0; - } - } - this.chibi.state = this.state.name; + this.timeInCurrentState++; + this.resolveAwake(); + this.resolveSleeping(); + this.resolveGrumbling(); + this.resolveEating(); } - resolveInteraction(interaction: EChibiInteraction, item?: Food): void { - // reassign state based on resolving map - const resolution: ResolutionFunction | undefined = this.interactionMap[this.state.name]?.[interaction]; + resolveInteraction(interaction: ChibiInteraction): void { + this.timeSinceLastInteraction = 0; + const specificMatch: ResolutionFunction | undefined = this.interactionMap[this.state.name]?.[interaction.name]; + const awakeMatch: ResolutionFunction | undefined = this.interactionMap[EChibiStateName.Awake]?.[interaction.name]; + const asleepMatch: ResolutionFunction | undefined = this.interactionMap[EChibiStateName.Sleeping]?.[interaction.name]; + const resolution: ResolutionFunction | undefined = specificMatch || (this.isAwake() ? awakeMatch : asleepMatch); + console.log(`specific match: ${specificMatch}`); + console.log(`${this.chibi.name} should ${interaction.name} with payload: ${interaction.payload}`); if (resolution) { - this.state = resolution(interaction); + this.changeState(resolution(interaction)); } + } + + isAwake(): boolean { + return isState(this.state, EChibiStateName.Awake); + } + + // resolvers + // functions which auitomatically resolve based on the existence cycle + + resolveAwake(): void { + if (this.isAwake()) { + 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); + } + } + } + + increaseHappyness(increase: number): void { + console.log(`${this.chibi.name} happyness increases.`); + this.chibi.happyness = this.chibi.happyness + increase; + } + + saddenedByNeglect(neglectTime: number, sadness: number): void { + console.log(`${this.chibi.name} happyness decreases.`); + this.chibi.happyness = this.chibi.happyness - (neglectTime * sadness); + } + + resolveSleeping(): void { + if (isState(this.state, EChibiStateName.Sleeping)) { + console.log(`${this.chibi.name} is sleeping.`); + this.increaseHappyness(HAPPINESS_FROM_SLEEP); + const awakeChance = this.randomService.obtainRandom(2048); + if (awakeChance.matchesChance(1)) { + this.changeState(STATE_AWAKE); + } + } + } + + 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); + } + } + } + + 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]); + } + } + } + + private changeState(state: ChibiState): void { + this.previousState = this.state.name; + this.state = state; this.chibi.state = this.state.name; + this.timeInCurrentState = 0; } /* - pear mostly sleeps - visiting caethya will wake her up and go into lovey-dovey mode - she has a 1/2048 chance of waking up on her own - pears happyness goes up when she sleeps - pear never gets hungry - but she accepts foods she likes, which raise her happyness as long as the same food is not offered thrice in a row (except banana split) pears energy never goes down pear will accept fights and enjoys them pear will accept walks and enjoys them - pear will get sad if she is awake and you do not interact with her - pear gets offended if you suggest she go to sleep after any interaction she has a 1/4 chance of going to sleep */ - private wakeUp(interaction: EChibiInteraction): ChibiState { + // interaction functions + // functions which are triggered by user actions + + private wakeUp(interaction: ChibiInteraction): ChibiState { const wakeUpOutcome: RandomOutcome = this.randomService.obtainRandom(128); const willWakeUp: boolean = wakeUpOutcome.matchesChance(1); const willGrumble: boolean = wakeUpOutcome.matchesChance(12, 1); - console.log(wakeUpOutcome.random); - console.log(willWakeUp); - console.log(willGrumble); if (willWakeUp) { return STATE_IDLE; } else if (willGrumble) { @@ -109,10 +182,16 @@ export class Aperio implements IBrain { return STATE_SLEEPING; } - private resolveAwakeInteraction(interaction: EChibiInteraction, item?: Food): ChibiState { - if (EChibiInteraction.Feed) { + private eat(interaction: ChibiInteraction): ChibiState { + console.log(`${this.chibi.name} should eat ${interaction.payload.name}`); + const foodId = interaction.payload.id; + if (this.preferredFoods.includes(foodId)) { + this.lastConsumedFoods.push(foodId); + this.increaseHappyness(100); return STATE_EATING; + } else { + } - return STATE_IDLE; + return STATE_EATING; } }; \ No newline at end of file diff --git a/src/app/pages/interactions/interactions.component.ts b/src/app/pages/interactions/interactions.component.ts index 70f85e3..7558df2 100644 --- a/src/app/pages/interactions/interactions.component.ts +++ b/src/app/pages/interactions/interactions.component.ts @@ -13,8 +13,8 @@ import { BRAIN_MAP } from '../../logic/chibi-behaviour/brain-map'; import { TranslateableComponent } from '../../components/translateable.component'; import { Food } from '../../types/food'; import { interval } from 'rxjs'; -import { ChibiState, STATES } from '../../types/chibi/chibi-state'; import { RandomService } from '../../logic/random.service'; +import { ChibiInteraction } from '../../logic/chibi-behaviour/brains/aperio.brain'; enum EInteractionMenuState { Neutral, @@ -22,7 +22,7 @@ enum EInteractionMenuState { Inventory } -const THINKING_INTERVAL: number = 10000; +const THINKING_INTERVAL: number = 2000; @Component({ selector: 'ff-interactions', @@ -61,7 +61,7 @@ export class InteractionsComponent extends TranslateableComponent { public interact(interaction: EChibiInteraction, item?: Food): void { console.log(`${interaction} ${this.chibi().name} and item ${item}`); - this.brain.resolveInteraction(interaction, item); + this.brain.resolveInteraction({ name: interaction, payload: item } as ChibiInteraction); } public openFoodPantry(): void {