Переглянути джерело

Fix display of opposed stat tests; change some actions to use it

master
Fen Dweller 5 роки тому
джерело
коміт
c77136aabd
4 змінених файлів з 68 додано та 27 видалено
  1. +16
    -10
      src/game/combat/actions.ts
  2. +17
    -0
      src/game/combat/perks.ts
  3. +32
    -16
      src/game/combat/tests.ts
  4. +3
    -1
      src/game/maps/town.ts

+ 16
- 10
src/game/combat/actions.ts Переглянути файл

@@ -1,4 +1,4 @@
import { StatTest, StatVigorTest, StatVigorSizeTest } from './tests'
import { StatTest, StatVigorTest, StatVigorSizeTest, OpposedStatTest, TestCategory } from './tests'
import { DynText, LiveText, TextLike, Verb, PairLine, PairLineArgs } from '../language'
import { Entity } from '../entity'
import { Creature } from "../creature"
@@ -98,10 +98,12 @@ export class DevourAction extends CompositionAction {
new LiveText(container, x => `Try to ${x.consumeVerb} your foe`),
{
conditions: [new CapableCondition(), new TogetherCondition(), new HasRoomCondition(container)],
tests: [new StatVigorSizeTest(
Stat.Power,
-5,
(user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to ${container.consumeVerb} ${target.name.objective}.`)
tests: [new OpposedStatTest(
{ Power: 1, Charm: 1, Mass: 0.05 },
{ Toughness: 1, Willpower: 1, Bulk: 0.05 },
(user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to ${container.consumeVerb} ${target.name.objective}.`),
TestCategory.Vore,
-5
)],
consequences: [
new ConsumeConsequence(container)
@@ -178,11 +180,15 @@ export class StruggleAction extends Action {
new DynText('Struggle (', new LiveText(container, x => x.name.all), ')'),
'Try to escape from your foe',
[new CapableCondition(), new PairCondition(), new ContainedByCondition(container)],
[new StatVigorSizeTest(
Stat.Power,
-5,
(user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to escape from ${target.name.possessive} ${container.name}.`)
)]
[
new OpposedStatTest(
{ Power: 1, Agility: 1, Bulk: 0.05 },
{ Toughness: 1, Reflexes: 1, Mass: 0.05 },
(user, target) => new LogLine(`${user.name.capital} ${user.name.conjugate(new Verb('fail'))} to escape from ${target.name.possessive} ${container.name}.`),
TestCategory.Vore,
-5
)
]
)
}



+ 17
- 0
src/game/combat/perks.ts Переглянути файл

@@ -55,3 +55,20 @@ export class RavenousPerk extends Perk {
}
}
}

export class DeliciousPerk extends Perk {
constructor () {
super(
"Delicious",
"-20 to all defensive vore checks"
)
}

modTestDefense (defender: Creature, attacker: Creature, kind: TestCategory): number {
if (kind === TestCategory.Vore) {
return -20
} else {
return 0
}
}
}

+ 32
- 16
src/game/combat/tests.ts Переглянути файл

@@ -1,4 +1,4 @@
import { CombatTest, Stat, Vigor, Stats, StatToVigor } from '../combat'
import { CombatTest, Stat, Vigor, Stats, StatToVigor, VoreStats, VoreStat } from '../combat'
import { Creature } from "../creature"
import { LogEntry, LogLines, PropElem, LogLine, nilLog } from '../interface'
import { Verb } from '../language'
@@ -49,8 +49,8 @@ export class OpposedStatTest extends RandomTest {
private maxTotalVigorPenalty = 0.1

constructor (
public readonly userStats: Partial<Stats>,
public readonly targetStats: Partial<Stats>,
public readonly userStats: Partial<Stats & VoreStats>,
public readonly targetStats: Partial<Stats & VoreStats>,
fail: (user: Creature, target: Creature) => LogEntry,
public category: TestCategory,
private bias = 0
@@ -60,8 +60,8 @@ export class OpposedStatTest extends RandomTest {
}

odds (user: Creature, target: Creature): number {
const userScore = this.getScore(user, this.userStats) + user.effects.reduce((total, effect) => total + effect.modTestOffense(user, target, this.category), 0)
const targetScore = this.getScore(target, this.targetStats) + target.effects.reduce((total, effect) => total + effect.modTestDefense(target, user, this.category), 0)
const userScore = this.getScoreOffense(user, target, this.userStats)
const targetScore = this.getScoreDefense(target, user, this.targetStats)

return this.f(userScore - targetScore + this.bias)
}
@@ -72,23 +72,22 @@ export class OpposedStatTest extends RandomTest {
`Pits `,
...Object.entries(this.userStats).map(([stat, frac]) => {
if (frac !== undefined) {
return new LogLine(`${(frac * 100).toFixed(0)}% `, new PropElem(stat as Stat))
return new LogLine(`${(frac * 100).toFixed(0)}% of `, new PropElem(stat as Stat), `, `)
} else {
return nilLog
}
}),
` from ${user.name.possessive} stats against `,
` against `,
...Object.entries(this.targetStats).map(([stat, frac]) => {
if (frac !== undefined) {
return new LogLine(`${(frac * 100).toFixed(0)}% `, new PropElem(stat as Stat))
return new LogLine(`${(frac * 100).toFixed(0)}% of `, new PropElem(stat as Stat), `, `)
} else {
return nilLog
}
}),
` from ${target.name.possessive} stats.`
})
),
new LogLine(
`${user.name.capital}: ${this.getScore(user, this.userStats)} // ${this.getScore(target, this.targetStats)} :${target.name.capital}`
`${user.name.capital}: ${this.getScoreOffense(user, target, this.userStats)} // ${this.getScoreDefense(target, user, this.targetStats)} :${target.name.capital}`
),
new LogLine(
`${user.name.capital} ${user.name.conjugate(new Verb("have", "has"))} a ${(this.odds(user, target) * 100).toFixed(0)}% chance of winning this test.`
@@ -96,22 +95,39 @@ export class OpposedStatTest extends RandomTest {
)
}

private getScoreDefense (defender: Creature, attacker: Creature, parts: Partial<Stats>): number {
return this.getScore(defender, parts) + defender.effects.reduce((total, effect) => total + effect.modTestDefense(defender, attacker, this.category), 0)
}

private getScoreOffense (attacker: Creature, defender: Creature, parts: Partial<Stats>): number {
return this.getScore(attacker, parts) + attacker.effects.reduce((total, effect) => total + effect.modTestOffense(attacker, defender, this.category), 0)
}

private getScore (actor: Creature, parts: Partial<Stats>): number {
const total = Object.entries(parts).reduce((total: number, [stat, frac]) => {
let value = actor.stats[stat as Stat] * (frac === undefined ? 0 : frac)
if (stat in Stat) {
let value = actor.stats[stat as Stat] * (frac === undefined ? 0 : frac)

const vigor = StatToVigor[stat as Stat]
value = value * (1 - this.maxStatVigorPenalty) + value * this.maxStatVigorPenalty * actor.vigors[vigor] / actor.maxVigors[vigor]

const vigor = StatToVigor[stat as Stat]
value = value * (1 - this.maxStatVigorPenalty) + value * this.maxStatVigorPenalty * actor.vigors[vigor] / actor.maxVigors[vigor]
return total + value
} else if (stat in VoreStat) {
const value = actor.voreStats[stat as VoreStat] * (frac === undefined ? 0 : frac)

return total + value
return total + value
} else {
return total
}
}, 0)

const modifiedTotal = Object.keys(Vigor).reduce(
(total, vigor) => {
return total * (1 - this.maxStatVigorPenalty) + total * actor.vigors[vigor as Vigor] / actor.maxVigors[vigor as Vigor]
return total * (1 - this.maxStatVigorPenalty) + total * this.maxStatVigorPenalty * actor.vigors[vigor as Vigor] / actor.maxVigors[vigor as Vigor]
},
total
)

return modifiedTotal
}
}


+ 3
- 1
src/game/maps/town.ts Переглянути файл

@@ -9,6 +9,7 @@ import { DevourAction } from '../combat/actions'
import { SurrenderEffect } from '../combat/effects'
import moment from 'moment'
import { VoreAI } from '../ai'
import { DeliciousPerk } from '../combat/perks'

function makeParty (): Creature[] {
const fighter = new Creatures.Human(new ProperNoun("Redgar"), MalePronouns, {
@@ -265,9 +266,10 @@ export const Town = (): Place => {
enemy.side = Side.Monsters
enemy.ai = new VoreAI()
enemy.equip(new Items.Sword(), Items.EquipmentSlot.MainHand)
enemy.perks.push(new DeliciousPerk())
const encounter = new Encounter(
{
name: "Fight some nerd",
name: "Fight some tasty nerd",
intro: world => new LogLine(`You find some nerd to fight.`)
},
[world.player, enemy]


Завантаження…
Відмінити
Зберегти