| @@ -1,7 +1,7 @@ | |||
| import { Creature } from './creature' | |||
| import { Encounter } from './combat' | |||
| import { LogEntry } from './interface' | |||
| import { ReleaseAction, TransferAction } from './combat/actions' | |||
| import { ReleaseAction, TransferAction, PassAction } from './combat/actions' | |||
| export interface AI { | |||
| name: string; | |||
| @@ -26,12 +26,12 @@ export class RandomAI implements AI { | |||
| action: action | |||
| }))) | |||
| const chosen = actions[Math.floor(Math.random() * actions.length)] | |||
| return chosen.action.execute(actor, chosen.target) | |||
| return chosen.action.try(actor, chosen.target) | |||
| } | |||
| } | |||
| /** | |||
| * The VoreAI tries to perform moves from its containers | |||
| * The VoreAI tries to eat opponents, but only if the odds are good enough | |||
| */ | |||
| export class VoreAI extends RandomAI { | |||
| name = "Vore AI" | |||
| @@ -41,11 +41,13 @@ export class VoreAI extends RandomAI { | |||
| action: action | |||
| }))) | |||
| const voreActions = actions.filter(action => actor.otherContainers.concat(actor.containers).some(container => container.actions.includes(action.action) || action instanceof TransferAction)) | |||
| const aggressiveActions = voreActions.filter(action => !(action.action instanceof ReleaseAction)) | |||
| const chosen = aggressiveActions[Math.floor(Math.random() * aggressiveActions.length)] | |||
| const aggressiveActions = voreActions.filter(action => !(action.action instanceof ReleaseAction) && !(action.action instanceof PassAction)) | |||
| const likelyActions = aggressiveActions.filter(action => action.action.odds(actor, action.target) > 0.4) | |||
| likelyActions.forEach(action => console.log(action.action.odds(actor, action.target))) | |||
| const chosen = likelyActions[Math.floor(Math.random() * likelyActions.length)] | |||
| if (chosen === undefined) { | |||
| return super.decide(actor, encounter) | |||
| } | |||
| return chosen.action.execute(actor, chosen.target) | |||
| return chosen.action.try(actor, chosen.target) | |||
| } | |||
| } | |||
| @@ -381,6 +381,10 @@ export abstract class Action { | |||
| ) | |||
| } | |||
| odds (user: Creature, target: Creature): number { | |||
| return this.tests.reduce((total, test) => total * test.odds(user, target), 1) | |||
| } | |||
| abstract execute (user: Creature, target: Creature): LogEntry | |||
| } | |||
| @@ -68,7 +68,7 @@ export class AttackAction extends DamageAction { | |||
| damage, | |||
| [new StatTest( | |||
| Stat.Power, | |||
| 10, | |||
| 15, | |||
| (user, target) => new LogLine( | |||
| `${user.name.capital} ${user.name.conjugate(new Verb('miss', 'misses'))} ${target.name.objective}!` | |||
| ) | |||
| @@ -85,10 +85,6 @@ export class AttackAction extends DamageAction { | |||
| `${user.name.capital} ${user.name.conjugate(this.verb)} ${target.name.objective} for `, | |||
| target.effectiveDamage(args.damage).renderShort() | |||
| ) | |||
| failLine: PairLine<Creature> = (user, target) => new LogLine( | |||
| `${user.name.capital} ${user.name.conjugate(new Verb('miss', 'misses'))} ${target.name.objective}` | |||
| ) | |||
| } | |||
| /** | |||
| @@ -102,7 +98,7 @@ export class DevourAction extends Action { | |||
| [new CapableCondition(), new TogetherCondition(), new HasRoomCondition(container)], | |||
| [new StatVigorSizeTest( | |||
| Stat.Power, | |||
| 10, | |||
| -5, | |||
| (user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to ${container.consumeVerb} ${target.name.objective}.`) | |||
| )] | |||
| ) | |||
| @@ -165,10 +161,6 @@ export class FeedAction extends Action { | |||
| protected successLine: PairLine<Entity> = (user, target) => new LogLine( | |||
| `${user.name.capital} ${user.name.conjugate(new Verb('feed'))} ${user.pronouns.reflexive} to ${target.name}. ` | |||
| ) | |||
| protected failLine: PairLine<Entity> = (user, target) => new LogLine( | |||
| `${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to feed ${user.pronouns.reflexive} to ${target.name}. ` | |||
| ) | |||
| } | |||
| /** | |||
| @@ -182,7 +174,7 @@ export class StruggleAction extends Action { | |||
| [new CapableCondition(), new PairCondition(), new ContainedByCondition(container)], | |||
| [new StatVigorSizeTest( | |||
| Stat.Power, | |||
| 0, | |||
| -5, | |||
| (user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to escape from ${target.name.possessive} ${container.name}.`) | |||
| )] | |||
| ) | |||
| @@ -26,10 +26,6 @@ export class TrappedAction extends DamageAction { | |||
| `${user.name.capital} ${user.name.conjugate(this.verb)} ${target.name.objective} for `, | |||
| target.effectiveDamage(args.damage).renderShort() | |||
| ) | |||
| failLine: PairLine<Creature> = (user, target) => new LogLine( | |||
| `${user.name.capital} can't quite get ${user.pronouns.possessive} teeth around ${target.name.objective}.` | |||
| ) | |||
| } | |||
| class Hand extends NormalContainer { | |||
| @@ -1,6 +1,6 @@ | |||
| import { Creature } from "../creature" | |||
| import { Damage, DamageType, ConstantDamageFormula, Vigor, Side } from '../combat' | |||
| import { MalePronouns, ImproperNoun, ProperNoun, ObjectPronouns, FemalePronouns, TheyPronouns } from '../language' | |||
| import { Damage, DamageType, ConstantDamageFormula, Vigor, Side, StatDamageFormula, Stat } from '../combat' | |||
| import { MalePronouns, ImproperNoun, ProperNoun, ObjectPronouns, FemalePronouns, TheyPronouns, Verb } from '../language' | |||
| import { VoreType, Stomach, Bowels, Cock, Balls, anyVore, Slit, Womb, biconnectContainers } from '../vore' | |||
| import { AttackAction, TransferAction, FeedAction } from '../combat/actions' | |||
| import { Human } from '../creatures' | |||
| @@ -18,11 +18,11 @@ export class Wolf extends Creature { | |||
| ) | |||
| this.actions.push( | |||
| new AttackAction( | |||
| new ConstantDamageFormula( | |||
| new Damage( | |||
| { amount: 20, type: DamageType.Pierce, target: Vigor.Health } | |||
| ) | |||
| ) | |||
| new StatDamageFormula([ | |||
| { fraction: 1, stat: Stat.Power, target: Vigor.Health, type: DamageType.Pierce }, | |||
| { fraction: 0.5, stat: Stat.Power, target: Vigor.Health, type: DamageType.Crush } | |||
| ]), | |||
| new Verb("bite") | |||
| ) | |||
| ) | |||