import { CombatTest, Stat, Vigor } from '../combat' import { Creature } from '../entity' import { LogEntry, LogLines, PropElem, LogLine } from '../interface' function logistic (x0: number, L: number, k: number): (x: number) => number { return (x: number) => { return L / (1 + Math.exp(-k * (x - x0))) } } abstract class RandomTest implements CombatTest { test (user: Creature, target: Creature): boolean { return Math.random() < this.odds(user, target) } abstract odds(user: Creature, target: Creature): number abstract explain(user: Creature, target: Creature): LogEntry } export class StatVigorTest extends RandomTest { private f: (x: number) => number constructor (public readonly stat: Stat, k = 0.1) { super() this.f = logistic(0, 1, k) } odds (user: Creature, target: Creature): number { let userPercent = 1 let targetPercent = 1 Object.keys(Vigor).forEach(key => { userPercent *= user.vigors[key as Vigor] / user.maxVigors[key as Vigor] targetPercent *= target.vigors[key as Vigor] / target.maxVigors[key as Vigor] userPercent = Math.max(0, userPercent) targetPercent = Math.max(0, targetPercent) }) if (userPercent === 0) { targetPercent *= 4 } if (targetPercent === 0) { userPercent *= 4 } console.log(userPercent, targetPercent, this.f(user.stats[this.stat] * userPercent - target.stats[this.stat] * targetPercent)) return this.f(user.stats[this.stat] * userPercent - target.stats[this.stat] * targetPercent) } explain (user: Creature, target: Creature): LogEntry { let result: LogEntry let userPercent = 1 let targetPercent = 1 Object.keys(Vigor).forEach(key => { userPercent *= user.vigors[key as Vigor] / user.maxVigors[key as Vigor] targetPercent *= target.vigors[key as Vigor] / target.maxVigors[key as Vigor] userPercent = Math.max(0, userPercent) targetPercent = Math.max(0, targetPercent) }) if (userPercent === 0) { targetPercent *= 4 } if (targetPercent === 0) { userPercent *= 4 } const userMod = user.stats[this.stat] * userPercent const targetMod = target.stats[this.stat] * targetPercent const delta = (userMod - targetMod) if (delta === 0) { result = new LogLine('You and the target have the same effective', new PropElem(this.stat), '.') } else if (delta < 0) { result = new LogLine('You effectively have ', new PropElem(this.stat, -delta), ' less than your foe.') } else { result = new LogLine('You effectively have ', new PropElem(this.stat, delta), ' more than you foe.') } result = new LogLine(result, 'Your odds of success are ' + (100 * this.odds(user, target)).toFixed(1) + '%') return result } } export class StatTest extends RandomTest { private f: (x: number) => number constructor (public readonly stat: Stat, k = 0.1) { super() this.f = logistic(0, 1, k) } odds (user: Creature, target: Creature): number { return this.f(user.stats[this.stat] - target.stats[this.stat]) } explain (user: Creature, target: Creature): LogEntry { const delta: number = user.stats[this.stat] - target.stats[this.stat] let result: LogEntry if (delta === 0) { result = new LogLine('You and the target have the same ', new PropElem(this.stat), '.') } else if (delta < 0) { result = new LogLine('You have ', new PropElem(this.stat, -delta), ' less than your foe.') } else { result = new LogLine('You have ', new PropElem(this.stat, delta), ' more than you foe.') } result = new LogLine(result, 'Your odds of success are ' + (100 * this.odds(user, target)).toFixed(1) + '%') return result } } export class ChanceTest extends RandomTest { constructor (public readonly chance: number) { super() } odds (user: Creature, target: Creature): number { return this.chance } explain (user: Creature, target: Creature): LogEntry { return new LogLine('You have a flat ' + (100 * this.chance) + '% chance.') } }