mirror of
https://github.com/IvarK/AntimatterDimensionsSourceCode.git
synced 2024-11-21 19:42:17 +00:00
Refactor GMS class structure to allow multiple effects
This commit is contained in:
parent
23b0f059a0
commit
d79390e482
@ -108,7 +108,6 @@
|
||||
"computed-property-spacing": "error",
|
||||
"consistent-this": "error",
|
||||
"func-call-spacing": "error",
|
||||
"guard-for-in": "warn",
|
||||
"id-blacklist": [
|
||||
"error",
|
||||
"ret",
|
||||
|
10
index.html
10
index.html
@ -94,14 +94,20 @@
|
||||
<script type="text/javascript" src="javascripts/core/math.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/async-utils.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/effect.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/effects.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/game-mechanic.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/puchasable.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/set-purchasable.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/bit-purchasable.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/rebuyable.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/core/automator/automator-backend.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/effects.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/game-database.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/glyph-effects.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/player.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/performance-stats.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/currency.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanic.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/event-hub.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/cache.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/intervals.js"></script>
|
||||
|
@ -3,13 +3,6 @@
|
||||
class AchievementState extends GameMechanicState {
|
||||
constructor(config) {
|
||||
super(config);
|
||||
if (config.secondaryEffect) {
|
||||
const secondaryConfig = {
|
||||
id: config.id,
|
||||
effect: config.secondaryEffect
|
||||
};
|
||||
this._secondaryState = new AchievementState(secondaryConfig);
|
||||
}
|
||||
this._row = Math.floor(this.id / 10);
|
||||
this._column = this.id % 10;
|
||||
// eslint-disable-next-line no-bitwise
|
||||
@ -73,16 +66,8 @@ class AchievementState extends GameMechanicState {
|
||||
return this.isUnlocked;
|
||||
}
|
||||
|
||||
get isEffectConditionSatisfied() {
|
||||
return this.config.effectCondition === undefined || this.config.effectCondition();
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
return this.isEnabled && this.isEffectConditionSatisfied;
|
||||
}
|
||||
|
||||
get secondaryEffect() {
|
||||
return this._secondaryState;
|
||||
get isEffectActive() {
|
||||
return this.isUnlocked;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ function bigCrunchReset() {
|
||||
player.bestInfinitiesPerMs = player.bestInfinitiesPerMs.clampMin(
|
||||
gainedInfinities().round().dividedBy(player.thisInfinityRealTime)
|
||||
);
|
||||
|
||||
|
||||
const earlyGame = player.bestInfinityTime > 60000 && !player.break;
|
||||
const challenge = NormalChallenge.current || InfinityChallenge.current;
|
||||
EventHub.dispatch(GameEvent.BIG_CRUNCH_BEFORE);
|
||||
@ -139,7 +139,7 @@ class ChargedInfinityUpgradeState extends GameMechanicState {
|
||||
this._upgrade = upgrade;
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
get isEffectActive() {
|
||||
return this._upgrade.isBought && this._upgrade.isCharged;
|
||||
}
|
||||
}
|
||||
@ -165,7 +165,7 @@ class InfinityUpgrade extends SetPurchasableMechanicState {
|
||||
return this._requirement === undefined || this._requirement.isBought;
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
get isEffectActive() {
|
||||
return this.isBought && !this.isCharged;
|
||||
}
|
||||
|
||||
@ -215,7 +215,7 @@ function totalIPMult() {
|
||||
Achievement(93),
|
||||
Achievement(116),
|
||||
Achievement(125),
|
||||
Achievement(141),
|
||||
Achievement(141).effects.ipGain,
|
||||
InfinityUpgrade.ipMult,
|
||||
DilationUpgrade.ipMultDT,
|
||||
GlyphEffect.ipMult
|
||||
@ -305,10 +305,6 @@ class InfinityIPMultUpgrade extends GameMechanicState {
|
||||
return !this.isCapped && player.infinityPoints.gte(this.cost) && this.isRequirementSatisfied;
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
return true;
|
||||
}
|
||||
|
||||
purchase(amount = 1) {
|
||||
if (!this.canBeBought) return;
|
||||
const costIncrease = this.costIncrease;
|
||||
|
@ -45,7 +45,7 @@ class AlchemyResourceState extends GameMechanicState {
|
||||
return this.config.isUnlocked();
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
get hasCustomEffectValue() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ class CompressionUpgradeState extends BitPurchasableMechanicState {
|
||||
return this.config.effectDisplay(this.config.effect());
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
get isEffectActive() {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
const requirementFulfilled = new Decimal(this.config.resource()).gte(this.config.threshold()) ^
|
||||
this.config.invertedCondition;
|
||||
|
@ -121,10 +121,6 @@ class PerkShopUpgradeState extends RebuyableMechanicState {
|
||||
player.celestials.teresa.perkShop[this.id] = value;
|
||||
}
|
||||
|
||||
get cap() {
|
||||
return this.config.cap();
|
||||
}
|
||||
|
||||
get isCapped() {
|
||||
return this.cost === this.cap;
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ class InfinityChallengeRewardState extends GameMechanicState {
|
||||
this._challenge = challenge;
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
get isEffectActive() {
|
||||
return this._challenge.isCompleted;
|
||||
}
|
||||
}
|
||||
@ -194,7 +194,7 @@ class InfinityChallengeState extends GameMechanicState {
|
||||
player.challenge.infinity.completedBits |= 1 << this.id;
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
get isEffectActive() {
|
||||
return this.isRunning;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ function normalDimensionCommonMultiplier() {
|
||||
Achievement(73),
|
||||
Achievement(74),
|
||||
Achievement(76),
|
||||
Achievement(78),
|
||||
Achievement(78).effects.dimensionMult,
|
||||
Achievement(84),
|
||||
Achievement(91),
|
||||
Achievement(92),
|
||||
@ -331,7 +331,7 @@ function buyMaxDimension(tier, bulk = Infinity, auto = false) {
|
||||
return;
|
||||
}
|
||||
let buying = maxBought.quantity;
|
||||
if (buying > bulkLeft) buying = bulkLeft;
|
||||
if (buying > bulkLeft) buying = bulkLeft;
|
||||
dimension.amount = dimension.amount.plus(10 * buying).round();
|
||||
dimension.bought += 10 * buying;
|
||||
dimension.currencyAmount = dimension.currencyAmount.minus(Decimal.pow10(maxBought.logPrice));
|
||||
@ -596,9 +596,9 @@ const NormalDimensions = {
|
||||
},
|
||||
get buyTenMultiplier() {
|
||||
if (NormalChallenge(7).isRunning) return new Decimal(2).min(1 + DimBoost.totalBoosts / 5);
|
||||
|
||||
|
||||
let mult = new Decimal(2).plusEffectsOf(
|
||||
Achievement(141).secondaryEffect,
|
||||
Achievement(141).effects.buyTenMult,
|
||||
EternityChallenge(3).reward
|
||||
);
|
||||
|
||||
@ -606,9 +606,9 @@ const NormalDimensions = {
|
||||
InfinityUpgrade.buy10Mult,
|
||||
Achievement(58)
|
||||
).times(getAdjustedGlyphEffect("powerbuy10"));
|
||||
|
||||
|
||||
mult = mult.pow(getAdjustedGlyphEffect("effarigforgotten")).powEffectOf(InfinityUpgrade.buy10Mult.chargedEffect);
|
||||
|
||||
|
||||
return mult;
|
||||
}
|
||||
};
|
||||
@ -638,4 +638,4 @@ function produceAntimatter(diff) {
|
||||
player.antimatter = player.antimatter.plus(amProduced);
|
||||
player.totalAntimatter = player.totalAntimatter.plus(amProduced);
|
||||
player.thisInfinityMaxAM = player.thisInfinityMaxAM.max(player.antimatter);
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ function eternityResetReplicanti() {
|
||||
player.replicanti.gal = 0;
|
||||
player.replicanti.galaxies = 0;
|
||||
player.replicanti.galCost = new Decimal(1e170);
|
||||
if (EternityMilestone.autobuyerReplicantiGalaxy.isReached &&
|
||||
if (EternityMilestone.autobuyerReplicantiGalaxy.isReached &&
|
||||
player.replicanti.galaxybuyer === undefined) player.replicanti.galaxybuyer = false;
|
||||
}
|
||||
|
||||
@ -281,10 +281,6 @@ class EPMultiplierState extends GameMechanicState {
|
||||
this.cachedEffectValue = new Lazy(() => Decimal.pow(5, player.epmultUpgrades));
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get isAffordable() {
|
||||
return player.eternityPoints.gte(this.cost);
|
||||
}
|
||||
@ -305,6 +301,10 @@ class EPMultiplierState extends GameMechanicState {
|
||||
Autobuyer.eternity.bumpAmount(Decimal.pow(5, diff));
|
||||
}
|
||||
|
||||
get hasCustomEffectValue() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get effectValue() {
|
||||
return this.cachedEffectValue.value;
|
||||
}
|
||||
|
@ -31,11 +31,15 @@ class EternityChallengeRewardState extends GameMechanicState {
|
||||
this._challenge = challenge;
|
||||
}
|
||||
|
||||
get hasCustomEffectValue() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get effectValue() {
|
||||
return this.config.effect(this._challenge.completions);
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
get isEffectActive() {
|
||||
return this._challenge.completions > 0;
|
||||
}
|
||||
}
|
||||
@ -59,7 +63,7 @@ class EternityChallengeState extends GameMechanicState {
|
||||
return player.challenge.eternity.current === this.id;
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
get isEffectActive() {
|
||||
return this.isRunning;
|
||||
}
|
||||
|
||||
|
@ -1,229 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
class GameMechanicState {
|
||||
constructor(config) {
|
||||
if (!config) throw new Error("Must specify config for GameMechanicState");
|
||||
this.config = config;
|
||||
if (typeof this.config.effect === "number" || this.config.effect instanceof Decimal) {
|
||||
Object.defineProperty(this, "effectValue", {
|
||||
configurable: false,
|
||||
writable: false,
|
||||
value: this.config.effect,
|
||||
});
|
||||
if (this.config.cap === undefined) {
|
||||
Object.defineProperty(this, "cappedEffectValue", {
|
||||
configurable: false,
|
||||
writable: false,
|
||||
value: this.config.effect,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.config.id;
|
||||
}
|
||||
|
||||
get effectValue() {
|
||||
return this.config.effect();
|
||||
}
|
||||
|
||||
get cappedEffectValue() {
|
||||
const effectValue = this.effectValue;
|
||||
if (this.config.cap === undefined) return effectValue;
|
||||
const cap = typeof this.config.cap === "function"
|
||||
? this.config.cap()
|
||||
: this.config.cap;
|
||||
if (cap === undefined) return effectValue;
|
||||
return typeof effectValue === "number"
|
||||
? Math.min(effectValue, cap)
|
||||
: Decimal.min(effectValue, cap);
|
||||
}
|
||||
|
||||
effectOrDefault(defaultValue) {
|
||||
return this.canBeApplied ? this.cappedEffectValue : defaultValue;
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
return false;
|
||||
}
|
||||
|
||||
applyEffect(applyFn) {
|
||||
if (this.canBeApplied) applyFn(this.cappedEffectValue);
|
||||
}
|
||||
|
||||
static createAccessor(gameData) {
|
||||
const index = mapGameData(gameData, config => new this(config));
|
||||
const accessor = id => index[id];
|
||||
accessor.index = index;
|
||||
return accessor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
class PurchasableMechanicState extends GameMechanicState {
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get currency() { throw new NotImplementedError(); }
|
||||
|
||||
get isAffordable() {
|
||||
return this.currency.isAffordable(this.cost);
|
||||
}
|
||||
|
||||
get isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get isRebuyable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get cost() {
|
||||
return this.config.cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get isBought() { throw new NotImplementedError(); }
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
set isBought(value) { throw new NotImplementedError(); }
|
||||
|
||||
get canBeBought() {
|
||||
return !this.isBought && this.isAffordable && this.isAvailable;
|
||||
}
|
||||
|
||||
purchase() {
|
||||
if (!this.canBeBought) return false;
|
||||
this.currency.subtract(this.cost);
|
||||
this.isBought = true;
|
||||
GameUI.update();
|
||||
return true;
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
return this.isBought;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
class SetPurchasableMechanicState extends PurchasableMechanicState {
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get set() { throw new NotImplementedError(); }
|
||||
|
||||
get isBought() {
|
||||
return this.set.has(this.id);
|
||||
}
|
||||
|
||||
set isBought(value) {
|
||||
if (value) {
|
||||
this.set.add(this.id);
|
||||
} else {
|
||||
this.set.delete(this.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
class BitPurchasableMechanicState extends PurchasableMechanicState {
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get bits() { throw new NotImplementedError(); }
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
set bits(value) { throw new NotImplementedError(); }
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get bitIndex() { throw new NotImplementedError(); }
|
||||
|
||||
get isBought() {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return (this.bits & (1 << this.bitIndex)) !== 0;
|
||||
}
|
||||
|
||||
set isBought(value) {
|
||||
if (value) {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
this.bits |= (1 << this.bitIndex);
|
||||
} else {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
this.bits &= ~(1 << this.bitIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
class RebuyableMechanicState extends GameMechanicState {
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get currency() { throw new NotImplementedError(); }
|
||||
|
||||
get isAffordable() {
|
||||
return this.currency.isAffordable(this.cost);
|
||||
}
|
||||
|
||||
get cost() {
|
||||
return this.config.cost();
|
||||
}
|
||||
|
||||
get isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get isCapped() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get isRebuyable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get boughtAmount() { throw new NotImplementedError(); }
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
set boughtAmount(value) { throw new NotImplementedError(); }
|
||||
|
||||
get canBeApplied() {
|
||||
return this.boughtAmount > 0;
|
||||
}
|
||||
|
||||
get canBeBought() {
|
||||
return this.isAffordable && this.isAvailable && !this.isCapped;
|
||||
}
|
||||
|
||||
purchase() {
|
||||
if (!this.canBeBought) return false;
|
||||
this.currency.subtract(this.cost);
|
||||
this.boughtAmount++;
|
||||
GameUI.update();
|
||||
return true;
|
||||
}
|
||||
}
|
36
javascripts/core/game-mechanics/bit-purchasable.js
Normal file
36
javascripts/core/game-mechanics/bit-purchasable.js
Normal file
@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
class BitPurchasableMechanicState extends PurchasableMechanicState {
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get bits() { throw new NotImplementedError(); }
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
set bits(value) { throw new NotImplementedError(); }
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get bitIndex() { throw new NotImplementedError(); }
|
||||
|
||||
get isBought() {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return (this.bits & (1 << this.bitIndex)) !== 0;
|
||||
}
|
||||
|
||||
set isBought(value) {
|
||||
if (value) {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
this.bits |= (1 << this.bitIndex);
|
||||
} else {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
this.bits &= ~(1 << this.bitIndex);
|
||||
}
|
||||
}
|
||||
}
|
135
javascripts/core/game-mechanics/effect.js
Normal file
135
javascripts/core/game-mechanics/effect.js
Normal file
@ -0,0 +1,135 @@
|
||||
"use strict";
|
||||
|
||||
class Effect {
|
||||
get effectValue() {
|
||||
throw new Error("Effect is undefined.");
|
||||
}
|
||||
|
||||
get uncappedEffectValue() {
|
||||
throw new Error("Effect is undefined.");
|
||||
}
|
||||
|
||||
get cap() {
|
||||
throw new Error("Cap is undefined.");
|
||||
}
|
||||
|
||||
get isEffectConditionSatisfied() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get isEffectActive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
return this.isEffectActive && this.isEffectConditionSatisfied;
|
||||
}
|
||||
|
||||
effectOrDefault(defaultValue) {
|
||||
return this.canBeApplied ? this.effectValue : defaultValue;
|
||||
}
|
||||
|
||||
applyEffect(applyFn) {
|
||||
if (this.canBeApplied) applyFn(this.effectValue);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-params
|
||||
defineEffect(value, cap, condition) {
|
||||
const isFunction = v => typeof v === "function";
|
||||
const isNumber = v => typeof v === "number";
|
||||
const isDecimal = v => v instanceof Decimal;
|
||||
const isConstant = v => isNumber(v) || isDecimal(v);
|
||||
if (!isFunction(value) && !isConstant(value)) {
|
||||
throw new Error("Unknown effect value type.");
|
||||
}
|
||||
const createProperty = () => ({
|
||||
configurable: false
|
||||
});
|
||||
const addGetter = (property, v) => {
|
||||
if (isConstant(v)) {
|
||||
property.writable = false;
|
||||
property.value = v;
|
||||
} else if (isFunction(v)) {
|
||||
property.get = v;
|
||||
} else {
|
||||
throw new Error("Unknown getter type.");
|
||||
}
|
||||
};
|
||||
if (condition !== undefined) {
|
||||
if (!isFunction(condition)) {
|
||||
throw new Error("Effect condition must be a function.");
|
||||
}
|
||||
const conditionProperty = createProperty();
|
||||
conditionProperty.get = condition;
|
||||
Object.defineProperty(this, "isEffectConditionSatisfied", conditionProperty);
|
||||
}
|
||||
const uncappedEffectValueProperty = createProperty();
|
||||
addGetter(uncappedEffectValueProperty, value);
|
||||
Object.defineProperty(this, "uncappedEffectValue", uncappedEffectValueProperty);
|
||||
if (cap !== undefined) {
|
||||
const capProperty = createProperty();
|
||||
addGetter(capProperty, cap);
|
||||
Object.defineProperty(this, "cap", capProperty);
|
||||
}
|
||||
const effectValueProperty = createProperty();
|
||||
addGetter(effectValueProperty, value);
|
||||
if (isConstant(cap)) {
|
||||
if (isNumber(value)) {
|
||||
effectValueProperty.get = () => Math.min(value, this.cap);
|
||||
} else if (isDecimal(value)) {
|
||||
effectValueProperty.get = () => Decimal.min(value, this.cap);
|
||||
} else if (isFunction(value)) {
|
||||
// Postpone effectValue specialization until the first call
|
||||
effectValueProperty.configurable = true;
|
||||
effectValueProperty.get = () => {
|
||||
const effectValue = value();
|
||||
const specializedProperty = createProperty();
|
||||
if (isNumber(effectValue)) {
|
||||
specializedProperty.get = () => Math.min(value(), this.cap);
|
||||
} else if (isDecimal(effectValue)) {
|
||||
effectValueProperty.get = () => Decimal.min(value(), this.cap);
|
||||
} else {
|
||||
throw new Error("Unknown effect value type.");
|
||||
}
|
||||
Object.defineProperty(this, "effectValue", specializedProperty);
|
||||
return specializedProperty.get();
|
||||
};
|
||||
}
|
||||
} else if (isFunction(cap)) {
|
||||
if (isNumber(value)) {
|
||||
effectValueProperty.get = () => {
|
||||
const capValue = this.cap;
|
||||
return capValue === undefined ? value : Math.min(value, capValue);
|
||||
};
|
||||
} else if (isDecimal(value)) {
|
||||
effectValueProperty.get = () => {
|
||||
const capValue = this.cap;
|
||||
return capValue === undefined ? value : Decimal.min(value, capValue);
|
||||
};
|
||||
} else if (isFunction(value)) {
|
||||
// Postpone effectValue specialization until the first call
|
||||
effectValueProperty.configurable = true;
|
||||
effectValueProperty.get = () => {
|
||||
const effectValue = value();
|
||||
const specializedProperty = createProperty();
|
||||
if (isNumber(effectValue)) {
|
||||
specializedProperty.get = () => {
|
||||
const capValue = this.cap;
|
||||
return capValue === undefined ? value() : Math.min(value(), capValue);
|
||||
};
|
||||
} else if (isDecimal(effectValue)) {
|
||||
specializedProperty.get = () => {
|
||||
const capValue = this.cap;
|
||||
return capValue === undefined ? value() : Decimal.min(value(), capValue);
|
||||
};
|
||||
} else {
|
||||
throw new Error("Unknown effect value type.");
|
||||
}
|
||||
Object.defineProperty(this, "effectValue", specializedProperty);
|
||||
return specializedProperty.get();
|
||||
};
|
||||
}
|
||||
}
|
||||
Object.defineProperty(this, "effectValue", effectValueProperty);
|
||||
}
|
||||
}
|
51
javascripts/core/game-mechanics/game-mechanic.js
Normal file
51
javascripts/core/game-mechanics/game-mechanic.js
Normal file
@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
class GameMechanicState extends Effect {
|
||||
constructor(config) {
|
||||
super();
|
||||
if (!config) throw new Error("Must specify config for GameMechanicState");
|
||||
this._config = config;
|
||||
if (config.effect !== undefined && !this.hasCustomEffectValue) {
|
||||
this.defineEffect(config.effect, config.cap, config.effectCondition);
|
||||
}
|
||||
if (config.effects !== undefined) {
|
||||
this.effects = {};
|
||||
for (const key in config.effects) {
|
||||
const effect = new Effect();
|
||||
const value = config.effects[key];
|
||||
if (typeof value === "number" || value instanceof Decimal) {
|
||||
effect.defineEffect(value);
|
||||
} else {
|
||||
effect.defineEffect(value.effect, value.cap, value.effectCondition);
|
||||
}
|
||||
Object.defineProperty(effect, "isEffectActive", {
|
||||
configurable: false,
|
||||
get: () => this.isEffectActive
|
||||
});
|
||||
this.effects[key] = effect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get config() {
|
||||
return this._config;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.config.id;
|
||||
}
|
||||
|
||||
get hasCustomEffectValue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
static createAccessor(gameData) {
|
||||
const index = mapGameData(gameData, config => new this(config));
|
||||
const accessor = id => index[id];
|
||||
accessor.index = index;
|
||||
return accessor;
|
||||
}
|
||||
}
|
53
javascripts/core/game-mechanics/puchasable.js
Normal file
53
javascripts/core/game-mechanics/puchasable.js
Normal file
@ -0,0 +1,53 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
class PurchasableMechanicState extends GameMechanicState {
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get currency() { throw new NotImplementedError(); }
|
||||
|
||||
get isAffordable() {
|
||||
return this.currency.isAffordable(this.cost);
|
||||
}
|
||||
|
||||
get isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get isRebuyable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get cost() {
|
||||
return this.config.cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get isBought() { throw new NotImplementedError(); }
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
set isBought(value) { throw new NotImplementedError(); }
|
||||
|
||||
get canBeBought() {
|
||||
return !this.isBought && this.isAffordable && this.isAvailable;
|
||||
}
|
||||
|
||||
purchase() {
|
||||
if (!this.canBeBought) return false;
|
||||
this.currency.subtract(this.cost);
|
||||
this.isBought = true;
|
||||
GameUI.update();
|
||||
return true;
|
||||
}
|
||||
|
||||
get isEffectActive() {
|
||||
return this.isBought;
|
||||
}
|
||||
}
|
57
javascripts/core/game-mechanics/rebuyable.js
Normal file
57
javascripts/core/game-mechanics/rebuyable.js
Normal file
@ -0,0 +1,57 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
class RebuyableMechanicState extends GameMechanicState {
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get currency() { throw new NotImplementedError(); }
|
||||
|
||||
get isAffordable() {
|
||||
return this.currency.isAffordable(this.cost);
|
||||
}
|
||||
|
||||
get cost() {
|
||||
return this.config.cost();
|
||||
}
|
||||
|
||||
get isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get isCapped() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get isRebuyable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get boughtAmount() { throw new NotImplementedError(); }
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
set boughtAmount(value) { throw new NotImplementedError(); }
|
||||
|
||||
get isEffectActive() {
|
||||
return this.boughtAmount > 0;
|
||||
}
|
||||
|
||||
get canBeBought() {
|
||||
return this.isAffordable && this.isAvailable && !this.isCapped;
|
||||
}
|
||||
|
||||
purchase() {
|
||||
if (!this.canBeBought) return false;
|
||||
this.currency.subtract(this.cost);
|
||||
this.boughtAmount++;
|
||||
GameUI.update();
|
||||
return true;
|
||||
}
|
||||
}
|
23
javascripts/core/game-mechanics/set-purchasable.js
Normal file
23
javascripts/core/game-mechanics/set-purchasable.js
Normal file
@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
class SetPurchasableMechanicState extends PurchasableMechanicState {
|
||||
/**
|
||||
* @abstract
|
||||
*/
|
||||
get set() { throw new NotImplementedError(); }
|
||||
|
||||
get isBought() {
|
||||
return this.set.has(this.id);
|
||||
}
|
||||
|
||||
set isBought(value) {
|
||||
if (value) {
|
||||
this.set.add(this.id);
|
||||
} else {
|
||||
this.set.delete(this.id);
|
||||
}
|
||||
}
|
||||
}
|
@ -574,7 +574,7 @@ const Player = {
|
||||
Achievement(37),
|
||||
Achievement(54),
|
||||
Achievement(55),
|
||||
Achievement(78).secondaryEffect
|
||||
Achievement(78).effects.antimatter
|
||||
).toDecimal();
|
||||
},
|
||||
|
||||
|
@ -726,9 +726,7 @@ const Glyphs = {
|
||||
}
|
||||
};
|
||||
|
||||
class GlyphSacrificeState extends GameMechanicState {
|
||||
get canBeApplied() { return true; }
|
||||
}
|
||||
class GlyphSacrificeState extends GameMechanicState { }
|
||||
|
||||
const GlyphSacrifice = (function() {
|
||||
const db = GameDatabase.reality.glyphSacrifice;
|
||||
|
@ -461,9 +461,13 @@ GameDatabase.achievements.normal = [
|
||||
checkEvent: GameEvent.BIG_CRUNCH_BEFORE,
|
||||
reward: () => `Start with ${shorten(2e25, 0, 0)} antimatter ` +
|
||||
`and all Dimensions are stronger in the first ${shortenSmallInteger(300)}ms of Infinities.`,
|
||||
effect: () => 330 / (Time.thisInfinity.totalMilliseconds + 30),
|
||||
effectCondition: () => Time.thisInfinity.totalMilliseconds < 300,
|
||||
secondaryEffect: () => 2e25
|
||||
effects: {
|
||||
dimensionMult: {
|
||||
effect: () => 330 / (Time.thisInfinity.totalMilliseconds + 30),
|
||||
effectCondition: () => Time.thisInfinity.totalMilliseconds < 300,
|
||||
},
|
||||
antimatter: 2e25
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 81,
|
||||
@ -902,8 +906,10 @@ GameDatabase.achievements.normal = [
|
||||
checkEvent: GameEvent.REALITY_RESET_BEFORE,
|
||||
reward: () => `${shortenSmallInteger(4)}x IP gain and boost from
|
||||
buying ${shortenSmallInteger(10)} Dimensions +${shorten(0.1, 0, 1)}.`,
|
||||
effect: 4,
|
||||
secondaryEffect: () => 0.1
|
||||
effects: {
|
||||
ipGain: 4,
|
||||
buyTenMult: 0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 142,
|
||||
|
@ -165,8 +165,8 @@ function canBuyStudy(id) {
|
||||
}
|
||||
|
||||
function canBuyLocked(id) {
|
||||
return V.availableST >= TimeStudy(id).STCost &&
|
||||
TimeStudy(id) &&
|
||||
return V.availableST >= TimeStudy(id).STCost &&
|
||||
TimeStudy(id) &&
|
||||
TimeStudy(id).checkVRequirement();
|
||||
}
|
||||
|
||||
@ -392,7 +392,7 @@ class NormalTimeStudyState extends TimeStudyState {
|
||||
return canBuyStudy(this.id) || canBuyLocked(this.id);
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
get isEffectActive() {
|
||||
return this.isBought;
|
||||
}
|
||||
|
||||
@ -655,7 +655,7 @@ class TriadStudyState extends TimeStudyState {
|
||||
return this.config.description;
|
||||
}
|
||||
|
||||
get canBeApplied() {
|
||||
get isEffectActive() {
|
||||
return this.isBought;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user