diff --git a/src/App.vue b/src/App.vue
index 5450fff..1339cb4 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -4,6 +4,7 @@
diff --git a/src/components/Combat.vue b/src/components/Combat.vue
index 5bb534e..5207262 100644
--- a/src/components/Combat.vue
+++ b/src/components/Combat.vue
@@ -216,7 +216,7 @@ export default class Combat extends Vue {
}
})
- if (!(this.encounter.currentMove.ai === null)) {
+ if (this.encounter.currentMove.perspective === POV.Third) {
if (this.encounter.currentMove.side === Side.Heroes) {
this.executedLeft(this.encounter.currentMove.ai.decide(this.encounter.currentMove, this.encounter))
} else {
diff --git a/src/components/Statblock.vue b/src/components/Statblock.vue
index f4a74e5..4fe9c8d 100644
--- a/src/components/Statblock.vue
+++ b/src/components/Statblock.vue
@@ -57,9 +57,7 @@
-
-
-
+
diff --git a/src/game/ai.ts b/src/game/ai.ts
index ce17dac..f524d74 100644
--- a/src/game/ai.ts
+++ b/src/game/ai.ts
@@ -202,6 +202,20 @@ export class FavorEscapedPrey extends Decider {
}
}
+/**
+ * The RandomAI just does whatever it wants to
+ */
+export class RandomAI extends AI {
+ constructor (owner: Creature) {
+ super(
+ [
+
+ ],
+ owner
+ )
+ }
+}
+
/**
* The VoreAI tries to eat opponents, but only if the odds are good enough
*/
diff --git a/src/game/creature.ts b/src/game/creature.ts
index d479ec1..54b4357 100644
--- a/src/game/creature.ts
+++ b/src/game/creature.ts
@@ -4,7 +4,7 @@ import { LogEntry, LogLines, LogLine } from '@/game/interface'
import { VoreContainer, VoreType, Container } from '@/game/vore'
import { Item, EquipmentSlot, Equipment, ItemKind, Currency } from '@/game/items'
import { PassAction } from '@/game/combat/actions'
-import { AI } from '@/game/ai'
+import { AI, RandomAI } from '@/game/ai'
import { Entity, Resistances } from '@/game/entity'
import { Perk } from '@/game/combat/perks'
import { VoreRelay } from '@/game/events'
@@ -60,7 +60,7 @@ export class Creature extends Entity {
side: Side;
title = "Lv. 1 Creature";
equipment: {[key in EquipmentSlot]?: Equipment } = {}
- ai: AI|null = null
+ ai: AI
constructor (name: Noun, kind: Noun, pronouns: Pronoun, public baseStats: Stats, public preyPrefs: Set, public predPrefs: Set, private baseMass: number) {
super(name, kind, pronouns)
@@ -76,6 +76,8 @@ export class Creature extends Entity {
/* eslint-disable-next-line */
const self = this
+ this.ai = new RandomAI(this)
+
this.voreStats = {
get [VoreStat.Bulk] () {
return self.containers.reduce(
diff --git a/src/game/creatures.ts b/src/game/creatures.ts
index 71a1372..e69de29 100644
--- a/src/game/creatures.ts
+++ b/src/game/creatures.ts
@@ -1,4 +0,0 @@
-import Human from '@/game/creatures/human'
-import Player from '@/game/creatures/player'
-import Inazuma from '@/game/creatures/characters/inazuma'
-export { Human, Player, Inazuma }
diff --git a/src/game/creatures/characters/inazuma.ts b/src/game/creatures/characters/inazuma.ts
index b1acb34..6128c5d 100644
--- a/src/game/creatures/characters/inazuma.ts
+++ b/src/game/creatures/characters/inazuma.ts
@@ -92,7 +92,6 @@ export default class Inazuma extends Creature {
))
this.addVoreContainer(stomach)
-
- this.ai = null
+ this.ai = new VoreAI(this)
}
}
diff --git a/src/game/creatures/monsters/slime.ts b/src/game/creatures/monsters/slime.ts
new file mode 100644
index 0000000..6d5face
--- /dev/null
+++ b/src/game/creatures/monsters/slime.ts
@@ -0,0 +1,39 @@
+import { VoreAI } from '@/game/ai'
+import { DamageType, Side, Stat, StatDamageFormula, Vigor } from '@/game/combat'
+import { Creature } from '@/game/creature'
+import { ImproperNoun, ObjectPronouns } from '@/game/language'
+import { anyVore, Goo } from '@/game/vore'
+
+export default class Slime extends Creature {
+ constructor () {
+ super(
+ new ImproperNoun("slime", "slimes"),
+ new ImproperNoun("slime", "slimes"),
+ ObjectPronouns,
+ {
+ Power: 20,
+ Toughness: 20,
+ Agility: 5,
+ Reflexes: 5,
+ Charm: 5,
+ Willpower: 5
+ },
+ anyVore,
+ anyVore,
+ 50
+ )
+
+ const gooContainer = new Goo(
+ this,
+ 3,
+ new StatDamageFormula([
+ { fraction: 1, stat: Stat.Toughness, type: DamageType.Acid, target: Vigor.Health }
+ ])
+ )
+
+ this.addVoreContainer(gooContainer)
+
+ this.side = Side.Monsters
+ this.ai = new VoreAI(this)
+ }
+}
diff --git a/src/game/creatures/player.ts b/src/game/creatures/player.ts
index 9d4c8e1..e99f334 100644
--- a/src/game/creatures/player.ts
+++ b/src/game/creatures/player.ts
@@ -4,6 +4,7 @@ import { Damage, DamageType, Vigor, ConstantDamageFormula } from '@/game/combat'
import { Stomach, Bowels, anyVore, Cock, Balls, Breasts, InnerBladder, Slit, Womb, biconnectContainers } from '@/game/vore'
import { AttackAction } from '@/game/combat/actions'
import { RavenousPerk, BellyBulwakPerk, FlauntPerk } from '@/game/combat/perks'
+import { VoreAI } from "../ai"
export default class Player extends Creature {
constructor () {
@@ -23,5 +24,7 @@ export default class Player extends Creature {
this.addVoreContainer(stomach)
this.perspective = POV.Second
+
+ this.ai = new VoreAI(this)
}
}
diff --git a/src/game/maps/town.ts b/src/game/maps/town.ts
index 241281d..3ccfecf 100644
--- a/src/game/maps/town.ts
+++ b/src/game/maps/town.ts
@@ -1,7 +1,6 @@
import { Place, Choice, Direction, World } from '@/game/world'
import { ProperNoun, ImproperNoun, MalePronouns, FemalePronouns, TheyPronouns } from '@/game/language'
import { Encounter, Stat, Damage, DamageType, Vigor, Side } from '@/game/combat'
-import * as Creatures from '@/game/creatures'
import * as Items from '@/game/items'
import { LogLine, nilLog, LogLines } from '@/game/interface'
import { Creature } from '@/game/creature'
@@ -10,9 +9,12 @@ import { InstantDigestionEffect, SurrenderEffect } from '@/game/combat/effects'
import moment from 'moment'
import { VoreAI } from '@/game/ai'
import { DeliciousPerk } from '@/game/combat/perks'
+import Inazuma from '../creatures/characters/inazuma'
+import Human from '../creatures/human'
+import Slime from '../creatures/monsters/slime'
function makeParty (): Creature[] {
- const fighter = new Creatures.Human(new ProperNoun("Redgar"), MalePronouns, {
+ const fighter = new Human(new ProperNoun("Redgar"), MalePronouns, {
stats: {
Toughness: 20,
Power: 20,
@@ -24,7 +26,7 @@ function makeParty (): Creature[] {
})
fighter.title = "Lv. 6 Fighter"
fighter.equip(new Items.Sword(), Items.EquipmentSlot.MainHand)
- const rogue = new Creatures.Human(new ProperNoun('Lidda'), FemalePronouns, {
+ const rogue = new Human(new ProperNoun('Lidda'), FemalePronouns, {
stats: {
Toughness: 10,
Power: 15,
@@ -36,7 +38,7 @@ function makeParty (): Creature[] {
})
rogue.title = "Lv. 5 Rogue"
rogue.equip(new Items.Dagger(), Items.EquipmentSlot.MainHand)
- const wizard = new Creatures.Human(new ProperNoun('Mialee'), FemalePronouns, {
+ const wizard = new Human(new ProperNoun('Mialee'), FemalePronouns, {
stats: {
Toughness: 10,
Power: 10,
@@ -48,7 +50,7 @@ function makeParty (): Creature[] {
})
wizard.title = "Lv. 6 Wizard"
wizard.equip(new Items.Wand(), Items.EquipmentSlot.MainHand)
- const cleric = new Creatures.Human(new ProperNoun('Jozan'), MalePronouns, {
+ const cleric = new Human(new ProperNoun('Jozan'), MalePronouns, {
stats: {
Toughness: 15,
Power: 15,
@@ -75,26 +77,6 @@ export const Town = (): Place => {
"Where weird stuff happens"
)
- const westAve = new Place(
- new ImproperNoun('West Avenue'),
- "Streets of Sim City"
- )
-
- const northAve = new Place(
- new ImproperNoun('North Avenue'),
- "Streets of Sim City"
- )
-
- const eastAve = new Place(
- new ImproperNoun('East Avenue'),
- "Streets of Sim City"
- )
-
- const southAve = new Place(
- new ImproperNoun('South Avenue'),
- "Streets of Sim City"
- )
-
const alley = new Place(
new ImproperNoun('alley'),
"A spooky alley"
@@ -123,7 +105,7 @@ export const Town = (): Place => {
const bossEncounters = [
new Encounter(
{ name: "Inazuma", intro: () => nilLog },
- makeParty().concat([new Creatures.Inazuma()])
+ makeParty().concat([new Inazuma()])
)
]
@@ -174,12 +156,12 @@ export const Town = (): Place => {
)
)
- westAve.choices.push(
+ square.choices.push(
new Choice(
"Eat someone",
"Slurp",
(world, executor) => {
- const snack = new Creatures.Human(new ProperNoun(["Snack", "Treat", "Tasty", "Dinner", "Appetizer"][Math.floor(Math.random() * 5)]), [MalePronouns, FemalePronouns, TheyPronouns][Math.floor(Math.random() * 3)])
+ const snack = new Human(new ProperNoun(["Snack", "Treat", "Tasty", "Dinner", "Appetizer"][Math.floor(Math.random() * 5)]), [MalePronouns, FemalePronouns, TheyPronouns][Math.floor(Math.random() * 3)])
snack.applyEffect(new SurrenderEffect())
const options = executor.validActions(snack).filter(action => action instanceof DevourAction)
return options[Math.floor(options.length * Math.random())].execute(executor, snack)
@@ -187,12 +169,12 @@ export const Town = (): Place => {
)
)
- westAve.choices.push(
+ square.choices.push(
new Choice(
"Fight someone",
"Ow",
(world) => {
- const enemy = new Creatures.Human(new ProperNoun("Nerd"), TheyPronouns)
+ const enemy = new Human(new ProperNoun("Nerd"), TheyPronouns)
enemy.side = Side.Monsters
enemy.ai = new VoreAI(enemy)
enemy.equip(new Items.Sword(), Items.EquipmentSlot.MainHand)
@@ -210,12 +192,12 @@ export const Town = (): Place => {
)
)
- westAve.choices.push(
+ square.choices.push(
new Choice(
"Recruit someone",
"Not ow",
(world) => {
- const ally = new Creatures.Human(new ProperNoun("Ally"), TheyPronouns)
+ const ally = new Human(new ProperNoun("Ally"), TheyPronouns)
ally.side = Side.Heroes
ally.ai = new VoreAI(ally)
ally.equip(new Items.Sword(), Items.EquipmentSlot.MainHand)
@@ -339,6 +321,25 @@ export const Town = (): Place => {
)
)
+ woods.choices.push(
+ new Choice(
+ "Fight a slime",
+ "Go fight a slime",
+ (world, executor) => {
+ const enemy = new Slime()
+ const encounter = new Encounter(
+ {
+ name: "Fight some tasty nerd",
+ intro: () => new LogLine(`A slime draws near!`)
+ },
+ [world.player, enemy].concat(world.party)
+ )
+ world.encounter = encounter
+ return nilLog
+ }
+ )
+ )
+
debug.choices.push(
new Choice(
"Add money",
@@ -352,14 +353,9 @@ export const Town = (): Place => {
home.biconnect(Direction.South, debug)
debug.biconnect(Direction.South, bosses)
- home.biconnect(Direction.North, westAve)
- westAve.biconnect(Direction.West, westRoad)
- westAve.biconnect(Direction.North, alley)
+ home.biconnect(Direction.North, square)
westRoad.biconnect(Direction.South, woods)
- square.biconnect(Direction.East, eastAve)
- square.biconnect(Direction.West, westAve)
- square.biconnect(Direction.North, northAve)
- square.biconnect(Direction.South, southAve)
+ square.biconnect(Direction.West, westRoad)
return home
}
diff --git a/src/game/vore.ts b/src/game/vore.ts
index c841c7d..f631194 100644
--- a/src/game/vore.ts
+++ b/src/game/vore.ts
@@ -13,7 +13,8 @@ export enum VoreType {
Unbirth = "Unbirthing",
Breast = "Breast Vore",
Bladder = "Bladder Vore",
- Tail = "Tail Vore"
+ Tail = "Tail Vore",
+ Goo = "Goo Vore"
}
export const anyVore = new Set([
@@ -23,7 +24,8 @@ export const anyVore = new Set([
VoreType.Unbirth,
VoreType.Breast,
VoreType.Bladder,
- VoreType.Tail
+ VoreType.Tail,
+ VoreType.Goo
])
export interface Container extends Actionable {
@@ -408,6 +410,21 @@ export class Tail extends NormalVoreContainer {
}
}
+export class Goo extends NormalVoreContainer {
+ fluidName = new Noun("goo")
+ fluidColor = "#66ee66";
+
+ constructor (owner: Creature, capacity: number, damage: DamageFormula) {
+ super(new ImproperNoun('goo', 'goo').all, owner, new Set([VoreType.Goo]), capacity, damage)
+ }
+
+ tickLine (user: Creature, target: Creature, args: { damage: Damage }) {
+ return new RandomEntry(
+ new LogLine(`${user.name.capital} ${user.name.conjugate(Words.Clench)} ${target.name.objective} in ${user.pronouns.possessive} ${this.name} for `, args.damage.renderShort(), `.`)
+ )
+ }
+}
+
export class Cock extends NormalVoreContainer {
fluidName = new Noun("cum")