pear can eat
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import { Chibi } from "../../types/chibi/chibi";
|
import { Chibi } from "../../types/chibi/chibi";
|
||||||
import { EChibiInteraction } from "../../types/chibi/chibi-interaction";
|
|
||||||
import { Food } from "../../types/food";
|
|
||||||
import { RandomService } from "../random.service";
|
import { RandomService } from "../random.service";
|
||||||
|
import { ChibiInteraction } from "./brains/aperio.brain";
|
||||||
|
|
||||||
export interface IBrain {
|
export interface IBrain {
|
||||||
|
|
||||||
@@ -12,5 +11,5 @@ export interface IBrain {
|
|||||||
exist(): void;
|
exist(): void;
|
||||||
|
|
||||||
// function which resolves all interactions
|
// function which resolves all interactions
|
||||||
resolveInteraction(interaction: EChibiInteraction, item?: Food): void
|
resolveInteraction(interaction: ChibiInteraction<any>): void
|
||||||
}
|
}
|
||||||
@@ -1,27 +1,49 @@
|
|||||||
import { Chibi } from "../../../types/chibi/chibi";
|
import { Chibi } from "../../../types/chibi/chibi";
|
||||||
import { EChibiInteraction } from "../../../types/chibi/chibi-interaction";
|
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 { EChibiStateName } from "../../../types/chibi/chibi-state-name";
|
||||||
import { Food } from "../../../types/food";
|
import { Food } from "../../../types/food";
|
||||||
import { RandomOutcome, RandomService } from "../../random.service";
|
import { RandomOutcome, RandomService } from "../../random.service";
|
||||||
import { IBrain } from "../brain";
|
import { IBrain } from "../brain";
|
||||||
|
|
||||||
type ResolutionFunction = (interaction: EChibiInteraction) => ChibiState;
|
export type ChibiInteraction<T = null> = {
|
||||||
|
name: EChibiInteraction;
|
||||||
|
payload: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResolutionFunction = (interaction: ChibiInteraction<any>) => ChibiState;
|
||||||
type InteractionRecord = Partial<Record<EChibiInteraction, ResolutionFunction>>;
|
type InteractionRecord = Partial<Record<EChibiInteraction, ResolutionFunction>>;
|
||||||
|
|
||||||
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 {
|
export class Aperio implements IBrain {
|
||||||
|
|
||||||
private randomService!: RandomService;
|
private randomService!: RandomService;
|
||||||
private chibi!: Chibi;
|
private chibi!: Chibi;
|
||||||
|
|
||||||
|
private readonly defaultState: EChibiStateName = EChibiStateName.Sleeping;
|
||||||
|
private previousState: EChibiStateName = this.defaultState;
|
||||||
|
|
||||||
private hasBeenAwakeFor: number = 0;
|
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 } = {
|
private interactionMap: { [key in EChibiStateName]: InteractionRecord | undefined } = {
|
||||||
[EChibiStateName.Sleeping]: {
|
[EChibiStateName.Sleeping]: {
|
||||||
[EChibiInteraction.WakeUp]: (interaction: EChibiInteraction): ChibiState => this.wakeUp(interaction),
|
[EChibiInteraction.WakeUp]: (interaction: ChibiInteraction): ChibiState => this.wakeUp(interaction),
|
||||||
|
},
|
||||||
|
[EChibiStateName.Awake]: {
|
||||||
|
[EChibiInteraction.Feed]: (interaction: ChibiInteraction<Food>): ChibiState => this.eat(interaction),
|
||||||
},
|
},
|
||||||
[EChibiStateName.Awake]: undefined,
|
|
||||||
[EChibiStateName.Snoring]: undefined,
|
[EChibiStateName.Snoring]: undefined,
|
||||||
[EChibiStateName.Nightmare]: undefined,
|
[EChibiStateName.Nightmare]: undefined,
|
||||||
[EChibiStateName.Grumbling]: undefined,
|
[EChibiStateName.Grumbling]: undefined,
|
||||||
@@ -35,72 +57,123 @@ export class Aperio implements IBrain {
|
|||||||
[EChibiStateName.Tired]: undefined
|
[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 {
|
init(chibi: Chibi, randomService: RandomService): void {
|
||||||
this.randomService = randomService;
|
this.randomService = randomService;
|
||||||
this.chibi = chibi;
|
this.chibi = chibi;
|
||||||
this.state = STATES[chibi.state];
|
this.state = STATES[chibi.state];
|
||||||
console.log(this.wakeUp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exist(): void {
|
exist(): void {
|
||||||
console.log('Brain is braining');
|
this.timeInCurrentState++;
|
||||||
if (isState(this.state, EChibiStateName.Awake)) {
|
this.resolveAwake();
|
||||||
console.log('is awake');
|
this.resolveSleeping();
|
||||||
this.hasBeenAwakeFor++;
|
this.resolveGrumbling();
|
||||||
if (this.hasBeenAwakeFor > MAX_TIME_AWAKE) {
|
this.resolveEating();
|
||||||
this.state = STATE_SLEEPING;
|
|
||||||
this.chibi.state = EChibiStateName.Sleeping;
|
|
||||||
this.hasBeenAwakeFor = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.chibi.state = this.state.name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveInteraction(interaction: EChibiInteraction, item?: Food): void {
|
resolveInteraction(interaction: ChibiInteraction): void {
|
||||||
// reassign state based on resolving map
|
this.timeSinceLastInteraction = 0;
|
||||||
const resolution: ResolutionFunction | undefined = this.interactionMap[this.state.name]?.[interaction];
|
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) {
|
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.chibi.state = this.state.name;
|
||||||
|
this.timeInCurrentState = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
pear mostly sleeps
|
|
||||||
|
|
||||||
visiting caethya will wake her up and go into lovey-dovey mode
|
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)
|
as long as the same food is not offered thrice in a row (except banana split)
|
||||||
|
|
||||||
pears energy never goes down
|
pears energy never goes down
|
||||||
pear will accept fights and enjoys them
|
pear will accept fights and enjoys them
|
||||||
pear will accept walks 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
|
pear gets offended if you suggest she go to sleep
|
||||||
|
|
||||||
after any interaction she has a 1/4 chance of going 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 wakeUpOutcome: RandomOutcome = this.randomService.obtainRandom(128);
|
||||||
const willWakeUp: boolean = wakeUpOutcome.matchesChance(1);
|
const willWakeUp: boolean = wakeUpOutcome.matchesChance(1);
|
||||||
const willGrumble: boolean = wakeUpOutcome.matchesChance(12, 1);
|
const willGrumble: boolean = wakeUpOutcome.matchesChance(12, 1);
|
||||||
console.log(wakeUpOutcome.random);
|
|
||||||
console.log(willWakeUp);
|
|
||||||
console.log(willGrumble);
|
|
||||||
if (willWakeUp) {
|
if (willWakeUp) {
|
||||||
return STATE_IDLE;
|
return STATE_IDLE;
|
||||||
} else if (willGrumble) {
|
} else if (willGrumble) {
|
||||||
@@ -109,10 +182,16 @@ export class Aperio implements IBrain {
|
|||||||
return STATE_SLEEPING;
|
return STATE_SLEEPING;
|
||||||
}
|
}
|
||||||
|
|
||||||
private resolveAwakeInteraction(interaction: EChibiInteraction, item?: Food): ChibiState {
|
private eat(interaction: ChibiInteraction<Food>): ChibiState {
|
||||||
if (EChibiInteraction.Feed) {
|
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_EATING;
|
return STATE_EATING;
|
||||||
}
|
}
|
||||||
return STATE_IDLE;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
@@ -13,8 +13,8 @@ import { BRAIN_MAP } from '../../logic/chibi-behaviour/brain-map';
|
|||||||
import { TranslateableComponent } from '../../components/translateable.component';
|
import { TranslateableComponent } from '../../components/translateable.component';
|
||||||
import { Food } from '../../types/food';
|
import { Food } from '../../types/food';
|
||||||
import { interval } from 'rxjs';
|
import { interval } from 'rxjs';
|
||||||
import { ChibiState, STATES } from '../../types/chibi/chibi-state';
|
|
||||||
import { RandomService } from '../../logic/random.service';
|
import { RandomService } from '../../logic/random.service';
|
||||||
|
import { ChibiInteraction } from '../../logic/chibi-behaviour/brains/aperio.brain';
|
||||||
|
|
||||||
enum EInteractionMenuState {
|
enum EInteractionMenuState {
|
||||||
Neutral,
|
Neutral,
|
||||||
@@ -22,7 +22,7 @@ enum EInteractionMenuState {
|
|||||||
Inventory
|
Inventory
|
||||||
}
|
}
|
||||||
|
|
||||||
const THINKING_INTERVAL: number = 10000;
|
const THINKING_INTERVAL: number = 2000;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ff-interactions',
|
selector: 'ff-interactions',
|
||||||
@@ -61,7 +61,7 @@ export class InteractionsComponent extends TranslateableComponent {
|
|||||||
|
|
||||||
public interact(interaction: EChibiInteraction, item?: Food): void {
|
public interact(interaction: EChibiInteraction, item?: Food): void {
|
||||||
console.log(`${interaction} ${this.chibi().name} and item ${item}`);
|
console.log(`${interaction} ${this.chibi().name} and item ${item}`);
|
||||||
this.brain.resolveInteraction(interaction, item);
|
this.brain.resolveInteraction({ name: interaction, payload: item } as ChibiInteraction<Food>);
|
||||||
}
|
}
|
||||||
|
|
||||||
public openFoodPantry(): void {
|
public openFoodPantry(): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user