Переглянути джерело

Add some deciders for composition actions

vintage
Fen Dweller 5 роки тому
джерело
коміт
b10dd63598
5 змінених файлів з 78 додано та 15 видалено
  1. +11
    -9
      src/game/ai.ts
  2. +62
    -1
      src/game/ai/deciders.ts
  3. +1
    -1
      src/game/combat.ts
  4. +3
    -3
      src/game/combat/consequences.ts
  5. +1
    -1
      src/game/creatures/human.ts

+ 11
- 9
src/game/ai.ts Переглянути файл

@@ -1,8 +1,10 @@
import { Creature } from './creature'
import { Encounter, Action } from './combat'
import { Encounter, Action, Damage, StatusEffect } from './combat'
import { LogEntry, nilLog } from './interface'
import { ReleaseAction, TransferAction, PassAction } from './combat/actions'
import { NoPassDecider, NoReleaseDecider, ChanceDecider } from './ai/deciders'
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;
@@ -20,7 +22,7 @@ export class NoAI implements AI {
* A Decider determines how favorable an action is to perform.
*/
export interface Decider {
decide: (encounter: Encounter, user: Creature, target: Creature, action: Action) => number
decide: (encounter: Encounter, user: Creature, target: Creature, action: Action) => number;
}

export class DeciderAI implements AI {
@@ -28,7 +30,7 @@ export class DeciderAI implements AI {

}

decide(actor: Creature, encounter: Encounter): LogEntry {
decide (actor: Creature, encounter: Encounter): LogEntry {
const options = encounter.combatants.flatMap(enemy => actor.validActions(enemy).map(action => ({
target: enemy,
action: action,
@@ -39,7 +41,7 @@ export class DeciderAI implements AI {

this.deciders.forEach(
decider => options.forEach(
option => option.weight *= decider.decide(encounter, actor, option.target, option.action)
option => { option.weight *= decider.decide(encounter, actor, option.target, option.action) }
)
)

@@ -51,7 +53,7 @@ export class DeciderAI implements AI {
total *= Math.random()
console.log(total)

const chosen = options.find (
const chosen = options.find(
option => {
if (total < option.weight) {
return true
@@ -92,12 +94,12 @@ export class RandomAI implements AI {
*/
export class VoreAI extends DeciderAI {
constructor () {
super (
super(
"Vore AI",
[
new NoPassDecider(),
new NoReleaseDecider(),
new ChanceDecider()
new ChanceDecider(),
new NoSurrenderDecider()
]
)
}


+ 62
- 1
src/game/ai/deciders.ts Переглянути файл

@@ -1,7 +1,9 @@
import { Decider } from '../ai'
import { Encounter, Action } from '../combat'
import { Encounter, Action, Consequence, CompositionAction } from '../combat'
import { Creature } from '../creature'
import { PassAction, ReleaseAction } from '../combat/actions'
import { StatusConsequence } from '../combat/consequences'
import { SurrenderEffect } from '../combat/effects'

/**
* Specifically avoids using a [[PassAction]]
@@ -37,3 +39,62 @@ export class ChanceDecider implements Decider {
return action.odds(user, target)
}
}

/**
* Adjusts the weights for [[CompositionAction]]s that contain the specified consequence
*/
export class ConsequenceDecider<T extends Consequence> implements Decider {
constructor (private consequenceType: new (...args: any) => T, private weight: number) {

}

decide (encounter: Encounter, user: Creature, target: Creature, action: Action): number {
if (action instanceof CompositionAction) {
if (action.consequences.some(
consequence => consequence instanceof this.consequenceType
)) {
return this.weight
} else {
return 1
}
} else {
return 1
}
}
}

/**
* Adjusts the weights for [[CompositionAction]]s, using the provided function to make the choice.
*/
export class ConsequenceFunctionDecider implements Decider {
constructor (private func: (encounter: Encounter, user: Creature, target: Creature, action: CompositionAction) => number) {

}

decide (encounter: Encounter, user: Creature, target: Creature, action: Action): number {
if (action instanceof CompositionAction) {
return this.func(encounter, user, target, action)
} else {
return 1
}
}
}

/**
* A [[ConsequenceFunctionDecider]] that filters out status effects
*/
export class NoSurrenderDecider extends ConsequenceFunctionDecider {
constructor () {
super(
(encounter, user, target, action) => {
return action.consequences.some(
consequence => {
if (consequence instanceof StatusConsequence) {
return (consequence.statusMaker(user, target) instanceof SurrenderEffect)
}
}
) ? 0 : 1
}
)
}
}

+ 1
- 1
src/game/combat.ts Переглянути файл

@@ -389,7 +389,7 @@ export abstract class Action {
}

export class CompositionAction extends Action {
private consequences: Array<Consequence>;
public consequences: Array<Consequence>;

constructor (
name: TextLike,


+ 3
- 3
src/game/combat/consequences.ts Переглянути файл

@@ -85,17 +85,17 @@ export class HealingConsequence extends Consequence {
* Applies a status effect
*/
export class StatusConsequence extends Consequence {
constructor (private statusMaker: () => StatusEffect, conditions: Condition[] = []) {
constructor (public statusMaker: (user: Creature, target: Creature) => StatusEffect, conditions: Condition[] = []) {
super(conditions)
}

apply (user: Creature, target: Creature): LogEntry {
return target.applyEffect(this.statusMaker())
return target.applyEffect(this.statusMaker(user, target))
}

describePair (user: Creature, target: Creature): LogEntry {
return new LogLine(
`Applies a ${this.statusMaker().name} effect.`
`Applies a ${this.statusMaker(user, target)} effect.`
)
}
}

+ 1
- 1
src/game/creatures/human.ts Переглянути файл

@@ -32,7 +32,7 @@ export class Human extends Creature {
{
consequences: [
new StatusConsequence(
() => new SurrenderEffect()
(user, target) => new SurrenderEffect()
)
],
conditions: [


Завантаження…
Відмінити
Зберегти