From 593a85dc45bb04a3eb4288d239e2ef0ce7796fa3 Mon Sep 17 00:00:00 2001 From: Fen Dweller Date: Mon, 3 Aug 2020 16:02:09 -0400 Subject: [PATCH] Add waves to container views and more vore types for wolves --- src/components/ContainerView.vue | 95 ++++++++++++++++++++++++-------- src/components/Explore.vue | 28 +++++++--- src/game/creatures/human.ts | 2 +- src/game/creatures/wolf.ts | 23 ++++++-- src/game/maps/town.ts | 17 +++++- src/game/vore.ts | 45 +++++++++++++-- src/game/world.ts | 14 +++-- 7 files changed, 179 insertions(+), 45 deletions(-) diff --git a/src/components/ContainerView.vue b/src/components/ContainerView.vue index 4bc3e08..82b5a11 100644 --- a/src/components/ContainerView.vue +++ b/src/components/ContainerView.vue @@ -1,8 +1,12 @@ @@ -11,34 +15,81 @@ import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator' import { Creature } from '@/game/creature' import { POV } from '@/game/language' import { Stats, Stat } from '@/game/combat' -import { Container } from '@/game/vore' +import { Container, VoreContainer, Vore } from '@/game/vore' + +// yoinked from https://jsfiddle.net/yckart/0adfw47y/ + +function draw (delta: number, dt: number, total: number, parent: HTMLElement, canvas: HTMLCanvasElement, container: VoreContainer) { + const ctx = canvas.getContext('2d') as CanvasRenderingContext2D + + canvas.width = parent.clientWidth + canvas.height = parent.clientHeight + ctx.fillStyle = container.fluidColor + const fraction = container.fullness / container.capacity + const livingFraction = container.contents.reduce((total: number, prey: Vore) => total + prey.voreStats.Bulk, 0) / container.capacity + const deadFraction = container.digested.reduce((total: number, prey: Vore) => total + prey.voreStats.Bulk, 0) / container.capacity + const liveliness = livingFraction + deadFraction * 0.5 + + total += dt * liveliness + + requestAnimationFrame((newDelta: number) => draw(newDelta, newDelta - delta, total, parent, canvas, container)) + + const randomLeft = Math.abs(Math.pow(Math.sin(total / 1000), 2)) * fraction * 100 + (1 - fraction) * canvas.height + const randomRight = Math.abs(Math.pow(Math.sin((total / 1000) + 10), 2)) * fraction * 100 + (1 - fraction) * canvas.height + const randomLeftConstraint = Math.abs(Math.pow(Math.sin((total / 1000) + 2), 2)) * fraction * 100 + (1 - fraction) * canvas.height + const randomRightConstraint = Math.abs(Math.pow(Math.sin((total / 1000) + 1), 2)) * fraction * 100 + (1 - fraction) * canvas.height + + ctx.beginPath() + ctx.moveTo(0, randomLeft) + + ctx.bezierCurveTo(canvas.width / 3, randomLeftConstraint, canvas.width / 3 * 2, randomRightConstraint, canvas.width, randomRight) + ctx.lineTo(canvas.width, canvas.height) + ctx.lineTo(0, canvas.height) + ctx.lineTo(0, randomLeft) + + ctx.closePath() + ctx.fill() +} @Component export default class ContainerView extends Vue { @Prop({ required: true }) container!: Container - constructor () { - super() + mounted () { + if ((this.container as VoreContainer).fluidColor !== undefined) { + const canvas = this.$el.querySelector('.container-waves') as HTMLCanvasElement + + canvas.width = (this.$el as HTMLElement).clientWidth + canvas.height = (this.$el as HTMLElement).clientHeight + canvas.width = canvas.width + 0 + requestAnimationFrame((delta: number) => draw(delta, delta, Math.random() * 1000, this.$el as HTMLElement, canvas, (this.container as VoreContainer))) + } } } + diff --git a/src/components/Explore.vue b/src/components/Explore.vue index 7f8223f..759c562 100644 --- a/src/components/Explore.vue +++ b/src/components/Explore.vue @@ -8,6 +8,9 @@

{{ world.time.format("hh:mm:ss a") }}

+
+ +

{{ location.name.capital }}

{{ location.desc }}

@@ -28,11 +31,12 @@ import { Direction, World, Place } from '@/game/world' import NavButton from './NavButton.vue' import ChoiceButton from './ChoiceButton.vue' import Statblock from './Statblock.vue' +import ContainerView from './ContainerView.vue' import { LogEntry } from '@/game/interface' @Component({ components: { - NavButton, ChoiceButton, Statblock + NavButton, ChoiceButton, Statblock, ContainerView }, data () { return { @@ -89,18 +93,26 @@ export default class Explore extends Vue { flex: 10; position: relative; display: grid; - grid-template-areas: "log worldinfo" - "log statblock" - "log info " - "log choices " - "nav choices "; - grid-template-rows: 0.5fr fit-content(250pt) 2fr 1fr 1fr; - grid-template-columns: 2fr 1fr; + grid-template-areas: "statblock containers containers" + "log log worldinfo" + "log log info " + "log log choices " + "nav nav choices "; + grid-template-rows: fit-content(30%) fit-content(250pt) 2fr 1fr 1fr; + grid-template-columns: 1fr 1fr 1fr; width: 100%; height: 100%; overflow: hidden; } +.explore-containers { + grid-area: containers; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + overflow-x: scroll; +} + .explore-log { grid-area: log; background: #222; diff --git a/src/game/creatures/human.ts b/src/game/creatures/human.ts index ee8b324..7cde43a 100644 --- a/src/game/creatures/human.ts +++ b/src/game/creatures/human.ts @@ -21,7 +21,7 @@ export class Human extends Creature { } else { stats = options.stats } - super(name, new ImproperNoun('human', 'humans'), pronouns, stats, new Set([VoreType.Oral, VoreType.Anal]), new Set([VoreType.Oral, VoreType.Anal]), 25) + super(name, new ImproperNoun('human', 'humans'), pronouns, stats, new Set([VoreType.Oral, VoreType.Anal, VoreType.Cock, VoreType.Unbirth]), new Set([VoreType.Oral, VoreType.Anal]), 25) this.title = "Snack" this.desc = "Definitely going on an adventure" diff --git a/src/game/creatures/wolf.ts b/src/game/creatures/wolf.ts index 180f62c..2fa0f3d 100644 --- a/src/game/creatures/wolf.ts +++ b/src/game/creatures/wolf.ts @@ -1,12 +1,13 @@ import { Creature } from "../creature" import { Damage, DamageType, ConstantDamageFormula, Vigor, Side } from '../combat' -import { MalePronouns, ImproperNoun } from '../language' -import { VoreType, Stomach, Bowels } from '../vore' +import { MalePronouns, ImproperNoun, ProperNoun, ObjectPronouns } from '../language' +import { VoreType, Stomach, Bowels, Cock, Balls } from '../vore' import { AttackAction, TransferAction, FeedAction } from '../combat/actions' +import { Human } from '../creatures' export class Wolf extends Creature { constructor () { - super(new ImproperNoun('wolf', 'wolves'), new ImproperNoun('wolf', 'wolves'), MalePronouns, { Toughness: 20, Power: 20, Speed: 20, Willpower: 20, Charm: 20 }, new Set([VoreType.Oral, VoreType.Anal]), new Set([VoreType.Oral, VoreType.Anal]), 25) + super(new ImproperNoun('wolf', 'wolves'), new ImproperNoun('wolf', 'wolves'), MalePronouns, { Toughness: 20, Power: 20, Speed: 20, Willpower: 20, Charm: 20 }, new Set([VoreType.Oral, VoreType.Anal, VoreType.Cock]), new Set([VoreType.Oral, VoreType.Anal, VoreType.Cock]), 25) this.actions.push( new AttackAction( new ConstantDamageFormula( @@ -24,7 +25,6 @@ export class Wolf extends Creature { { amount: 30, type: DamageType.Crush, target: Vigor.Stamina }, { amount: 30, type: DamageType.Dominance, target: Vigor.Resolve } )) - this.containers.push(stomach) const bowels = new Bowels(this, 50, new Damage( @@ -38,5 +38,20 @@ export class Wolf extends Creature { this.actions.push(new TransferAction(bowels, stomach)) this.otherActions.push(new FeedAction(stomach)) + + const cock = new Cock(this, 50, new Damage( + { amount: 30, type: DamageType.Crush, target: Vigor.Health }, + { amount: 60, type: DamageType.Crush, target: Vigor.Stamina }, + { amount: 60, type: DamageType.Dominance, target: Vigor.Resolve } + )) + + const balls = new Balls(this, 50, new Damage( + { amount: 30, type: DamageType.Crush, target: Vigor.Health }, + { amount: 60, type: DamageType.Crush, target: Vigor.Stamina }, + { amount: 60, type: DamageType.Dominance, target: Vigor.Resolve } + ), cock) + + this.containers.push(balls) + this.containers.push(cock) } } diff --git a/src/game/maps/town.ts b/src/game/maps/town.ts index 984ce4e..52cf868 100644 --- a/src/game/maps/town.ts +++ b/src/game/maps/town.ts @@ -1,10 +1,12 @@ import { Place, Choice, Direction } from '../world' -import { ProperNoun, ImproperNoun, MalePronouns, FemalePronouns } from '../language' +import { ProperNoun, ImproperNoun, MalePronouns, FemalePronouns, TheyPronouns } from '../language' import { Encounter } from '../combat' import * as Creatures from '../creatures' import * as Items from '../items' import { LogLine, nilLog } from '../interface' import { Creature } from '../creature' +import { DevourAction } from '../combat/actions' +import { SurrenderEffect } from '../combat/effects' function makeParty (): Creature[] { const fighter = new Creatures.Human(new ProperNoun("Redgar"), MalePronouns, { @@ -126,6 +128,19 @@ export const Town = (): Place => { ) ] + home.choices.push( + new Choice( + "Eat someone", + "Slurp", + (world, executor) => { + const snack = new Creatures.Human(new ProperNoun("Snack"), TheyPronouns) + 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) + } + ) + ) + bossEncounters.forEach(encounter => { bosses.choices.push( new Choice( diff --git a/src/game/vore.ts b/src/game/vore.ts index e8ca133..b7ee244 100644 --- a/src/game/vore.ts +++ b/src/game/vore.ts @@ -123,9 +123,9 @@ export abstract class NormalContainer implements Container { contents: Array = [] actions: Array = [] - abstract consumeVerb: Verb - abstract releaseVerb: Verb - abstract struggleVerb: Verb + consumeVerb = new Verb('trap') + releaseVerb = new Verb('release', 'releases', 'releasing', 'released') + struggleVerb = new Verb('struggle', 'struggles', 'struggling', 'struggled') constructor (name: Noun, public owner: Vore, public voreTypes: Set, public capacity: number) { this.name = name.all @@ -214,12 +214,14 @@ export interface VoreContainer extends Container { digested: Array; tick: (dt: number) => LogEntry; digest: (preys: Vore[]) => LogEntry; + fluidColor: string; } export abstract class NormalVoreContainer extends NormalContainer implements VoreContainer { consumeVerb = new Verb('devour') releaseVerb = new Verb('release', 'releases', 'releasing', 'released') struggleVerb = new Verb('struggle', 'struggles', 'struggling', 'struggled') + fluidColor = "#00ff0088" digested: Array = [] @@ -231,6 +233,10 @@ export abstract class NormalVoreContainer extends NormalContainer implements Vor this.actions.push(new DigestAction(this)) } + get fullness (): number { + return Array.from(this.contents.concat(this.digested).values()).reduce((total: number, prey: Vore) => total + prey.voreStats.Bulk, 0) + } + consumeLine: PairLineArgs = (user, target, args) => { return new LogLine(`${user.name.capital} ${user.name.conjugate(this.consumeVerb)} ${target.name.objective}, forcing ${target.pronouns.objective} into ${user.pronouns.possessive} ${args.container.name}.`) } @@ -240,7 +246,7 @@ export abstract class NormalVoreContainer extends NormalContainer implements Vor } digestLine: PairLineArgs = (user, target, args) => { - return new LogLine(`${user.name.capital.possessive} ${args.container.name} finishes ${Words.Digests.present} ${target.name.objective} down, ${target.pronouns.possessive} ${Words.Struggles.singular} fading away.`) + return new LogLine(`${user.name.capital.possessive} ${args.container.name} ${args.container.name.conjugate(new Verb('finish', 'finishes'))} ${Words.Digests.present} ${target.name.objective} down, ${target.pronouns.possessive} ${Words.Struggles.singular} fading away.`) } tick (dt: number): LogEntry { @@ -328,6 +334,35 @@ export class InnerStomach extends InnerVoreContainer { export class Bowels extends NormalVoreContainer { constructor (owner: Vore, capacity: number, damage: Damage) { - super(new ImproperNoun('bowel', 'bowels').plural, owner, new Set([VoreType.Anal]), capacity, damage) + super(new ImproperNoun('bowel', 'bowels').plural.all, owner, new Set([VoreType.Anal]), capacity, damage) + } +} + +export class Cock extends NormalVoreContainer { + fluidColor = "#eeeeee66"; + + constructor (owner: Vore, capacity: number, damage: Damage) { + super( + new ImproperNoun('cock').all, + owner, + new Set([VoreType.Cock]), + capacity, + damage + ) + } +} + +export class Balls extends InnerVoreContainer { + fluidColor = "#eeeeeecc"; + + constructor (owner: Vore, capacity: number, damage: Damage, escape: Container) { + super( + new ImproperNoun('ball', 'balls').all.plural, + owner, + new Set([VoreType.Cock]), + capacity, + damage, + escape + ) } } diff --git a/src/game/world.ts b/src/game/world.ts index 1d74c37..22222e8 100644 --- a/src/game/world.ts +++ b/src/game/world.ts @@ -2,7 +2,7 @@ import { TextLike, Verb, Noun, ProperNoun } from './language' import { Entity } from './entity' import { Creature } from './creature' import moment, { Moment, Duration } from 'moment' -import { LogEntry, LogLine } from './interface' +import { LogEntry, LogLine, LogLines } from './interface' import { Encounter } from './combat' export enum Direction { @@ -57,9 +57,10 @@ export class Connection { } travel (world: World, traveler: Creature): LogEntry { - world.advance(moment.duration(5, "minutes")) + const advanceLogs = world.advance(moment.duration(5, "minutes")) traveler.location = this.dst - return new LogLine( + return new LogLines( + advanceLogs, `${traveler.name.capital} ${traveler.name.conjugate(new Verb('travel'))} to ${this.dst.name}.` ) } @@ -98,7 +99,12 @@ export class World { this.creatures.push(player) } - advance (dt: Duration) { + advance (dt: Duration): LogEntry { this.time.add(dt) + return new LogLines( + ...this.player.containers.map( + container => container.tick(dt.asSeconds()) + ) + ) } }