Files
forgotten-friends/src/app/logic/chibi-behaviour/brains/aperio.brain.ts
2026-03-30 16:31:19 +02:00

169 lines
6.3 KiB
TypeScript

import { EChibiInteraction } from "../../../types/chibi/chibi-interaction";
import { ChibiState, STATE_AWAKE, STATE_EATING, STATE_GRUMBLING, STATE_IDLE, STATE_SLEEPING } from "../../../types/chibi/chibi-state";
import { EChibiStateName } from "../../../types/chibi/chibi-state-name";
import { Food } from "../../../types/food";
import { RandomOutcome, } from "../../random.service";
import { BasicBrain, ChibiInteraction, InteractionMap, ResolutionMap } from "../basic.brain";
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 extends BasicBrain {
private lastConsumedFoods: string[] = [];
private preferredFoods: string[] = [];
protected override interactionMap: InteractionMap = {
[EChibiStateName.Sleeping]: {
[EChibiInteraction.WakeUp]: (interaction: ChibiInteraction): ChibiState => this.wakeUp(interaction),
},
[EChibiStateName.Awake]: {
[EChibiInteraction.Feed]: (interaction: ChibiInteraction<Food>): ChibiState => this.feedTo(interaction),
},
[EChibiStateName.Snoring]: undefined,
[EChibiStateName.Nightmare]: undefined,
[EChibiStateName.Grumbling]: undefined,
[EChibiStateName.Bored]: undefined,
[EChibiStateName.Idle]: undefined,
[EChibiStateName.Exited]: undefined,
[EChibiStateName.Fighting]: undefined,
[EChibiStateName.Eating]: undefined,
[EChibiStateName.Hungry]: undefined,
[EChibiStateName.Depressed]: undefined,
[EChibiStateName.Tired]: undefined
}
protected override 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
}
// resolvers
// functions which automatically resolve based on the existence cycle
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) {
return STATE_SLEEPING;
}
return undefined;
}
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(): ChibiState | undefined {
console.log(`${this.chibi.name} is grumbling. ${this.timeInCurrentState}`);
if (this.timeInCurrentState > MAX_DURATION_GRUMBLE) {
return STATE_SLEEPING;
}
return undefined;
}
resolveEating(): ChibiState | undefined {
console.log(`${this.chibi.name} is eating. ${this.timeInCurrentState}`);
if (this.timeInCurrentState > MAX_DURATION_EATING) {
return STATE_IDLE;
}
return undefined;
}
private increaseHappyness(increase: number): void {
console.log(`${this.chibi.name} happyness increases.`);
this.chibi.happyness.current = this.chibi.happyness.current + increase;
}
private saddenedByNeglect(neglectTime: number, sadness: number): void {
console.log(`${this.chibi.name} happyness decreases.`);
this.chibi.happyness.current = this.chibi.happyness.current - (neglectTime * sadness);
}
/*
visiting caethya will wake her up and go into lovey-dovey mode
pears energy never goes down
pear will accept fights and enjoys them
pear will accept walks and enjoys them
pear gets offended if you suggest she go to sleep
after any interaction she has a 1/4 chance of going to sleep
*/
// 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);
if (willWakeUp) {
return STATE_IDLE;
} else if (willGrumble) {
return STATE_GRUMBLING;
}
return this.state;
}
private feedTo(interaction: ChibiInteraction<Food>): ChibiState {
console.log(`${this.chibi.name} should eat ${interaction.payload.name}`);
const foodId = interaction.payload.id;
if (this.preferredFoods.includes(foodId)) {
this.eat(interaction.payload);
return STATE_EATING;
} else if (this.lastConsumedFoods[0] === foodId && this.lastConsumedFoods[1] === foodId && this.lastConsumedFoods[2] === foodId) {
console.log(`${this.chibi.name} refuses to eat another ${interaction.payload.name}!`);
return this.state;
}
this.eat(interaction.payload);
return STATE_EATING;
}
private eat(food: Food): void {
this.addToLastEatenFoods(food.id);
this.increaseHappyness(100);
}
private addToLastEatenFoods(foodId: string): void {
if (this.lastConsumedFoods.length < 3) {
this.lastConsumedFoods.push(foodId);
} else {
this.lastConsumedFoods = this.lastConsumedFoods.slice(1, 3);
this.lastConsumedFoods.push(foodId);
}
console.log(this.lastConsumedFoods);
}
};