#2 Smol upgrades and a bug fix (Infinite potion usage)

Открыто
great_wolves хочет смерджить 14 коммит(ов) из great_wolves/feast:master в master
  1. +1
    -1
      .eslintrc.js
  2. +1230
    -660
      package-lock.json
  3. +3
    -3
      src/App.vue
  4. +20
    -0
      src/components/Combat.vue
  5. +2
    -2
      src/components/Profile.vue
  6. +2
    -0
      src/game/combat.ts
  7. +38
    -0
      src/game/creatures/characters/Samuel.ts
  8. +147
    -0
      src/game/creatures/characters/SheenTheGryph.ts
  9. +1
    -1
      src/game/creatures/player.ts
  10. +5
    -2
      src/game/items.ts
  11. +533
    -0
      src/game/maps/Newtown.ts
  12. +22
    -2
      src/game/maps/town.ts
  13. +2
    -1
      src/game/vore.ts
  14. +41
    -11
      src/game/world.ts

+ 1
- 1
.eslintrc.js Просмотреть файл

@@ -16,7 +16,7 @@ module.exports = {
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-useless-constructor': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'quotes': 'off',
quotes: 'off',
'function-paren-newline': ['error', 'multiline-arguments'],
'@typescript-eslint/member-ordering': ['warn'],
'indent': 'off',


+ 1230
- 660
package-lock.json
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 3
- 3
src/App.vue Просмотреть файл

@@ -29,10 +29,10 @@ import { Creature } from '@/game/creature'
import { ProperNoun, TheyPronouns, FemalePronouns, MalePronouns, ImproperNoun, POV } from '@/game/language'
import { Place, Direction, World, Choice } from '@/game/world'
import { Encounter, Side } from '@/game/combat'
import { LogLine, nilLog } from '@/game/interface'
import { LogLine, Newline, nilLog } from '@/game/interface'
import { InstantKillEffect } from '@/game/combat/effects'
import moment from 'moment'
import { Town } from '@/game/maps/town'
import { Newtown } from '@/game/maps/Newtown'
import Player from './game/creatures/player'

@Component({
@@ -84,7 +84,7 @@ export default class App extends Vue {
player.items.push(new Items.Mace())
player.items.push(new Items.Dagger())
this.$data.world = new World(player)
this.$data.home = Town()
this.$data.home = Newtown()
player.location = this.$data.home
}



+ 20
- 0
src/components/Combat.vue Просмотреть файл

@@ -182,6 +182,16 @@ export default class Combat extends Vue {
),
"center"
)
if (this.encounter.winner === this.world.player.side && this.encounter.rewardGifted === false) {
this.world.player.wallet.Gold += this.encounter.reward
this.writeLog(
new LogLine(
`You found ` + this.encounter.reward + ` gold.`
),
"center"
)
this.encounter.rewardGifted = true
}
} else if (this.encounter.winner !== null && !this.$data.won && !this.$data.continuing) {
this.$data.won = true
this.writeLog(
@@ -190,6 +200,16 @@ export default class Combat extends Vue {
),
"center"
)
if (this.encounter.winner === this.world.player.side && this.encounter.rewardGifted === false) {
this.world.player.wallet.Gold += this.encounter.reward
this.writeLog(
new LogLine(
`You found ` + this.encounter.reward + ` gold.`
),
"center"
)
this.encounter.rewardGifted = true
}
} else {
if (this.encounter.currentMove.side === Side.Heroes) {
this.$data.left = this.encounter.currentMove


+ 2
- 2
src/components/Profile.vue Просмотреть файл

@@ -2,7 +2,7 @@
<div class="character-layout">
<button @click="$emit('exit')" class="profile-exit">Exit</button>
<div class="character-items">
<ItemView @click.native="useItem(item)" :item="item" v-for="(item, index) in subject.items" :key="'item-' + index" />
<ItemView @click.native="useItem(item)" :item="item" v-for="(item, index) in subject.items" :key="'item-' + index" />
</div>
<div class="character-containers">
<ContainerView :container="container" v-for="(container, index) in subject.containers" :key="'explore-container-' + index" />
@@ -36,7 +36,7 @@ import EquipmentView from '@/components/EquipmentView.vue'
import { Creature } from '@/game/creature'
import { World } from '@/game/world'
import { LogEntry } from '@/game/interface'
import { Item, ItemKind, Equipment } from '@/game/items'
import { Item, ItemKind, Equipment, KeyItem } from '@/game/items'
@Component({
components: {
Statblock, ContainerView, ItemView, EquipmentView


+ 2
- 0
src/game/combat.ts Просмотреть файл

@@ -868,6 +868,8 @@ export class Encounter {
initiatives: Map<Creature, number>
currentMove: Creature
turnTime = 100
reward = 50 // Gold
rewardGifted = false

constructor (public desc: EncounterDesc, public combatants: Creature[]) {
this.initiatives = new Map()


+ 38
- 0
src/game/creatures/characters/Samuel.ts Просмотреть файл

@@ -0,0 +1,38 @@
import { NoPassDecider, AI } from '@/game/ai'
import { CompositionAction, UniformRandomDamageFormula, Damage, DamageType, FractionDamageFormula, Side, Stat, StatDamageFormula, Vigor } from '@/game/combat'
import { AttackAction } from '@/game/combat/actions'
import { PairCondition, TogetherCondition } from '@/game/combat/conditions'
import { ConsumeConsequence, DamageConsequence, DrainConsequence, StatusConsequence } from '@/game/combat/consequences'
import { LogGroupConsequence } from '@/game/combat/groupConsequences'
import { PreyTargeter, SideTargeter, SoloTargeter } from '@/game/combat/targeters'
import { CompositionTest, OpposedStatScorer, TestCategory } from '@/game/combat/tests'
import { Creature } from '@/game/creature'
import { LogLine, nilLog } from '@/game/interface'
import { ImproperNoun, MalePronouns, ProperNoun, Verb } from '@/game/language'
import { anyVore, Stomach } from '@/game/vore'

export default class Samuel extends Creature {
constructor () {
super(
new ProperNoun("Samuel"),
new ImproperNoun("wolf"),
MalePronouns,
{
Power: 20,
Toughness: 10,
Agility: 30,
Reflexes: 10,
Charm: 30,
Willpower: 15
},
anyVore,
new Set(),
10
)

this.side = Side.Monsters
this.ai = (new AI([new NoPassDecider()], this))

this.actions.push(new AttackAction(new UniformRandomDamageFormula(new Damage({ type: DamageType.Slash, amount: 10, target: Vigor.Health }), 0.5), new Verb("claw", "claws", "claws", "clawed")))
}
}

+ 147
- 0
src/game/creatures/characters/SheenTheGryph.ts Просмотреть файл

@@ -0,0 +1,147 @@
import { VoreAI } from '@/game/ai'
import { DamageType, Side, Stat, StatDamageFormula, StatusEffect, Vigor } from '@/game/combat'
import { DigestionPowerEffect } from '@/game/combat/effects'
import { Creature } from '@/game/creature'
import { LogEntry, LogLine, nilLog } from '@/game/interface'
import { ImproperNoun, MalePronouns, ObjectPronouns, Preposition, Verb, ProperNoun, Noun } from '@/game/language'
import { anyVore, ConnectionDirection, Container, ContainerCapability, DefaultContainer, Stomach, Throat, transferDescription, VoreType } from '@/game/vore'
import * as Words from '@/game/words'
import * as Onomatopoeia from '@/game/onomatopoeia'
import { ConsumeConsequence } from '@/game/combat/consequences'

export default class SheenTheGryph extends Creature {
constructor () {
super(
new ProperNoun("Sheen"),
new ImproperNoun("gryphon", "gryphons"),
MalePronouns,
{
Power: 60,
Toughness: 35,
Agility: 15,
Reflexes: 10,
Charm: 20,
Willpower: 20
},
anyVore,
anyVore,
250
)

class Paw extends DefaultContainer{
constructor(owner : Creature,capacityFactor : number) {
super(
new Noun("paw", "paws"),
owner,
new Set<VoreType>([VoreType.Paw]),
capacityFactor,
new Set<ContainerCapability>([
ContainerCapability.Consume,
ContainerCapability.Release
])
)
}
}

const paw = new Paw(
this,
25
)

const throat = new Throat(
this,
25
)

const stomach = new Stomach(
this,
50,
new StatDamageFormula([
{ fraction: 1, stat: Stat.Toughness, type: DamageType.Acid, target: Vigor.Health }
])
)

stomach.effects.push(new class extends StatusEffect {
constructor () {
super(
"Pinned",
"Prey sometimes can't move.",
"fas fa-sun"
)
}

onApply (creature: Creature): LogEntry {
return new LogLine(
`${stomach.owner.name.capital.possessive} ${stomach.name} is incredibly tight, gripping ${creature.name.objective} like a vice!`
)
}

preAction (creature: Creature): { prevented: boolean; log: LogEntry } {
if (Math.random() < 0.5) {
return {
prevented: true,
log: new LogLine(`${creature.name.capital} can't move!`)
}
} else {
return {
prevented: false,
log: nilLog
}
}
}
}())

paw.effects.push(new class extends StatusEffect {
constructor () {
super(
"Pinned",
"Prey sometimes can't move.",
"fas fa-sun"
)
}

onApply (creature: Creature): LogEntry {
return new LogLine(
`${stomach.owner.name.capital.possessive} ${stomach.name} is incredibly tight, gripping ${creature.name.objective} like a vice!`
)
}

preAction (creature: Creature): { prevented: boolean; log: LogEntry } {
if (Math.random() < 0.5) {
return {
prevented: true,
log: new LogLine(`${creature.name.capital} can't move!`)
}
} else {
return {
prevented: false,
log: nilLog
}
}
}
}())

this.addContainer(throat)
this.addContainer(stomach)
this.addContainer(paw)

throat.connect({
destination: stomach,
direction: ConnectionDirection.Deeper,
description: transferDescription(Words.Swallow, new Preposition("down"))
})

stomach.connect({
destination: throat,
direction: ConnectionDirection.Shallower,
description: transferDescription(new Verb("hork"), new Preposition("up"))
})

stomach.voreRelay.subscribe("onDigested", (sender, args) => {
return Onomatopoeia.makeOnomatopoeia(Onomatopoeia.Burp)
})

this.side = Side.Monsters
this.ai = new VoreAI(this)
}
}

+ 1
- 1
src/game/creatures/player.ts Просмотреть файл

@@ -23,7 +23,7 @@ export default class Player extends Creature {
const stomach = new Stomach(this, 2, new ConstantDamageFormula(new Damage({ amount: 20, type: DamageType.Acid, target: Vigor.Health }, { amount: 10, type: DamageType.Crush, target: Vigor.Health })))
this.addContainer(stomach)

this.perspective = POV.First
this.perspective = POV.Second

this.ai = new VoreAI(this)



+ 5
- 2
src/game/items.ts Просмотреть файл

@@ -37,7 +37,6 @@ export abstract class Item implements Actionable {

abstract kind: ItemKind
constructor (public name: Word, public desc: TextLike) {

}
}

@@ -169,7 +168,11 @@ export class ItemAction extends Action {
}

execute (user: Creature, target: Creature): LogEntry {
if (this.item.consumed) {
return new LogLine(`You have already consumed this `.concat(this.item.name.toString())) // Keeps the [[Consumable]] from being used twice, even if the element still exists
}
this.item.consumed = true
delete user.items[user.items.indexOf(this.item)] // Removes [[Consumable]], but does not remove the element till the next gui draw (Not keen in html)
return this.action.execute(user, target)
}

@@ -195,7 +198,7 @@ export class Consumable extends Item {
export abstract class Potion extends Consumable {
constructor (name: ImproperNoun, desc: string, consequences: Array<Consequence>) {
super(
new ImproperNoun("health potion"),
name,
desc,
new CompositionAction(
"Drink " + name,


+ 533
- 0
src/game/maps/Newtown.ts Просмотреть файл

@@ -0,0 +1,533 @@
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 Items from '@/game/items'
import { LogLine, nilLog, LogLines } from '@/game/interface'
import { Creature } from '@/game/creature'
import { DevourAction } from '@/game/combat/actions'
import { InstantDigestionEffect, SurrenderEffect } from '@/game/combat/effects'
import moment from 'moment'
import { VoreAI } from '@/game/ai'
import { DeliciousPerk } from '@/game/combat/perks'
import Samuel from '../creatures/characters/Samuel'
import Human from '../creatures/human'
import Werewolf from '../creatures/monsters/werewolf'
import SheenTheGryph from '../creatures/characters/SheenTheGryph'

function makeParty (): Creature[] {
const fighter = new Human(new ProperNoun("Redgar"), MalePronouns, {
stats: {
Toughness: 20,
Power: 20,
Reflexes: 15,
Agility: 15,
Willpower: 15,
Charm: 10
}
})
fighter.title = "Lv. 6 Fighter"
fighter.equip(new Items.Sword(), Items.EquipmentSlot.MainHand)
const rogue = new Human(new ProperNoun('Lidda'), FemalePronouns, {
stats: {
Toughness: 10,
Power: 15,
Reflexes: 20,
Agility: 20,
Willpower: 15,
Charm: 20
}
})
rogue.title = "Lv. 5 Rogue"
rogue.equip(new Items.Dagger(), Items.EquipmentSlot.MainHand)
const wizard = new Human(new ProperNoun('Mialee'), FemalePronouns, {
stats: {
Toughness: 10,
Power: 10,
Reflexes: 15,
Agility: 15,
Willpower: 20,
Charm: 25
}
})
wizard.title = "Lv. 6 Wizard"
wizard.equip(new Items.Wand(), Items.EquipmentSlot.MainHand)
const cleric = new Human(new ProperNoun('Jozan'), MalePronouns, {
stats: {
Toughness: 15,
Power: 15,
Reflexes: 10,
Agility: 10,
Willpower: 20,
Charm: 15
}
})
cleric.title = "Lv. 5 Cleric"
cleric.equip(new Items.Mace(), Items.EquipmentSlot.MainHand)

return [fighter, cleric, rogue, wizard]
}

export const Newtown = (): Place => {
const home = new Place(
new ProperNoun("Home"),
"A place you can rest after long adventures"
)

const debug = new Place(
new ProperNoun("Debug Room"),
"Where weird stuff happens"
)

const southTownStreet = new Place(
new ProperNoun("South Town Street"),
"Town street south of the Town square"
)

const northTownStreet = new Place(
new ProperNoun("North Town Street"),
"Town street north of the Town square"
)

const northTownShop = new Place(
new ProperNoun("North Town Shop"),
"A shop for your impulsive buying needs"
)

const eastTownStreet = new Place(
new ProperNoun("East Town Street"),
"Town street east of the Town square"
)

const westTownStreet = new Place(
new ProperNoun("West Town Street"),
"Town street west of the Town square"
)

const townSquare = new Place(
new ProperNoun("Town Square"),
"The central-most part of town, and a hub of bustling activity"
)

const eastGate = new Place(
new ProperNoun("East Gate"),
"The towns gate, leading out into the wilderness"
)
const woods = new Place(
new ProperNoun("The Woods"),
"A scary part of the forest where monsters hide"
)
const deepwoods = new Place(
new ProperNoun("Deep Woods"),
"Extra scary"
)
southTownStreet.choices.push(
new Choice(
"Fight Sheen",
"Go fight Sheen!",
(world, executor) => {
const enemy = new SheenTheGryph()
const encounter = new Encounter(
{
name: "Fight some tough nerd",
intro: () => new LogLine(`Sheen Approaches!`)
},
[world.player, enemy].concat(world.party)
)
world.encounter = encounter
return nilLog
}
)
)
deepwoods.choices.push(
new Choice(
"Fight Werewolf",
"Go fight Werewolf!",
(world, executor) => {
const enemy = new Werewolf()
const encounter = new Encounter(
{
name: "Fight some tough nerd",
intro: () => new LogLine(`Werewolf Approaches!`)
},
[world.player, enemy].concat(world.party)
)
world.encounter = encounter
return nilLog
}
)
)
const bossEncounters = [
new Encounter(
{ name: "Inazuma", intro: () => nilLog },
makeParty().concat([new Werewolf()])
)
]

home.choices.push(
new Choice(
"Nap",
"Zzzzzz",
(world) => {
return new LogLines(
`You lie down for a nice nap...`,
world.advance(moment.duration(1, "hour"))
)
}
)
)

home.choices.push(
new Choice(
"Heal",
"Become not dead and/or eaten",
(world, executor) => {
Object.keys(Vigor).forEach(vigor => {
executor.vigors[vigor as Vigor] = executor.maxVigors[vigor as Vigor]
})
if (executor.containedIn !== null) {
executor.containedIn.release(executor)
}
executor.statusEffects.forEach(effect => {
executor.removeEffect(effect)
})
executor.destroyed = false
return new LogLine(`You're healthy again`)
}
)
)

home.choices.push(
new Choice(
"Heal your party",
"Revive your party, and ensure they are not dead and/or eaten",
(world, executor) => {
world.party.forEach((partyMember) => {
Object.keys(Vigor).forEach(vigor => {
partyMember.vigors[vigor as Vigor] = partyMember.maxVigors[vigor as Vigor]
})
if (partyMember.containedIn !== null) {
partyMember.containedIn.release(partyMember)
}
partyMember.statusEffects.forEach(effect => {
partyMember.removeEffect(effect)
})
partyMember.destroyed = false
})
Object.keys(Vigor).forEach(vigor => {
executor.vigors[vigor as Vigor] = executor.maxVigors[vigor as Vigor]
})
if (executor.containedIn !== null) {
executor.containedIn.release(executor)
}
executor.statusEffects.forEach(effect => {
executor.removeEffect(effect)
})
executor.destroyed = false
return new LogLine(`Your party is healthy again`)
}
)
)

home.choices.push(
new Choice(
"Grab potions",
"Grab some potions",
(world, executor) => {
executor.items.push(new Items.HealthPotion())
executor.items.push(new Items.AcidPotion())
executor.items.push(new Items.ShrinkPotion())
executor.items.push(new Items.StrengthPotion())
return new LogLine("You grab some potions")
}
)
)

townSquare.choices.push(
new Choice(
"Eat someone",
"Slurp",
(world, executor) => {
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)
}
)
)

townSquare.choices.push(
new Choice(
"Fight someone",
"Ow",
(world) => {
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)
enemy.addPerk(new DeliciousPerk())
const encounter = new Encounter(
{
name: "Fight some tasty nerd",
intro: () => new LogLine(`You find some nerd to fight.`)
},
[world.player, enemy].concat(world.party)
)
world.encounter = encounter
return nilLog
}
)
)

townSquare.choices.push(
new Choice(
"Recruit someone",
"Not ow",
(world) => {
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)
world.party.push(ally)

return new LogLine(`You recruit a nerd`)
}
)
)

northTownShop.choices.push(
new Choice(
"Buy a shiny rock",
"This rock has no use.",
(world, executor) => {
if (executor.wallet.Gold >= 500) {
executor.wallet.Gold -= 500
executor.items.push(
new Items.KeyItem(new ProperNoun("Shiny Rock"), "Very shiny")
)

return new LogLine(`You buy a shiny rock`)
} else {
return new LogLine(`Shiny rocks are 500 gold coins, loser!`)
}
}
)
)
northTownShop.choices.push(
new Choice(
"Buy a health potion",
"50 Gold",
(world, executor) => {
if (executor.wallet.Gold >= 50) {
executor.wallet.Gold -= 50
executor.items.push(
new Items.HealthPotion()
)

return new LogLine(`You buy a health potion.`)
} else {
return new LogLine(`Health potions are 50 gold coins.`)
}
}
)
)

northTownShop.choices.push(
new Choice(
"Buy a strength potion",
"40 Gold",
(world, executor) => {
if (executor.wallet.Gold >= 40) {
executor.wallet.Gold -= 40
executor.items.push(
new Items.StrengthPotion()
)

return new LogLine(`You buy a strength potion.`)
} else {
return new LogLine(`Strength potions are 40 gold coins.`)
}
}
)
)

northTownShop.choices.push(
new Choice(
"Buy an acid potion",
"25 Gold",
(world, executor) => {
if (executor.wallet.Gold >= 25) {
executor.wallet.Gold -= 25
executor.items.push(
new Items.AcidPotion()
)

return new LogLine(`You buy an acid potion.`)
} else {
return new LogLine(`Acid potions are 25 gold coins.`)
}
}
)
)

northTownShop.choices.push(
new Choice(
"Buy a shrink potion",
"10 Gold",
(world, executor) => {
if (executor.wallet.Gold >= 10) {
executor.wallet.Gold -= 10
executor.items.push(
new Items.ShrinkPotion()
)

return new LogLine(`You buy a shrink potion.`)
} else {
return new LogLine(`Shrink potions are 10 gold coins.`)
}
}
)
)

debug.choices.push(
new Choice(
"Cut stats",
"Make your stats less good-er",
(world, executor) => {
Object.keys(Stat).forEach(stat => {
executor.baseStats[stat as Stat] -= 5
executor.takeDamage(new Damage(
{ amount: 5, target: (stat as Stat), type: DamageType.Pure }
))
})
return new LogLine(`You're weaker now`)
}
)
)

debug.choices.push(
new Choice(
"Boost stats",
"Make your stats more good-er",
(world, executor) => {
Object.keys(Stat).forEach(stat => {
executor.baseStats[stat as Stat] += 5
executor.takeDamage(new Damage(
{ amount: 5, target: (stat as Stat), type: DamageType.Heal }
))
})
return new LogLine(`You're stronger now`)
}
)
)

debug.choices.push(
new Choice(
"Grow",
"Make yourself larger",
(world, executor) => {
executor.voreStats.Mass *= 1.5
return new LogLine(`You're larger now`)
}
)
)

debug.choices.push(
new Choice(
"Shrink",
"Make yourself smaller",
(world, executor) => {
executor.voreStats.Mass /= 1.5
return new LogLine(`You're smaller now`)
}
)
)

debug.choices.push(
new Choice(
"Instant Digestion",
"Make your stomach REALLY powerful",
(world, executor) => {
executor.applyEffect(new InstantDigestionEffect())
return new LogLine(`You're really gonna melt people now.`)
}
)
)

debug.choices.push(
new Choice(
"Set Name",
"Set your name",
(world, executor) => {
const input = prompt("Enter a name")
if (input !== null) {
executor.baseName = new ProperNoun(input)
return new LogLine(`Your new name is ${executor.baseName}.`)
} else {
return new LogLine(`nvm`)
}
}
)
)

debug.choices.push(
new Choice(
"Add money",
"Get some money",
(world, executor) => {
executor.wallet.Gold += 1000
return new LogLine(`$$$$$$$$$$$$$$$$$`)
}
)
)

woods.choices.push(
new Choice(
"Fight Samuel",
"Go fight a poor little wolf!",
(world, executor) => {
const enemy = new Samuel()
const encounter = new Encounter(
{
name: "Fight some tasty nerd",
intro: () => new LogLine(`Samuel pokes his head out from the bushes!`)
},
[world.player, enemy].concat(world.party)
)
world.encounter = encounter
return nilLog
}
)
)

const bosses = new Place(
new ProperNoun("BOSS ZONE"),
"Extra scary"
)

bossEncounters.forEach(encounter => {
bosses.choices.push(
new Choice(
encounter.desc.name,
"Boss fight!",
(world) => {
world.encounter = encounter
return nilLog
}
)
)
})

home.biconnect(Direction.South, debug, "Walk", "Enter the debug room", "Leave", "Exit the debug room")
home.biconnect(Direction.Northeast, townSquare, "Leave", "Go outside", "Enter", "Enter your home")
townSquare.biconnect(Direction.North, northTownStreet, "Walk", "Go that way", "Walk", "Go that way")
townSquare.biconnect(Direction.East, eastTownStreet, "Walk", "Go that way", "Walk", "Go that way")
townSquare.biconnect(Direction.South, southTownStreet, "Walk", "Go that way", "Walk", "Go that way")
townSquare.biconnect(Direction.West, westTownStreet, "Walk", "Go that way", "Walk", "Go that way")
northTownShop.biconnect(Direction.West, northTownStreet, "Exit", "Leave the shop", "Enter", "Enter the shop")
debug.biconnect(Direction.South, bosses, "Enter", "Boss Fight!", "Leave", "Go back to the debug room")
eastTownStreet.biconnect(Direction.East, eastGate, "Walk", "Go that way", "Walk", "Go that way")
eastGate.biconnect(Direction.East, woods, "Walk", "Enter the woods", "Approach", "Enter the city gates")
woods.biconnect(Direction.North, deepwoods, "Walk", "Go deeper", "Walk", "Leave the deep woods")

return home
}

+ 22
- 2
src/game/maps/town.ts Просмотреть файл

@@ -10,6 +10,7 @@ import moment from 'moment'
import { VoreAI } from '@/game/ai'
import { DeliciousPerk } from '@/game/combat/perks'
import Human from '../creatures/human'
import Samuel from '../creatures/characters/Samuel'
import Werewolf from '../creatures/monsters/werewolf'

function makeParty (): Creature[] {
@@ -334,6 +335,25 @@ export const Town = (): Place => {
)
)

woods.choices.push(
new Choice(
"Fight Samuel",
"Go fight a poor little wolf!",
(world, executor) => {
const enemy = new Samuel()
const encounter = new Encounter(
{
name: "Fight some tasty nerd",
intro: () => new LogLine(`Samuel pokes his head out from the bushes!`)
},
[world.player, enemy].concat(world.party)
)
world.encounter = encounter
return nilLog
}
)
)

debug.choices.push(
new Choice(
"Add money",
@@ -345,8 +365,8 @@ export const Town = (): Place => {
)
)

home.biconnect(Direction.South, debug)
debug.biconnect(Direction.South, bosses)
home.biconnect(Direction.South, debug, "Walk", "Enter the debug room", "Leave", "Exit the debug room")
debug.biconnect(Direction.South, bosses, "Enter", "Boss Fight!", "Leave", "Go back to the debug room")
home.biconnect(Direction.North, square)
westRoad.biconnect(Direction.South, woods)
square.biconnect(Direction.West, westRoad)


+ 2
- 1
src/game/vore.ts Просмотреть файл

@@ -8,7 +8,8 @@ import { Creature } from '@/game/creature'
import { VoreRelay } from '@/game/events'

export enum VoreType {
Oral = "Oral Vore"
Oral = "Oral Vore",
Paw = "Paw Vore"
}

export const anyVore = new Set([


+ 41
- 11
src/game/world.ts Просмотреть файл

@@ -29,34 +29,55 @@ export function reverse (dir: Direction): Direction {
}

export class Choice {
isAccessible: boolean
isVisible: boolean
constructor (public name: TextLike, public desc: TextLike, public execute: (world: World, executor: Creature) => LogEntry) {

this.isAccessible = true
this.isVisible = true
}

/**
* Gets the choice's visiblity. No funtionality at the moment.
*/
visible (): boolean {
return true
}

/**
* Gets the choice's visiblity. No funtionality at the moment.
*/
accessible (): boolean {
return true
}
}

export class Connection {
isAccessible: boolean
isVisible: boolean
constructor (public src: Place, public dst: Place, public name: TextLike = "Travel", public desc: TextLike = "Go there lol") {

this.isAccessible = true
this.isVisible = true
}

/**
* Gets the connection's visiblity. No funtionality at the moment.
*/
visible (): boolean {
return true
return this.isVisible
}

/**
* Gets the connection's accessibility. No funtionality at the moment.
*/
accessible (): boolean {
return true
return this.isAccessible
}

travel (world: World, traveler: Creature): LogEntry {
const advanceLogs = world.advance(moment.duration(5, "minutes"))
/**
* Moves [[traveler]] through this connection to [[dst]] and progresses the time by [[moveTime]].
*/
travel (world: World, traveler: Creature, moveTime: Duration = moment.duration(5, "minutes")): LogEntry {
const advanceLogs = world.advance(moveTime)
traveler.location = this.dst
return new LogLines(
advanceLogs,
@@ -73,13 +94,19 @@ export class Place {

}

connect (dir: Direction, dst: Place) {
this.connections[dir] = new Connection(this, dst)
/**
* Connects a room one way.
*/
connect (dir: Direction, dst: Place, name: TextLike = "Travel", desc: TextLike = "Go there lol") {
this.connections[dir] = new Connection(this, dst, name, desc)
}

biconnect (dir: Direction, dst: Place) {
this.connect(dir, dst)
dst.connect(reverse(dir), this)
/**
* Connects two rooms and names both hover boxes.
*/
biconnect (dir: Direction, dst: Place, name1: TextLike = "Travel", desc1: TextLike = "Go there lol", name2: TextLike = "Travel", desc2: TextLike = "Go there lol") {
this.connect(dir, dst, name1, desc1)
dst.connect(reverse(dir), this, name2, desc2)
}
}

@@ -99,6 +126,9 @@ export class World {
this.creatures.push(player)
}

/**
* Progresses the clock.
*/
advance (dt: Duration): LogEntry {
this.time.add(dt)
return new LogLines(


Загрузка…
Отмена
Сохранить