|
- import { Creature } from './creature'
- import { Encounter, Action } from './combat'
- import { LogEntry } from './interface'
- import { PassAction } from './combat/actions'
- import { NoPassDecider, NoReleaseDecider, ChanceDecider, NoSurrenderDecider } from './ai/deciders'
-
- /**
- * A Decider determines how favorable an action is to perform.
- */
- export interface Decider {
- decide: (encounter: Encounter, user: Creature, target: Creature, action: Action) => number;
- }
-
- export class AI {
- constructor (private deciders: Decider[]) {
-
- }
-
- decide (actor: Creature, encounter: Encounter): LogEntry {
- const options = encounter.combatants.flatMap(enemy => actor.validActions(enemy).map(action => ({
- target: enemy,
- action: action,
- weight: 1
- })))
-
- this.deciders.forEach(
- decider => options.forEach(
- option => { option.weight *= decider.decide(encounter, actor, option.target, option.action) }
- )
- )
-
- let total = options.reduce(
- (sum: number, option) => sum + option.weight,
- 0
- )
-
- total *= Math.random()
-
- const chosen = options.find(
- option => {
- if (total < option.weight) {
- return true
- } else {
- total -= option.weight
- return false
- }
- }
- )
-
- if (chosen !== undefined) {
- return chosen.action.try(actor, chosen.target)
- }
-
- // if we filtered out EVERY action, we should just give up and pass
-
- return new PassAction().try(actor, actor)
- }
- }
-
- /**
- * The VoreAI tries to eat opponents, but only if the odds are good enough
- */
- export class VoreAI extends AI {
- constructor () {
- super(
- [
- new NoReleaseDecider(),
- new NoSurrenderDecider(),
- new NoPassDecider(),
- new ChanceDecider()
- ]
- )
- }
- }
|