| @@ -1,7 +1,7 @@ | |||||
| import { Creature } from './creature' | import { Creature } from './creature' | ||||
| import { Encounter } from './combat' | import { Encounter } from './combat' | ||||
| import { LogEntry } from './interface' | import { LogEntry } from './interface' | ||||
| import { ReleaseAction, TransferAction } from './combat/actions' | |||||
| import { ReleaseAction, TransferAction, PassAction } from './combat/actions' | |||||
| export interface AI { | export interface AI { | ||||
| name: string; | name: string; | ||||
| @@ -26,12 +26,12 @@ export class RandomAI implements AI { | |||||
| action: action | action: action | ||||
| }))) | }))) | ||||
| const chosen = actions[Math.floor(Math.random() * actions.length)] | 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 { | export class VoreAI extends RandomAI { | ||||
| name = "Vore AI" | name = "Vore AI" | ||||
| @@ -41,11 +41,13 @@ export class VoreAI extends RandomAI { | |||||
| action: action | action: action | ||||
| }))) | }))) | ||||
| const voreActions = actions.filter(action => actor.otherContainers.concat(actor.containers).some(container => container.actions.includes(action.action) || action instanceof TransferAction)) | 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) { | if (chosen === undefined) { | ||||
| return super.decide(actor, encounter) | 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 | abstract execute (user: Creature, target: Creature): LogEntry | ||||
| } | } | ||||
| @@ -68,7 +68,7 @@ export class AttackAction extends DamageAction { | |||||
| damage, | damage, | ||||
| [new StatTest( | [new StatTest( | ||||
| Stat.Power, | Stat.Power, | ||||
| 10, | |||||
| 15, | |||||
| (user, target) => new LogLine( | (user, target) => new LogLine( | ||||
| `${user.name.capital} ${user.name.conjugate(new Verb('miss', 'misses'))} ${target.name.objective}!` | `${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 `, | `${user.name.capital} ${user.name.conjugate(this.verb)} ${target.name.objective} for `, | ||||
| target.effectiveDamage(args.damage).renderShort() | 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 CapableCondition(), new TogetherCondition(), new HasRoomCondition(container)], | ||||
| [new StatVigorSizeTest( | [new StatVigorSizeTest( | ||||
| Stat.Power, | Stat.Power, | ||||
| 10, | |||||
| -5, | |||||
| (user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to ${container.consumeVerb} ${target.name.objective}.`) | (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( | protected successLine: PairLine<Entity> = (user, target) => new LogLine( | ||||
| `${user.name.capital} ${user.name.conjugate(new Verb('feed'))} ${user.pronouns.reflexive} to ${target.name}. ` | `${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 CapableCondition(), new PairCondition(), new ContainedByCondition(container)], | ||||
| [new StatVigorSizeTest( | [new StatVigorSizeTest( | ||||
| Stat.Power, | 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}.`) | (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 `, | `${user.name.capital} ${user.name.conjugate(this.verb)} ${target.name.objective} for `, | ||||
| target.effectiveDamage(args.damage).renderShort() | 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 { | class Hand extends NormalContainer { | ||||
| @@ -1,6 +1,6 @@ | |||||
| import { Creature } from "../creature" | 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 { VoreType, Stomach, Bowels, Cock, Balls, anyVore, Slit, Womb, biconnectContainers } from '../vore' | ||||
| import { AttackAction, TransferAction, FeedAction } from '../combat/actions' | import { AttackAction, TransferAction, FeedAction } from '../combat/actions' | ||||
| import { Human } from '../creatures' | import { Human } from '../creatures' | ||||
| @@ -18,11 +18,11 @@ export class Wolf extends Creature { | |||||
| ) | ) | ||||
| this.actions.push( | this.actions.push( | ||||
| new AttackAction( | 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") | |||||
| ) | ) | ||||
| ) | ) | ||||