Changed how conversion gain modifiers work, so nextAt will be correct

This commit is contained in:
thepaperpilot 2022-03-29 21:26:01 -05:00
parent 84ed880533
commit f40765e4de

View file

@ -1,7 +1,10 @@
import { GenericLayer } from "game/layers"; import { GenericLayer } from "game/layers";
import Decimal, { DecimalSource } from "util/bignum"; import Decimal, { DecimalSource } from "util/bignum";
import { isFunction } from "util/common";
import { import {
Computable, Computable,
convertComputable,
DoNotCache,
GetComputableTypeWithDefault, GetComputableTypeWithDefault,
processComputable, processComputable,
ProcessedComputable ProcessedComputable
@ -20,7 +23,7 @@ export interface ConversionOptions {
buyMax?: Computable<boolean>; buyMax?: Computable<boolean>;
roundUpCost?: Computable<boolean>; roundUpCost?: Computable<boolean>;
convert?: VoidFunction; convert?: VoidFunction;
modifyGainAmount?: (gain: DecimalSource) => DecimalSource; gainModifier?: GainModifier;
} }
export interface BaseConversion { export interface BaseConversion {
@ -47,6 +50,11 @@ export type GenericConversion = Replace<
} }
>; >;
export interface GainModifier {
apply: (gain: DecimalSource) => DecimalSource;
revert: (gain: DecimalSource) => DecimalSource;
}
export function createConversion<T extends ConversionOptions>( export function createConversion<T extends ConversionOptions>(
optionsFunc: () => T & ThisType<Conversion<T>> optionsFunc: () => T & ThisType<Conversion<T>>
): Conversion<T> { ): Conversion<T> {
@ -54,25 +62,33 @@ export function createConversion<T extends ConversionOptions>(
const conversion: T = optionsFunc(); const conversion: T = optionsFunc();
if (conversion.currentGain == null) { if (conversion.currentGain == null) {
conversion.currentGain = computed(() => conversion.currentGain = computed(() => {
let gain = conversion.gainModifier
? conversion.gainModifier.apply(
conversion.scaling.currentGain(conversion as GenericConversion) conversion.scaling.currentGain(conversion as GenericConversion)
); )
: conversion.scaling.currentGain(conversion as GenericConversion);
gain = Decimal.floor(gain).max(0);
if (!conversion.buyMax) {
gain = gain.min(1);
}
return gain;
});
} }
if (conversion.nextAt == null) { if (conversion.nextAt == null) {
conversion.nextAt = computed(() => conversion.nextAt = computed(() => {
conversion.scaling.nextAt(conversion as GenericConversion) let next = conversion.scaling.nextAt(conversion as GenericConversion);
); if (conversion.roundUpCost) next = Decimal.ceil(next);
return next;
});
} }
if (conversion.convert == null) { if (conversion.convert == null) {
conversion.convert = function () { conversion.convert = function () {
conversion.gainResource.value = Decimal.add( conversion.gainResource.value = Decimal.add(
conversion.gainResource.value, conversion.gainResource.value,
conversion.modifyGainAmount
? conversion.modifyGainAmount(
unref((conversion as GenericConversion).currentGain) unref((conversion as GenericConversion).currentGain)
)
: unref((conversion as GenericConversion).currentGain)
); );
// TODO just subtract cost? // TODO just subtract cost?
conversion.baseResource.value = 0; conversion.baseResource.value = 0;
@ -107,25 +123,17 @@ export function createLinearScaling(
return 0; return 0;
} }
let gain = Decimal.sub(conversion.baseResource.value, unref(base)) return Decimal.sub(conversion.baseResource.value, unref(base))
.sub(1) .sub(1)
.times(unref(coefficient)) .times(unref(coefficient))
.add(1) .add(1);
.floor()
.max(0);
if (!conversion.buyMax) {
gain = gain.min(1);
}
return gain;
}, },
nextAt(conversion) { nextAt(conversion) {
let next = Decimal.add(unref(conversion.currentGain), 1) let next: DecimalSource = Decimal.add(unref(conversion.currentGain), 1);
.times(unref(coefficient)) if (conversion.gainModifier) {
.add(unref(base)) next = conversion.gainModifier.revert(next);
.max(unref(base)); }
if (conversion.roundUpCost) next = next.ceil(); return Decimal.times(next, unref(coefficient)).add(unref(base)).max(unref(base));
return next;
} }
}; };
} }
@ -138,27 +146,21 @@ export function createPolynomialScaling(
): ScalingFunction { ): ScalingFunction {
return { return {
currentGain(conversion) { currentGain(conversion) {
let gain = Decimal.div(conversion.baseResource.value, unref(base)) const gain = Decimal.div(conversion.baseResource.value, unref(base)).pow(
.pow(unref(exponent)) unref(exponent)
.floor() );
.max(0);
if (gain.isNan()) { if (gain.isNan()) {
return new Decimal(0); return new Decimal(0);
} }
if (!conversion.buyMax) {
gain = gain.min(1);
}
return gain; return gain;
}, },
nextAt(conversion) { nextAt(conversion) {
let next = Decimal.add(unref(conversion.currentGain), 1) let next: DecimalSource = Decimal.add(unref(conversion.currentGain), 1);
.root(unref(exponent)) if (conversion.gainModifier) {
.times(unref(base)) next = conversion.gainModifier.revert(next);
.max(unref(base)); }
if (conversion.roundUpCost) next = next.ceil(); return Decimal.root(next, unref(exponent)).times(unref(base)).max(unref(base));
return next;
} }
}; };
} }
@ -188,8 +190,10 @@ export function createIndependentConversion<S extends ConversionOptions>(
); );
} }
setDefault(conversion, "convert", function () { setDefault(conversion, "convert", function () {
conversion.gainResource.value = conversion.modifyGainAmount conversion.gainResource.value = conversion.gainModifier
? conversion.modifyGainAmount(unref((conversion as GenericConversion).currentGain)) ? conversion.gainModifier.apply(
unref((conversion as GenericConversion).currentGain)
)
: unref((conversion as GenericConversion).currentGain); : unref((conversion as GenericConversion).currentGain);
// TODO just subtract cost? // TODO just subtract cost?
// Maybe by adding a cost function to scaling and nextAt just calls the cost function // Maybe by adding a cost function to scaling and nextAt just calls the cost function
@ -250,3 +254,34 @@ export function addHardcap(
currentGain: conversion => Decimal.min(scaling.currentGain(conversion), unref(cap)) currentGain: conversion => Decimal.min(scaling.currentGain(conversion), unref(cap))
}; };
} }
export function createAdditiveModifier(addend: Computable<DecimalSource>): GainModifier {
const processedAddend = convertComputable(addend);
return {
apply: gain => Decimal.add(gain, unref(processedAddend)),
revert: gain => Decimal.sub(gain, unref(processedAddend))
};
}
export function createMultiplicativeModifier(multiplier: Computable<DecimalSource>): GainModifier {
const processedMultiplier = convertComputable(multiplier);
return {
apply: gain => Decimal.times(gain, unref(processedMultiplier)),
revert: gain => Decimal.div(gain, unref(processedMultiplier))
};
}
export function createExponentialModifier(exponent: Computable<DecimalSource>): GainModifier {
const processedExponent = convertComputable(exponent);
return {
apply: gain => Decimal.pow(gain, unref(processedExponent)),
revert: gain => Decimal.root(gain, unref(processedExponent))
};
}
export function createSequentialModifier(...modifiers: GainModifier[]): GainModifier {
return {
apply: gain => modifiers.reduce((gain, modifier) => modifier.apply(gain), gain),
revert: gain => modifiers.reduceRight((gain, modifier) => modifier.revert(gain), gain)
};
}