瀏覽代碼

Add onomatopoeia, separate entering from consuming

Containers have separate methods for consuming prey and
having prey enter them: the latter is used for transfers.
Also makes the left-side characters align to the right.
I forget why I didn't do that; it was probably a browser bug.
Also lets you become a werewolf.
master
Fen Dweller 3 年之前
父節點
當前提交
c2681a2668
共有 10 個檔案被更改,包括 189 行新增18 行删除
  1. +14
    -0
      src/App.vue
  2. +1
    -1
      src/components/Combat.vue
  3. +8
    -3
      src/game/combat/actions.ts
  4. +1
    -0
      src/game/creatures/monsters/werewolf.ts
  5. +3
    -1
      src/game/events.ts
  6. +2
    -1
      src/game/interface.ts
  7. +26
    -0
      src/game/language.ts
  8. +15
    -1
      src/game/maps/town.ts
  9. +58
    -0
      src/game/onomatopoeia.ts
  10. +61
    -11
      src/game/vore.ts

+ 14
- 0
src/App.vue 查看文件

@@ -193,4 +193,18 @@ html {
/* .component-fade-leave-active below version 2.1.8 */ {
opacity: 0;
}

.onomatopoeia {
font-weight: bold;
font-style: italic;
font-size: 200%;
animation: fly-in 0.4s;
animation-timing-function: ease-out;
display: inline-block;
}

@keyframes fly-in {
0% { transform: scale(0, 0); opacity: 0 };
100% { transform: scale(1, 1); opacity: 1 };
}
</style>

+ 1
- 1
src/components/Combat.vue 查看文件

@@ -386,7 +386,7 @@ export default class Combat extends Vue {
}

.left-stats {
flex-direction: row;
flex-direction: row-reverse;
}

.right-stats {


+ 8
- 3
src/game/combat/actions.ts 查看文件

@@ -338,9 +338,14 @@ export class TransferAction extends Action {
}

execute (user: Creature, target: Creature): LogEntry {
this.from.release(target)
this.to.destination.consume(target)
return this.line(user, target, { from: this.from, to: this.to })
const results = [
this.from.exit(target),
this.line(user, target, { from: this.from, to: this.to }),
this.to.destination.enter(target)

]

return new LogLines(...results)
}

describe (user: Creature, target: Creature): LogEntry {


+ 1
- 0
src/game/creatures/monsters/werewolf.ts 查看文件

@@ -1,5 +1,6 @@
import { VoreAI } from '@/game/ai'
import { DamageType, Side, Stat, StatDamageFormula, Vigor } from '@/game/combat'
import { DigestionPowerEffect } from '@/game/combat/effects'
import { Creature } from '@/game/creature'
import { LogEntry, LogLine } from '@/game/interface'
import { ImproperNoun, MalePronouns, ObjectPronouns, Preposition, Verb } from '@/game/language'


+ 3
- 1
src/game/events.ts 查看文件

@@ -43,13 +43,15 @@ abstract class Relay<Sender, EventMap extends { [name: string]: any }> {
type VoreMap = {
"onEaten": { prey: Creature };
"onReleased": { prey: Creature };
"onEntered": { prey: Creature };
"onExited": { prey: Creature };
"onDigested": { prey: Creature };
"onAbsorbed": { prey: Creature };
}

export class VoreRelay extends Relay<Container, VoreMap> {
constructor () {
super(["onEaten", "onReleased", "onDigested", "onAbsorbed"])
super(["onEaten", "onReleased", "onEntered", "onExited", "onDigested", "onAbsorbed"])
}
}



+ 2
- 1
src/game/interface.ts 查看文件

@@ -55,7 +55,8 @@ export class LogLines implements LogEntry {

export enum FormatOpt {
Damage = "log-damage",
DamageInst = "damage-instance"
DamageInst = "damage-instance",
Onomatopoeia = "onomatopoeia"
}

/**


+ 26
- 0
src/game/language.ts 查看文件

@@ -1,4 +1,5 @@
import { LogEntry } from "@/game/interface"
import { parseTwoDigitYear } from "moment"

export enum POV {
First,
@@ -574,6 +575,31 @@ export class Pronoun implements Pluralizable {
}
}

export type OnomatopoeiaPart = [string, number, number]

export class Onomatopoeia extends Word {
constructor (protected parts: Array<OnomatopoeiaPart>, public opts: WordOptions = emptyConfig) {
super(opts)
}

configure (opts: WordOptions): Word {
return new Onomatopoeia(this.parts, opts)
}

toString (): string {
const built = this.parts.reduce((result, next) => {
const [piece, min, max] = next
const count = Math.floor(Math.random() * (max - min)) + min
for (let i = 0; i < count; i++) {
result += piece
}
return result
}, "")

return built
}
}

export const MalePronouns = new Pronoun({
subjective: "he",
objective: "him",


+ 15
- 1
src/game/maps/town.ts 查看文件

@@ -1,5 +1,5 @@
import { Place, Choice, Direction, World } from '@/game/world'
import { ProperNoun, ImproperNoun, MalePronouns, FemalePronouns, TheyPronouns } from '@/game/language'
import { ProperNoun, ImproperNoun, MalePronouns, FemalePronouns, TheyPronouns, POV } from '@/game/language'
import { Encounter, Stat, Damage, DamageType, Vigor, Side } from '@/game/combat'
import * as Items from '@/game/items'
import { LogLine, nilLog, LogLines } from '@/game/interface'
@@ -148,6 +148,20 @@ export const Town = (): Place => {
)
)

home.choices.push(
new Choice(
"Become a werewolf",
"Yum",
(world, executor) => {
world.player = new Werewolf()
world.player.location = home
world.player.perspective = POV.Second
world.player.side = Side.Heroes
return new LogLine("Nice")
}
)
)

square.choices.push(
new Choice(
"Eat someone",


+ 58
- 0
src/game/onomatopoeia.ts 查看文件

@@ -0,0 +1,58 @@
import { Onomatopoeia, RandomWord } from "./language"

export const Swallow = new RandomWord([
new Onomatopoeia([
["GL", 1, 1],
["U", 1, 10],
["R", 1, 3],
["K", 1, 1],
["!", 1, 3]
]),
new Onomatopoeia([
["GL", 1, 1],
["U", 1, 3],
["NK", 1, 1],
["!", 1, 3]
]),
new Onomatopoeia([
["G", 1, 1],
["L", 1, 3],
["U", 1, 3],
["RSH", 1, 1],
["!", 1, 3]
])
])

export const Glunk = new RandomWord([
new Onomatopoeia([
["G", 1, 1],
["L", 2, 4],
["U", 1, 3],
["NK", 1, 1],
["!", 1, 1]
]),
new Onomatopoeia([
["GL", 1, 1],
["O", 2, 5],
["RSH", 1, 1],
["!", 1, 1]
])
])

export const Gurgle = new RandomWord([
new Onomatopoeia([
["g", 1, 1],
["w", 1, 3],
["o", 1, 3],
["r", 1, 2],
["b", 1, 3],
["le", 1, 1]
]),
new Onomatopoeia([
["g", 2, 5],
["r", 3, 7],
["rg", 1, 1],
["l", 1, 3],
["e", 1, 1]
])
])

+ 61
- 11
src/game/vore.ts 查看文件

@@ -1,8 +1,9 @@
import { Damage, DamageType, Actionable, Action, Vigor, DamageInstance, DamageFormula, ConstantDamageFormula } from '@/game/combat'
import { LogLines, LogEntry, LogLine, nilLog, RandomEntry } from '@/game/interface'
import { LogLines, LogEntry, LogLine, nilLog, RandomEntry, FormatEntry, FormatOpt } from '@/game/interface'
import { Noun, ImproperNoun, Verb, RandomWord, Word, Preposition, ToBe, Adjective } from '@/game/language'
import { RubAction, DevourAction, ReleaseAction, StruggleAction, TransferAction, StruggleMoveAction } from '@/game/combat/actions'
import * as Words from '@/game/words'
import * as Onomatopoeia from '@/game/onomatopoeia'
import { Creature } from '@/game/creature'
import { VoreRelay } from '@/game/events'

@@ -87,8 +88,13 @@ export interface Container extends Actionable {
strugglePreposition: Preposition;

canTake (prey: Creature): boolean;

consume (prey: Creature): LogEntry;
release (prey: Creature): LogEntry;

enter (prey: Creature): LogEntry;
exit (prey: Creature): LogEntry;

struggle (prey: Creature): LogEntry;

tick (dt: number, victims?: Array<Creature>): LogEntry;
@@ -189,29 +195,57 @@ export abstract class DefaultContainer implements Container {
}

consume (prey: Creature): LogEntry {
const results: Array<LogEntry> = [
this.enter(prey),
this.voreRelay.dispatch("onEaten", this, { prey: prey }),
prey.voreRelay.dispatch("onEaten", this, { prey: prey }),
this.consumeLine(this.owner, prey)
]

this.owner.effects.forEach(effect => results.push(effect.postConsume(this.owner, prey, this)))

return new LogLines(...results)
}

release (prey: Creature): LogEntry {
const results = [
this.exit(prey),
this.releaseLine(this.owner, prey),
this.voreRelay.dispatch("onReleased", this, { prey: prey }),
prey.voreRelay.dispatch("onReleased", this, { prey: prey })
]
return new LogLines(...results)
}

enter (prey: Creature): LogEntry {
if (prey.containedIn !== null) {
prey.containedIn.contents = prey.containedIn.contents.filter(item => prey !== item)
}
this.contents.push(prey)
prey.containedIn = this

const results: Array<LogEntry> = []
this.owner.effects.forEach(effect => results.push(effect.postConsume(this.owner, prey, this)))
const relayResults = this.voreRelay.dispatch("onEaten", this, { prey: prey })
const preyRelayResults = prey.voreRelay.dispatch("onEaten", this, { prey: prey })
const consumeLineResult: LogEntry = this.consumeLine(this.owner, prey)
const results = [
this.voreRelay.dispatch("onEntered", this, { prey: prey }),
prey.voreRelay.dispatch("onEntered", this, { prey: prey })
]

return new LogLines(...[consumeLineResult].concat(results).concat(relayResults).concat(preyRelayResults))
return new LogLines(...results)
}

release (prey: Creature): LogEntry {
exit (prey: Creature): LogEntry {
prey.containedIn = this.owner.containedIn
this.contents = this.contents.filter(victim => victim !== prey)

if (this.owner.containedIn !== null) {
this.owner.containedIn.contents.push(prey)
}
return new LogLines(this.releaseLine(this.owner, prey), this.voreRelay.dispatch("onReleased", this, { prey: prey }))

const results = [
this.voreRelay.dispatch("onExited", this, { prey: prey }),
prey.voreRelay.dispatch("onExited", this, { prey: prey })
]

return new LogLines(...results)
}

struggle (prey: Creature): LogEntry {
@@ -268,7 +302,15 @@ export abstract class DefaultContainer implements Container {
options.push(new LogLine(`${this.fluid.name.capital} ${this.fluid.sloshVerb.singular} and ${this.fluid.sound.singular} as ${this.owner.name.possessive} ${this.name} steadily ${Words.Digest.singular} ${target.name.objective}.`))
}

return new RandomEntry(...options)
const result: Array<LogEntry> = [
new RandomEntry(...options)
]

if (Math.random() < 0.3) {
result.push(new FormatEntry(new LogLine(`${Onomatopoeia.Gurgle}`), FormatOpt.Onomatopoeia))
}

return new LogLines(...result)
}

digestLine (user: Creature, target: Creature): LogEntry {
@@ -390,6 +432,10 @@ export class Stomach extends DefaultContainer {
ContainerCapability.Absorb
]))

this.voreRelay.subscribe("onEntered", (sender: Container, args: { prey: Creature }) => {
return new FormatEntry(new LogLine(`${Onomatopoeia.Glunk}`), FormatOpt.Onomatopoeia)
})

this.damage = damage
}
}
@@ -418,11 +464,15 @@ export class Throat extends DefaultContainer {
ContainerCapability.Consume,
ContainerCapability.Release
]))

this.voreRelay.subscribe("onEaten", (sender: Container, args: { prey: Creature }) => {
return new FormatEntry(new LogLine(`${Onomatopoeia.Swallow}`), FormatOpt.Onomatopoeia)
})
}
}

export function transferDescription (verb: Word, preposition: Preposition): ((from: Container, to: Container, prey: Creature) => LogEntry) {
return (from: Container, to: Container, prey: Creature) => {
return new LogLine(`${from.owner.name.capital} ${verb.singular} ${prey.name.objective} ${preposition} ${to.consumePreposition} ${from.owner.pronouns.possessive} ${to.name}.`)
return new LogLine(`${from.owner.name.capital} ${from.owner.name.conjugate(verb.singular)} ${prey.name.objective} ${preposition} ${to.consumePreposition} ${from.owner.pronouns.possessive} ${to.name}.`)
}
}

Loading…
取消
儲存