|
- import { Creature } from './creature'
- import { Encounter, Action, Damage, StatusEffect } from './combat'
- import { LogEntry, nilLog } from './interface'
- import { ReleaseAction, TransferAction, PassAction } from './combat/actions'
- import { NoPassDecider, NoReleaseDecider, ChanceDecider, ConsequenceDecider, ConsequenceFunctionDecider, NoSurrenderDecider } from './ai/deciders'
- import { SurrenderEffect } from './combat/effects'
- import { StatusConsequence, DamageConsequence } from './combat/consequences'
-
- export interface AI {
- name: string;
- decide (actor: Creature, encounter: Encounter): LogEntry;
- }
-
- export class NoAI implements AI {
- name = "No AI"
- decide (actor: Creature, encounter: Encounter): LogEntry {
- throw new Error("This AI cannot be used.")
- }
- }
-
- /**
- * 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 DeciderAI implements AI {
- constructor (public name: string, 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
- })))
-
- console.log(options)
-
- 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()
- console.log(total)
-
- 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)
- }
-
- // should never reach this point!
-
- throw new Error("Couldn't pick an action")
- }
- }
-
- /**
- * The RandomAI is **COMPLETELY** random. Good luck.
- */
- export class RandomAI implements AI {
- name = "Random AI"
- decide (actor: Creature, encounter: Encounter): LogEntry {
- const actions = encounter.combatants.flatMap(enemy => actor.validActions(enemy).map(action => ({
- target: enemy,
- action: action
- })))
- const chosen = actions[Math.floor(Math.random() * actions.length)]
- return chosen.action.try(actor, chosen.target)
- }
- }
-
- /**
- * The VoreAI tries to eat opponents, but only if the odds are good enough
- */
- export class VoreAI extends DeciderAI {
- constructor () {
- super(
- "Vore AI",
- [
- new NoReleaseDecider(),
- new ChanceDecider(),
- new NoSurrenderDecider()
- ]
- )
- }
- }
|