Sfoglia il codice sorgente

Fixed potions being infinitely usable in inventory.

Made a new map that is a little bigger.
New enemy - Samuel
The boss, Inazuma, is now fightable.
Updated old constructors for connecting places to allow for naming the walk direction(Instead of "Travel, go there lol")
master
Samuel Dweller 3 anni fa
parent
commit
20d1ea6d13
11 ha cambiato i file con 1694 aggiunte e 684 eliminazioni
  1. +1
    -1
      .eslintrc.js
  2. +1230
    -660
      package-lock.json
  3. +3
    -3
      src/App.vue
  4. +2
    -2
      src/components/Profile.vue
  5. +38
    -0
      src/game/creatures/characters/Samuel.ts
  6. +1
    -1
      src/game/creatures/player.ts
  7. +5
    -2
      src/game/items.ts
  8. +2
    -2
      src/game/language.ts
  9. +349
    -0
      src/game/maps/Newtown.ts
  10. +22
    -2
      src/game/maps/town.ts
  11. +41
    -11
      src/game/world.ts

+ 1
- 1
.eslintrc.js Vedi File

@@ -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']
}


+ 1230
- 660
package-lock.json
File diff soppresso perché troppo grande
Vedi File


+ 3
- 3
src/App.vue Vedi File

@@ -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
}



+ 2
- 2
src/components/Profile.vue Vedi File

@@ -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


+ 38
- 0
src/game/creatures/characters/Samuel.ts Vedi File

@@ -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")))
}
}

+ 1
- 1
src/game/creatures/player.ts Vedi File

@@ -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.addVoreContainer(stomach)

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

this.ai = new VoreAI(this)
}


+ 5
- 2
src/game/items.ts Vedi File

@@ -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,


+ 2
- 2
src/game/language.ts Vedi File

@@ -537,14 +537,14 @@ export const SecondPersonPronouns = new Pronoun({
objective: 'you',
possessive: 'your',
reflexive: 'yourself'
}, false, true)
})

export const FirstPersonPronouns = new Pronoun({
subjective: 'I',
objective: 'me',
possessive: 'my',
reflexive: 'myself'
}, false, true)
})

export class PronounAsNoun extends Noun {
constructor (private pronouns: Pronoun, opt: WordOptions = emptyConfig) {


+ 349
- 0
src/game/maps/Newtown.ts Vedi File

@@ -0,0 +1,349 @@
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 Inazuma from '../creatures/characters/inazuma'
import Samuel from '../creatures/characters/Samuel'
import Human from '../creatures/human'
import Slime from '../creatures/monsters/slime'

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 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"
)
deepwoods.choices.push(
new Choice(
"Fight Inazuma",
"Go fight Inazuma!",
(world, executor) => {
const enemy = new Inazuma()
const encounter = new Encounter(
{
name: "Fight some tough nerd",
intro: () => new LogLine(`Inazuma Approaches!`)
},
[world.player, enemy].concat(world.party)
)
world.encounter = encounter
return nilLog
}
)
)
const bossEncounters = [
new Encounter(
{ name: "Inazuma", intro: () => nilLog },
makeParty().concat([new Inazuma()])
)
]

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(
"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")
}
)
)

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 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
}
)
)

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")
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 Vedi File

@@ -12,6 +12,7 @@ import { DeliciousPerk } from '@/game/combat/perks'
import Inazuma from '../creatures/characters/inazuma'
import Human from '../creatures/human'
import Slime from '../creatures/monsters/slime'
import Samuel from '../creatures/characters/Samuel'

function makeParty (): Creature[] {
const fighter = new Human(new ProperNoun("Redgar"), MalePronouns, {
@@ -340,6 +341,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",
@@ -351,8 +371,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)


+ 41
- 11
src/game/world.ts Vedi File

@@ -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(


Loading…
Annulla
Salva