| @@ -57,6 +57,7 @@ import { LogEntry, LogLine } from '@/game/interface' | |||||
| import Statblock from './Statblock.vue' | import Statblock from './Statblock.vue' | ||||
| import ActionButton from './ActionButton.vue' | import ActionButton from './ActionButton.vue' | ||||
| import { Side, Encounter } from '@/game/combat' | import { Side, Encounter } from '@/game/combat' | ||||
| import { NoAI } from '../game/ai' | |||||
| @Component( | @Component( | ||||
| { | { | ||||
| @@ -182,6 +183,14 @@ export default class Combat extends Vue { | |||||
| this.scrollParentTo(target) | this.scrollParentTo(target) | ||||
| } | } | ||||
| }) | }) | ||||
| if (!(this.encounter.currentMove.ai instanceof NoAI)) { | |||||
| if (this.encounter.currentMove.side === Side.Heroes) { | |||||
| this.executedLeft(this.encounter.currentMove.ai.decide(this.encounter.currentMove, this.encounter)) | |||||
| } else { | |||||
| this.executedRight(this.encounter.currentMove.ai.decide(this.encounter.currentMove, this.encounter)) | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -60,6 +60,9 @@ | |||||
| <button v-if="subject.perspective === POV.Third" @click.stop="subject.perspective = POV.Second">Second-person</button> | <button v-if="subject.perspective === POV.Third" @click.stop="subject.perspective = POV.Second">Second-person</button> | ||||
| <button v-if="subject.perspective === POV.First" @click.stop="subject.perspective = POV.Third">Third-person</button> | <button v-if="subject.perspective === POV.First" @click.stop="subject.perspective = POV.Third">Third-person</button> | ||||
| <button v-if="subject.perspective === POV.Second" @click.stop="subject.perspective = POV.First">First-person</button> | <button v-if="subject.perspective === POV.Second" @click.stop="subject.perspective = POV.First">First-person</button> | ||||
| <select @change="subject.ai = new ais[$event.target.selectedIndex]()"> | |||||
| <option v-for="(ai, index) in ais" :key="'ai-' + index">{{ ai.name }}</option> | |||||
| </select> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </template> | </template> | ||||
| @@ -68,6 +71,7 @@ | |||||
| import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator' | import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator' | ||||
| import { Creature } from '@/game/creature' | import { Creature } from '@/game/creature' | ||||
| import { POV } from '@/game/language' | import { POV } from '@/game/language' | ||||
| import { NoAI, RandomAI } from '@/game/ai' | |||||
| import { Stats, Stat, StatIcons, StatDescs, Vigor, VigorIcons, VigorDescs, VoreStatDescs, VoreStatIcons, VisibleStatus } from '@/game/combat' | import { Stats, Stat, StatIcons, StatDescs, Vigor, VigorIcons, VigorDescs, VoreStatDescs, VoreStatIcons, VisibleStatus } from '@/game/combat' | ||||
| import ContainerView from './ContainerView.vue' | import ContainerView from './ContainerView.vue' | ||||
| import tippy, { delegate, createSingleton } from 'tippy.js' | import tippy, { delegate, createSingleton } from 'tippy.js' | ||||
| @@ -79,7 +83,8 @@ import 'tippy.js/dist/tippy.css' | |||||
| }, | }, | ||||
| data () { | data () { | ||||
| return { | return { | ||||
| POV: POV | |||||
| POV: POV, | |||||
| ais: [NoAI, RandomAI] | |||||
| } | } | ||||
| }, | }, | ||||
| methods: { | methods: { | ||||
| @@ -0,0 +1,30 @@ | |||||
| import { Creature } from './creature' | |||||
| import { Encounter } from './combat' | |||||
| import { LogEntry } from './interface' | |||||
| 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.") | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 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.filter(enemy => enemy !== actor).flatMap(enemy => actor.validActions(enemy).map(action => ({ | |||||
| target: enemy, | |||||
| action: action | |||||
| }))) | |||||
| const chosen = actions[Math.floor(Math.random() * actions.length)] | |||||
| return chosen.action.execute(actor, chosen.target) | |||||
| } | |||||
| } | |||||
| @@ -4,6 +4,7 @@ import { LogEntry, LogLines } from './interface' | |||||
| import { Vore, VoreContainer, VoreType } from './vore' | import { Vore, VoreContainer, VoreType } from './vore' | ||||
| import { Item, EquipmentSlot, Equipment } from './items' | import { Item, EquipmentSlot, Equipment } from './items' | ||||
| import { PassAction } from './combat/actions' | import { PassAction } from './combat/actions' | ||||
| import { AI, NoAI } from './ai' | |||||
| export class Creature extends Vore implements Combatant { | export class Creature extends Vore implements Combatant { | ||||
| actions: Array<Action> = []; | actions: Array<Action> = []; | ||||
| @@ -16,6 +17,7 @@ export class Creature extends Vore implements Combatant { | |||||
| side: Side; | side: Side; | ||||
| title = "Lv. 1 Creature"; | title = "Lv. 1 Creature"; | ||||
| equipment: Map<EquipmentSlot, Equipment> = new Map() | equipment: Map<EquipmentSlot, Equipment> = new Map() | ||||
| ai: AI = new NoAI() | |||||
| constructor (name: Noun, kind: Noun, pronouns: Pronoun, stats: Stats, preyPrefs: Set<VoreType>, predPrefs: Set<VoreType>, mass: number) { | constructor (name: Noun, kind: Noun, pronouns: Pronoun, stats: Stats, preyPrefs: Set<VoreType>, predPrefs: Set<VoreType>, mass: number) { | ||||
| super(name, kind, pronouns, stats, preyPrefs, predPrefs, mass) | super(name, kind, pronouns, stats, preyPrefs, predPrefs, mass) | ||||