basic brain
This commit is contained in:
91
src/app/logic/chibi-behaviour/basic.brain.ts
Normal file
91
src/app/logic/chibi-behaviour/basic.brain.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { Chibi } from "../../types/chibi/chibi";
|
||||
import { EChibiInteraction } from "../../types/chibi/chibi-interaction";
|
||||
import { ChibiState, STATES } from "../../types/chibi/chibi-state";
|
||||
import { EChibiStateName } from "../../types/chibi/chibi-state-name";
|
||||
import { RandomService } from "../random.service";
|
||||
import { IBrain } from "./brain";
|
||||
|
||||
export type InteractionMap = { [key in EChibiStateName]: InteractionRecord | undefined }
|
||||
|
||||
export type ChibiInteraction<T = null> = {
|
||||
name: EChibiInteraction;
|
||||
payload: T;
|
||||
}
|
||||
|
||||
export type InteractionResolutionFunction = (interaction: ChibiInteraction<any>) => ChibiState;
|
||||
export type InteractionRecord = Partial<Record<EChibiInteraction, InteractionResolutionFunction>>;
|
||||
|
||||
export type ResolutionFunction = () => ChibiState | undefined;
|
||||
export type ResolutionMap = { [key in EChibiStateName]: ResolutionFunction | undefined }
|
||||
|
||||
export abstract class BasicBrain implements IBrain {
|
||||
|
||||
protected randomService!: RandomService;
|
||||
protected chibi!: Chibi;
|
||||
|
||||
protected readonly defaultState: EChibiStateName = EChibiStateName.Sleeping;
|
||||
|
||||
protected hasBeenAwakeFor: number = 0;
|
||||
protected timeSinceLastInteraction: number = 0;
|
||||
protected timeInCurrentState: number = 0;
|
||||
|
||||
protected abstract interactionMap: InteractionMap;
|
||||
protected abstract resolutionMap: ResolutionMap;
|
||||
|
||||
get state(): ChibiState {
|
||||
return STATES[this.chibi.currentStateName];
|
||||
}
|
||||
|
||||
init(chibi: Chibi, randomService: RandomService): void {
|
||||
this.randomService = randomService;
|
||||
this.chibi = chibi;
|
||||
}
|
||||
|
||||
exist(): void {
|
||||
this.timeInCurrentState++;
|
||||
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.currentStateName]);
|
||||
console.log('resolution', resolution);
|
||||
console.log(`${this.chibi.name} should ${interaction.name} with payload: ${interaction.payload}`);
|
||||
if (resolution) {
|
||||
this.changeState(resolution(interaction));
|
||||
}
|
||||
}
|
||||
|
||||
matchInteraction(map: InteractionMap, interaction: EChibiInteraction, state: ChibiState): InteractionResolutionFunction | undefined {
|
||||
const directMatch = map?.[state.name]?.[interaction];
|
||||
if (directMatch) {
|
||||
return directMatch;
|
||||
}
|
||||
if (state.parent) {
|
||||
return this.matchInteraction(map, interaction, state.parent);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
protected changeState(state: ChibiState): void {
|
||||
this.chibi.currentStateName = state.name;
|
||||
this.timeInCurrentState = 0;
|
||||
}
|
||||
};
|
||||
@@ -1,15 +1,20 @@
|
||||
import { EChibiName } from "../../types/chibi/chibi-name";
|
||||
import { IBrain } from "./brain";
|
||||
import { Aperio } from "./brains/aperio.brain";
|
||||
import { Caethya } from "./brains/caethya.brain";
|
||||
import { Haetor } from "./brains/haetor.brain";
|
||||
|
||||
const APERIO = new Aperio();
|
||||
const CAETHYA = new Caethya();
|
||||
const HAETOR = new Haetor();
|
||||
|
||||
export const BRAIN_MAP: Record<EChibiName, IBrain> = {
|
||||
[EChibiName.Aperio]: APERIO,
|
||||
[EChibiName.Basra]: APERIO,
|
||||
[EChibiName.Caethya]: APERIO,
|
||||
[EChibiName.Caethya]: CAETHYA,
|
||||
[EChibiName.Eos]: APERIO,
|
||||
[EChibiName.Evina]: APERIO,
|
||||
[EChibiName.Haetor]: HAETOR,
|
||||
[EChibiName.Sol]: APERIO,
|
||||
[EChibiName.Sybil]: APERIO,
|
||||
[EChibiName.Vinera]: APERIO
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Chibi } from "../../types/chibi/chibi";
|
||||
import { RandomService } from "../random.service";
|
||||
import { ChibiInteraction } from "./brains/aperio.brain";
|
||||
import { ChibiInteraction } from "./basic.brain";
|
||||
|
||||
export interface IBrain {
|
||||
|
||||
|
||||
@@ -1,23 +1,9 @@
|
||||
import { Chibi } from "../../../types/chibi/chibi";
|
||||
import { EChibiInteraction } from "../../../types/chibi/chibi-interaction";
|
||||
import { ChibiState, isState, STATE_AWAKE, STATE_EATING, STATE_GRUMBLING, STATE_IDLE, STATE_SLEEPING, STATES } from "../../../types/chibi/chibi-state";
|
||||
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, RandomService } from "../../random.service";
|
||||
import { IBrain } from "../brain";
|
||||
|
||||
export type InteractionMap = { [key in EChibiStateName]: InteractionRecord | undefined }
|
||||
|
||||
export type ChibiInteraction<T = null> = {
|
||||
name: EChibiInteraction;
|
||||
payload: T;
|
||||
}
|
||||
|
||||
type InteractionResolutionFunction = (interaction: ChibiInteraction<any>) => ChibiState;
|
||||
type InteractionRecord = Partial<Record<EChibiInteraction, InteractionResolutionFunction>>;
|
||||
|
||||
type ResolutionFunction = () => ChibiState | undefined;
|
||||
type ResolutionMap = { [key in EChibiStateName]: ResolutionFunction | undefined }
|
||||
import { RandomOutcome, } from "../../random.service";
|
||||
import { BasicBrain, ChibiInteraction, InteractionMap, ResolutionMap } from "../basic.brain";
|
||||
|
||||
const MAX_TIME_AWAKE: number = 10;
|
||||
|
||||
@@ -27,21 +13,12 @@ const SADNESS_FROM_NEGLECT: number = 50;
|
||||
const MAX_DURATION_GRUMBLE: number = 1;
|
||||
const MAX_DURATION_EATING: number = 1;
|
||||
|
||||
export class Aperio implements IBrain {
|
||||
export class Aperio extends BasicBrain {
|
||||
|
||||
private randomService!: RandomService;
|
||||
private chibi!: Chibi;
|
||||
|
||||
private readonly defaultState: EChibiStateName = EChibiStateName.Sleeping;
|
||||
private previousState: EChibiStateName = this.defaultState;
|
||||
|
||||
private hasBeenAwakeFor: number = 0;
|
||||
private timeSinceLastInteraction: number = 0;
|
||||
private timeInCurrentState: number = 0;
|
||||
private lastConsumedFoods: string[] = [];
|
||||
private preferredFoods: string[] = [];
|
||||
|
||||
private interactionMap: InteractionMap = {
|
||||
protected override interactionMap: InteractionMap = {
|
||||
[EChibiStateName.Sleeping]: {
|
||||
[EChibiInteraction.WakeUp]: (interaction: ChibiInteraction): ChibiState => this.wakeUp(interaction),
|
||||
},
|
||||
@@ -60,7 +37,7 @@ export class Aperio implements IBrain {
|
||||
[EChibiStateName.Depressed]: undefined,
|
||||
[EChibiStateName.Tired]: undefined
|
||||
}
|
||||
private resolutionMap: ResolutionMap = {
|
||||
protected override resolutionMap: ResolutionMap = {
|
||||
[EChibiStateName.Sleeping]: (): ChibiState | undefined => this.resolveSleeping(),
|
||||
[EChibiStateName.Awake]: (): ChibiState | undefined => this.resolveAwake(),
|
||||
[EChibiStateName.Snoring]: undefined,
|
||||
@@ -76,62 +53,6 @@ export class Aperio implements IBrain {
|
||||
[EChibiStateName.Tired]: undefined
|
||||
}
|
||||
|
||||
get state(): ChibiState {
|
||||
return STATES[this.chibi.currentStateName];
|
||||
}
|
||||
|
||||
init(chibi: Chibi, randomService: RandomService): void {
|
||||
this.randomService = randomService;
|
||||
this.chibi = chibi;
|
||||
}
|
||||
|
||||
exist(): void {
|
||||
this.timeInCurrentState++;
|
||||
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.currentStateName]);
|
||||
console.log('resolution', resolution);
|
||||
console.log(`${this.chibi.name} should ${interaction.name} with payload: ${interaction.payload}`);
|
||||
if (resolution) {
|
||||
this.changeState(resolution(interaction));
|
||||
}
|
||||
}
|
||||
|
||||
isAwake(): boolean {
|
||||
return isState(this.state, EChibiStateName.Awake);
|
||||
}
|
||||
|
||||
matchInteraction(map: InteractionMap, interaction: EChibiInteraction, state: ChibiState): InteractionResolutionFunction | undefined {
|
||||
const directMatch = map?.[state.name]?.[interaction];
|
||||
if (directMatch) {
|
||||
return directMatch;
|
||||
}
|
||||
if (state.parent) {
|
||||
return this.matchInteraction(map, interaction, state.parent);
|
||||
}
|
||||
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 automatically resolve based on the existence cycle
|
||||
|
||||
@@ -189,12 +110,6 @@ export class Aperio implements IBrain {
|
||||
this.chibi.happyness.current = this.chibi.happyness.current - (neglectTime * sadness);
|
||||
}
|
||||
|
||||
private changeState(state: ChibiState): void {
|
||||
this.previousState = this.state.name;
|
||||
this.chibi.currentStateName = state.name;
|
||||
this.timeInCurrentState = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
visiting caethya will wake her up and go into lovey-dovey mode
|
||||
|
||||
|
||||
36
src/app/logic/chibi-behaviour/brains/caethya.brain.ts
Normal file
36
src/app/logic/chibi-behaviour/brains/caethya.brain.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { EChibiStateName } from "../../../types/chibi/chibi-state-name";
|
||||
import { BasicBrain, InteractionMap, ResolutionMap } from "../basic.brain";
|
||||
|
||||
export class Caethya extends BasicBrain {
|
||||
protected override interactionMap: InteractionMap = {
|
||||
[EChibiStateName.Sleeping]: undefined,
|
||||
[EChibiStateName.Awake]: undefined,
|
||||
[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]: undefined,
|
||||
[EChibiStateName.Snoring]: undefined,
|
||||
[EChibiStateName.Nightmare]: undefined,
|
||||
[EChibiStateName.Grumbling]: undefined,
|
||||
[EChibiStateName.Awake]: 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
|
||||
};
|
||||
|
||||
}
|
||||
36
src/app/logic/chibi-behaviour/brains/haetor.brain.ts
Normal file
36
src/app/logic/chibi-behaviour/brains/haetor.brain.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { EChibiStateName } from "../../../types/chibi/chibi-state-name";
|
||||
import { BasicBrain, InteractionMap, ResolutionMap } from "../basic.brain";
|
||||
|
||||
export class Haetor extends BasicBrain {
|
||||
protected override interactionMap: InteractionMap = {
|
||||
[EChibiStateName.Sleeping]: undefined,
|
||||
[EChibiStateName.Awake]: undefined,
|
||||
[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]: undefined,
|
||||
[EChibiStateName.Snoring]: undefined,
|
||||
[EChibiStateName.Nightmare]: undefined,
|
||||
[EChibiStateName.Grumbling]: undefined,
|
||||
[EChibiStateName.Awake]: 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
|
||||
};
|
||||
|
||||
}
|
||||
@@ -12,12 +12,12 @@ import { IBrain } from '../../logic/chibi-behaviour/brain';
|
||||
import { BRAIN_MAP } from '../../logic/chibi-behaviour/brain-map';
|
||||
import { TranslateableComponent } from '../../components/translateable.component';
|
||||
import { Food } from '../../types/food';
|
||||
import { interval, Subscribable, Subscription } from 'rxjs';
|
||||
import { interval, Subscription } from 'rxjs';
|
||||
import { RandomService } from '../../logic/random.service';
|
||||
import { ChibiInteraction } from '../../logic/chibi-behaviour/brains/aperio.brain';
|
||||
import { isState, STATES } from '../../types/chibi/chibi-state';
|
||||
import { EChibiStateName } from '../../types/chibi/chibi-state-name';
|
||||
import { VisitorListComponent } from "../../components/interaction-menus/visitor-list/visitor-list.component";
|
||||
import { ChibiInteraction } from '../../logic/chibi-behaviour/basic.brain';
|
||||
|
||||
enum EInteractionMenuState {
|
||||
Neutral,
|
||||
|
||||
@@ -4,6 +4,7 @@ export enum EChibiName {
|
||||
Caethya = 'Caethya',
|
||||
Eos = 'Eos',
|
||||
Evina = 'Evina',
|
||||
Haetor = 'Haetor',
|
||||
Sol = 'Sol',
|
||||
Sybil = 'Sybil',
|
||||
Vinera = 'Vinera'
|
||||
|
||||
Reference in New Issue
Block a user