Control is now determined by whether or not something is viewed in third person.master
| @@ -4,6 +4,7 @@ | |||||
| <div id="main-area"> | <div id="main-area"> | ||||
| <transition name="component-fade" mode='out-in'> | <transition name="component-fade" mode='out-in'> | ||||
| <component | <component | ||||
| @control="control" | |||||
| @profile="profile" | @profile="profile" | ||||
| @exit="$data.profileSubject = null" | @exit="$data.profileSubject = null" | ||||
| @give-in="gameOver()" | @give-in="gameOver()" | ||||
| @@ -23,7 +24,6 @@ import Header from '@/components/Header.vue' | |||||
| import Combat from '@/components/Combat.vue' | import Combat from '@/components/Combat.vue' | ||||
| import Explore from '@/components/Explore.vue' | import Explore from '@/components/Explore.vue' | ||||
| import Profile from '@/components/Profile.vue' | import Profile from '@/components/Profile.vue' | ||||
| import * as Creatures from '@/game/creatures' | |||||
| import * as Items from '@/game/items' | import * as Items from '@/game/items' | ||||
| import { Creature } from '@/game/creature' | import { Creature } from '@/game/creature' | ||||
| import { ProperNoun, TheyPronouns, FemalePronouns, MalePronouns, ImproperNoun, POV } from '@/game/language' | import { ProperNoun, TheyPronouns, FemalePronouns, MalePronouns, ImproperNoun, POV } from '@/game/language' | ||||
| @@ -33,6 +33,7 @@ import { LogLine, nilLog } from '@/game/interface' | |||||
| import { InstantKillEffect } from '@/game/combat/effects' | import { InstantKillEffect } from '@/game/combat/effects' | ||||
| import moment from 'moment' | import moment from 'moment' | ||||
| import { Town } from '@/game/maps/town' | import { Town } from '@/game/maps/town' | ||||
| import Player from './game/creatures/player' | |||||
| @Component({ | @Component({ | ||||
| components: { | components: { | ||||
| @@ -74,7 +75,7 @@ export default class App extends Vue { | |||||
| } | } | ||||
| created () { | created () { | ||||
| const player = new Creatures.Player() | |||||
| const player = new Player() | |||||
| player.perspective = POV.Second | player.perspective = POV.Second | ||||
| player.side = Side.Heroes | player.side = Side.Heroes | ||||
| player.equipment[Items.EquipmentSlot.MainHand] = new Items.Sword() | player.equipment[Items.EquipmentSlot.MainHand] = new Items.Sword() | ||||
| @@ -95,6 +96,12 @@ export default class App extends Vue { | |||||
| profile (subject: Creature) { | profile (subject: Creature) { | ||||
| this.$data.profileSubject = subject | this.$data.profileSubject = subject | ||||
| } | } | ||||
| control (subject: Creature) { | |||||
| this.$data.world.player.perspective = POV.Third | |||||
| this.$data.world.player = subject | |||||
| subject.perspective = POV.Second | |||||
| } | |||||
| } | } | ||||
| </script> | </script> | ||||
| @@ -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) { | if (this.encounter.currentMove.side === Side.Heroes) { | ||||
| this.executedLeft(this.encounter.currentMove.ai.decide(this.encounter.currentMove, this.encounter)) | this.executedLeft(this.encounter.currentMove.ai.decide(this.encounter.currentMove, this.encounter)) | ||||
| } else { | } else { | ||||
| @@ -57,9 +57,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <button @click.stop="subject.perspective = POV.First">1st</button> | |||||
| <button @click.stop="subject.perspective = POV.Second">2nd</button> | |||||
| <button @click.stop="subject.perspective = POV.Third">3rd</button> | |||||
| <button @click="$emit('control', subject)">Control</button> | |||||
| <button class="show-profile" @click="$emit('profile', subject)">Show profile</button> | <button class="show-profile" @click="$emit('profile', subject)">Show profile</button> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -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 | * The VoreAI tries to eat opponents, but only if the odds are good enough | ||||
| */ | */ | ||||
| @@ -4,7 +4,7 @@ import { LogEntry, LogLines, LogLine } from '@/game/interface' | |||||
| import { VoreContainer, VoreType, Container } from '@/game/vore' | import { VoreContainer, VoreType, Container } from '@/game/vore' | ||||
| import { Item, EquipmentSlot, Equipment, ItemKind, Currency } from '@/game/items' | import { Item, EquipmentSlot, Equipment, ItemKind, Currency } from '@/game/items' | ||||
| import { PassAction } from '@/game/combat/actions' | import { PassAction } from '@/game/combat/actions' | ||||
| import { AI } from '@/game/ai' | |||||
| import { AI, RandomAI } from '@/game/ai' | |||||
| import { Entity, Resistances } from '@/game/entity' | import { Entity, Resistances } from '@/game/entity' | ||||
| import { Perk } from '@/game/combat/perks' | import { Perk } from '@/game/combat/perks' | ||||
| import { VoreRelay } from '@/game/events' | import { VoreRelay } from '@/game/events' | ||||
| @@ -60,7 +60,7 @@ export class Creature extends Entity { | |||||
| side: Side; | side: Side; | ||||
| title = "Lv. 1 Creature"; | title = "Lv. 1 Creature"; | ||||
| equipment: {[key in EquipmentSlot]?: Equipment } = {} | equipment: {[key in EquipmentSlot]?: Equipment } = {} | ||||
| ai: AI|null = null | |||||
| ai: AI | |||||
| constructor (name: Noun, kind: Noun, pronouns: Pronoun, public baseStats: Stats, public preyPrefs: Set<VoreType>, public predPrefs: Set<VoreType>, private baseMass: number) { | constructor (name: Noun, kind: Noun, pronouns: Pronoun, public baseStats: Stats, public preyPrefs: Set<VoreType>, public predPrefs: Set<VoreType>, private baseMass: number) { | ||||
| super(name, kind, pronouns) | super(name, kind, pronouns) | ||||
| @@ -76,6 +76,8 @@ export class Creature extends Entity { | |||||
| /* eslint-disable-next-line */ | /* eslint-disable-next-line */ | ||||
| const self = this | const self = this | ||||
| this.ai = new RandomAI(this) | |||||
| this.voreStats = { | this.voreStats = { | ||||
| get [VoreStat.Bulk] () { | get [VoreStat.Bulk] () { | ||||
| return self.containers.reduce( | return self.containers.reduce( | ||||
| @@ -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 } | |||||
| @@ -92,7 +92,6 @@ export default class Inazuma extends Creature { | |||||
| )) | )) | ||||
| this.addVoreContainer(stomach) | this.addVoreContainer(stomach) | ||||
| this.ai = null | |||||
| this.ai = new VoreAI(this) | |||||
| } | } | ||||
| } | } | ||||
| @@ -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) | |||||
| } | |||||
| } | |||||
| @@ -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 { Stomach, Bowels, anyVore, Cock, Balls, Breasts, InnerBladder, Slit, Womb, biconnectContainers } from '@/game/vore' | ||||
| import { AttackAction } from '@/game/combat/actions' | import { AttackAction } from '@/game/combat/actions' | ||||
| import { RavenousPerk, BellyBulwakPerk, FlauntPerk } from '@/game/combat/perks' | import { RavenousPerk, BellyBulwakPerk, FlauntPerk } from '@/game/combat/perks' | ||||
| import { VoreAI } from "../ai" | |||||
| export default class Player extends Creature { | export default class Player extends Creature { | ||||
| constructor () { | constructor () { | ||||
| @@ -23,5 +24,7 @@ export default class Player extends Creature { | |||||
| this.addVoreContainer(stomach) | this.addVoreContainer(stomach) | ||||
| this.perspective = POV.Second | this.perspective = POV.Second | ||||
| this.ai = new VoreAI(this) | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,7 +1,6 @@ | |||||
| import { Place, Choice, Direction, World } from '@/game/world' | import { Place, Choice, Direction, World } from '@/game/world' | ||||
| import { ProperNoun, ImproperNoun, MalePronouns, FemalePronouns, TheyPronouns } from '@/game/language' | import { ProperNoun, ImproperNoun, MalePronouns, FemalePronouns, TheyPronouns } from '@/game/language' | ||||
| import { Encounter, Stat, Damage, DamageType, Vigor, Side } from '@/game/combat' | import { Encounter, Stat, Damage, DamageType, Vigor, Side } from '@/game/combat' | ||||
| import * as Creatures from '@/game/creatures' | |||||
| import * as Items from '@/game/items' | import * as Items from '@/game/items' | ||||
| import { LogLine, nilLog, LogLines } from '@/game/interface' | import { LogLine, nilLog, LogLines } from '@/game/interface' | ||||
| import { Creature } from '@/game/creature' | import { Creature } from '@/game/creature' | ||||
| @@ -10,9 +9,12 @@ import { InstantDigestionEffect, SurrenderEffect } from '@/game/combat/effects' | |||||
| import moment from 'moment' | import moment from 'moment' | ||||
| import { VoreAI } from '@/game/ai' | import { VoreAI } from '@/game/ai' | ||||
| import { DeliciousPerk } from '@/game/combat/perks' | 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[] { | function makeParty (): Creature[] { | ||||
| const fighter = new Creatures.Human(new ProperNoun("Redgar"), MalePronouns, { | |||||
| const fighter = new Human(new ProperNoun("Redgar"), MalePronouns, { | |||||
| stats: { | stats: { | ||||
| Toughness: 20, | Toughness: 20, | ||||
| Power: 20, | Power: 20, | ||||
| @@ -24,7 +26,7 @@ function makeParty (): Creature[] { | |||||
| }) | }) | ||||
| fighter.title = "Lv. 6 Fighter" | fighter.title = "Lv. 6 Fighter" | ||||
| fighter.equip(new Items.Sword(), Items.EquipmentSlot.MainHand) | 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: { | stats: { | ||||
| Toughness: 10, | Toughness: 10, | ||||
| Power: 15, | Power: 15, | ||||
| @@ -36,7 +38,7 @@ function makeParty (): Creature[] { | |||||
| }) | }) | ||||
| rogue.title = "Lv. 5 Rogue" | rogue.title = "Lv. 5 Rogue" | ||||
| rogue.equip(new Items.Dagger(), Items.EquipmentSlot.MainHand) | 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: { | stats: { | ||||
| Toughness: 10, | Toughness: 10, | ||||
| Power: 10, | Power: 10, | ||||
| @@ -48,7 +50,7 @@ function makeParty (): Creature[] { | |||||
| }) | }) | ||||
| wizard.title = "Lv. 6 Wizard" | wizard.title = "Lv. 6 Wizard" | ||||
| wizard.equip(new Items.Wand(), Items.EquipmentSlot.MainHand) | 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: { | stats: { | ||||
| Toughness: 15, | Toughness: 15, | ||||
| Power: 15, | Power: 15, | ||||
| @@ -75,26 +77,6 @@ export const Town = (): Place => { | |||||
| "Where weird stuff happens" | "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( | const alley = new Place( | ||||
| new ImproperNoun('alley'), | new ImproperNoun('alley'), | ||||
| "A spooky alley" | "A spooky alley" | ||||
| @@ -123,7 +105,7 @@ export const Town = (): Place => { | |||||
| const bossEncounters = [ | const bossEncounters = [ | ||||
| new Encounter( | new Encounter( | ||||
| { name: "Inazuma", intro: () => nilLog }, | { 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( | new Choice( | ||||
| "Eat someone", | "Eat someone", | ||||
| "Slurp", | "Slurp", | ||||
| (world, executor) => { | (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()) | snack.applyEffect(new SurrenderEffect()) | ||||
| const options = executor.validActions(snack).filter(action => action instanceof DevourAction) | const options = executor.validActions(snack).filter(action => action instanceof DevourAction) | ||||
| return options[Math.floor(options.length * Math.random())].execute(executor, snack) | 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( | new Choice( | ||||
| "Fight someone", | "Fight someone", | ||||
| "Ow", | "Ow", | ||||
| (world) => { | (world) => { | ||||
| const enemy = new Creatures.Human(new ProperNoun("Nerd"), TheyPronouns) | |||||
| const enemy = new Human(new ProperNoun("Nerd"), TheyPronouns) | |||||
| enemy.side = Side.Monsters | enemy.side = Side.Monsters | ||||
| enemy.ai = new VoreAI(enemy) | enemy.ai = new VoreAI(enemy) | ||||
| enemy.equip(new Items.Sword(), Items.EquipmentSlot.MainHand) | enemy.equip(new Items.Sword(), Items.EquipmentSlot.MainHand) | ||||
| @@ -210,12 +192,12 @@ export const Town = (): Place => { | |||||
| ) | ) | ||||
| ) | ) | ||||
| westAve.choices.push( | |||||
| square.choices.push( | |||||
| new Choice( | new Choice( | ||||
| "Recruit someone", | "Recruit someone", | ||||
| "Not ow", | "Not ow", | ||||
| (world) => { | (world) => { | ||||
| const ally = new Creatures.Human(new ProperNoun("Ally"), TheyPronouns) | |||||
| const ally = new Human(new ProperNoun("Ally"), TheyPronouns) | |||||
| ally.side = Side.Heroes | ally.side = Side.Heroes | ||||
| ally.ai = new VoreAI(ally) | ally.ai = new VoreAI(ally) | ||||
| ally.equip(new Items.Sword(), Items.EquipmentSlot.MainHand) | 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( | debug.choices.push( | ||||
| new Choice( | new Choice( | ||||
| "Add money", | "Add money", | ||||
| @@ -352,14 +353,9 @@ export const Town = (): Place => { | |||||
| home.biconnect(Direction.South, debug) | home.biconnect(Direction.South, debug) | ||||
| debug.biconnect(Direction.South, bosses) | 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) | 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 | return home | ||||
| } | } | ||||
| @@ -13,7 +13,8 @@ export enum VoreType { | |||||
| Unbirth = "Unbirthing", | Unbirth = "Unbirthing", | ||||
| Breast = "Breast Vore", | Breast = "Breast Vore", | ||||
| Bladder = "Bladder Vore", | Bladder = "Bladder Vore", | ||||
| Tail = "Tail Vore" | |||||
| Tail = "Tail Vore", | |||||
| Goo = "Goo Vore" | |||||
| } | } | ||||
| export const anyVore = new Set([ | export const anyVore = new Set([ | ||||
| @@ -23,7 +24,8 @@ export const anyVore = new Set([ | |||||
| VoreType.Unbirth, | VoreType.Unbirth, | ||||
| VoreType.Breast, | VoreType.Breast, | ||||
| VoreType.Bladder, | VoreType.Bladder, | ||||
| VoreType.Tail | |||||
| VoreType.Tail, | |||||
| VoreType.Goo | |||||
| ]) | ]) | ||||
| export interface Container extends Actionable { | 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 { | export class Cock extends NormalVoreContainer { | ||||
| fluidName = new Noun("cum") | fluidName = new Noun("cum") | ||||