Merge branch 'master' into make-all-fixed-elements-into-one-container

This commit is contained in:
Dys 2022-05-23 20:41:30 +08:00
commit 74006d53d9
94 changed files with 5493 additions and 5464 deletions

View File

@ -45,9 +45,9 @@
}
],
"keyframes-name-pattern": [
"^([_a-z][a-z0-9]*)([-_]{1,2}[a-z0-9]+)*$",
"^a-([-_]{0,2}[a-z0-9]+)*$",
{
"message": "Expected keyframe name to be kebab-case"
"message": "Keyframe name must begin with `a-` and be kebab-case"
}
],
"selector-id-pattern": [

View File

@ -57,36 +57,32 @@ import SacrificeModal from "@/components/modals/SacrificeModal";
import SingularityMilestonesModal from "@/components/modals/SingularityMilestonesModal";
import StdStoreModal from "@/components/modals/StdStoreModal";
import StudyStringModal from "@/components/modals/StudyStringModal";
import SwitchAutomatorEditorModal from "@/components/modals/SwitchAutomatorEditorModal";
import UiChoiceModal from "@/components/modals/UiChoiceModal";
import UndoGlyphModal from "@/components/modals/UndoGlyphModal";
export class Modal {
constructor(component, bare = false) {
constructor(component, priority = 0, bare = false) {
this._component = component;
this._bare = bare;
this._modalConfig = {};
this._prioritize = false;
this._priority = priority;
}
show(modalConfig) {
if (!GameUI.initialized) return;
this._props = Object.assign({}, modalConfig || {});
if (ui.view.modal.queue.length === 0) ui.view.modal.current = this;
// New modals go to the back of the queue (shown last).
if (!ui.view.modal.queue.includes(this)) {
if (this._prioritize) {
ui.view.modal.queue.unshift(this);
ui.view.modal.current = this;
} else {
ui.view.modal.queue.push(this);
}
}
}
prioritize() {
this._prioritize = true;
return this;
const modalQueue = ui.view.modal.queue;
// Add this modal to the front of the queue and sort based on priority to ensure priority is maintained.
modalQueue.unshift(this);
modalQueue.sort((x, y) => y.priority - x.priority);
// Filter out multiple instances of the same modal.
const singleQueue = [...new Set(modalQueue)];
ui.view.modal.queue = singleQueue;
// If the front of the queue is what is currently presented, we dont need to do anything.
if (!singleQueue[0].isOpen) ui.view.modal.current = singleQueue[0];
}
get isOpen() {
@ -105,6 +101,10 @@ export class Modal {
return this._props;
}
get priority() {
return this._priority;
}
static hide() {
if (!GameUI.initialized) return;
ui.view.modal.queue.shift();
@ -132,8 +132,7 @@ export class Modal {
class ChallengeConfirmationModal extends Modal {
show(id) {
this.id = id;
super.show();
super.show({ id });
}
}
@ -144,20 +143,20 @@ Modal.startEternityChallenge = new ChallengeConfirmationModal(EternityChallengeS
Modal.startInfinityChallenge = new ChallengeConfirmationModal(InfinityChallengeStartModal);
Modal.startNormalChallenge = new ChallengeConfirmationModal(NormalChallengeStartModal);
Modal.dimensionBoost = new Modal(DimensionBoostModal).prioritize();
Modal.antimatterGalaxy = new Modal(AntimatterGalaxyModal).prioritize();
Modal.bigCrunch = new Modal(BigCrunchModal).prioritize();
Modal.replicantiGalaxy = new Modal(ReplicantiGalaxyModal).prioritize();
Modal.eternity = new Modal(EternityModal).prioritize();
Modal.enterDilation = new Modal(EnterDilationModal).prioritize();
Modal.reality = new Modal(RealityModal).prioritize();
Modal.resetReality = new Modal(ResetRealityModal).prioritize();
Modal.exitCelestialReality = new Modal(ExitCelestialModal).prioritize();
Modal.celestials = new Modal(EnterCelestialsModal).prioritize();
Modal.hardReset = new Modal(HardResetModal).prioritize();
Modal.dimensionBoost = new Modal(DimensionBoostModal, 1);
Modal.antimatterGalaxy = new Modal(AntimatterGalaxyModal, 1);
Modal.bigCrunch = new Modal(BigCrunchModal, 1);
Modal.replicantiGalaxy = new Modal(ReplicantiGalaxyModal, 1);
Modal.eternity = new Modal(EternityModal, 1);
Modal.enterDilation = new Modal(EnterDilationModal, 1);
Modal.reality = new Modal(RealityModal, 1);
Modal.resetReality = new Modal(ResetRealityModal, 1);
Modal.exitCelestialReality = new Modal(ExitCelestialModal, 1);
Modal.celestials = new Modal(EnterCelestialsModal, 1);
Modal.hardReset = new Modal(HardResetModal, 1);
Modal.enterSpeedrun = new Modal(SpeedrunModeModal);
Modal.changeName = new Modal(ChangeNameModal);
Modal.armageddon = new Modal(ArmageddonModal).prioritize();
Modal.armageddon = new Modal(ArmageddonModal, 1);
Modal.confirmationOptions = new Modal(ConfirmationOptionsModal);
Modal.infoDisplayOptions = new Modal(InfoDisplayOptionsModal);
@ -168,16 +167,16 @@ Modal.animationOptions = new Modal(AnimationOptionsModal);
Modal.hiddenTabs = new Modal(HiddenTabsModal);
Modal.preferredTree = new Modal(PreferredTreeModal);
Modal.deleteCompanion = new Modal(DeleteCompanionGlyphModal).prioritize();
Modal.glyphDelete = new Modal(DeleteGlyphModal).prioritize();
Modal.glyphPurge = new Modal(PurgeGlyphModal).prioritize();
Modal.glyphSacrifice = new Modal(SacrificeGlyphModal).prioritize();
Modal.glyphRefine = new Modal(RefineGlyphModal).prioritize();
Modal.deleteAllUnprotectedGlyphs = new Modal(PurgeAllUnprotectedGlyphsModal).prioritize();
Modal.deleteAllRejectedGlyphs = new Modal(PurgeAllRejectedGlyphsModal).prioritize();
Modal.deleteCompanion = new Modal(DeleteCompanionGlyphModal, 1);
Modal.glyphDelete = new Modal(DeleteGlyphModal, 1);
Modal.glyphPurge = new Modal(PurgeGlyphModal, 1);
Modal.glyphSacrifice = new Modal(SacrificeGlyphModal, 1);
Modal.glyphRefine = new Modal(RefineGlyphModal, 1);
Modal.deleteAllUnprotectedGlyphs = new Modal(PurgeAllUnprotectedGlyphsModal, 1);
Modal.deleteAllRejectedGlyphs = new Modal(PurgeAllRejectedGlyphsModal, 1);
Modal.glyphShowcasePanel = new Modal(GlyphShowcasePanelModal);
Modal.glyphUndo = new Modal(UndoGlyphModal).prioritize();
Modal.glyphUndo = new Modal(UndoGlyphModal, 1);
Modal.glyphReplace = new Modal(ReplaceGlyphModal);
Modal.enslavedHints = new Modal(EnslavedHintsModal);
Modal.realityGlyph = new Modal(RealityGlyphCreationModal);
@ -191,12 +190,13 @@ Modal.import = new Modal(ImportSaveModal);
Modal.importScript = new Modal(ImportAutomatorScriptModal);
Modal.automatorScriptDelete = new Modal(DeleteAutomatorScriptModal);
Modal.automatorScriptTemplate = new Modal(AutomatorScriptTemplate);
Modal.switchAutomatorEditorMode = new Modal(SwitchAutomatorEditorModal);
Modal.shop = new Modal(StdStoreModal);
Modal.studyString = new Modal(StudyStringModal);
Modal.singularityMilestones = new Modal(SingularityMilestonesModal);
Modal.pelleEffects = new Modal(PelleEffectsModal);
Modal.sacrifice = new Modal(SacrificeModal).prioritize();
Modal.breakInfinity = new Modal(BreakInfinityModal);
Modal.sacrifice = new Modal(SacrificeModal, 1);
Modal.breakInfinity = new Modal(BreakInfinityModal, 1);
Modal.celestialQuote = new class extends Modal {
show(celestial, lines) {
if (!GameUI.initialized || player.speedrun.isActive) return;
@ -245,7 +245,7 @@ Modal.celestialQuote = new class extends Modal {
}
return x;
}
}(CelestialQuoteModal, true);
}(CelestialQuoteModal, 2, true);
Modal.cloudSaveConflict = new Modal(CloudSaveConflictModal);
Modal.cloudLoadConflict = new Modal(CloudLoadConflictModal);
@ -319,4 +319,4 @@ Modal.message = new class extends Modal {
this.closeButton = this.queue[0].closeButton;
}
}
}(MessageModal);
}(MessageModal, 2);

View File

@ -1,4 +1,5 @@
import { sha512_256 } from "js-sha512";
import FullScreenAnimationHandler from "../full-screen-animation-handler";
export class GameOptions {
@ -67,7 +68,7 @@ export function isSecretImport(data) {
export function tryImportSecret(data) {
const index = secretImportIndex(data);
if (index === 0) {
FullScreenAnimationHandler.display("barrelRoll", 5);
FullScreenAnimationHandler.display("a-barrel-roll", 5);
SecretAchievement(15).unlock();
return true;
}

View File

@ -97,7 +97,7 @@ const ReactivityComplainer = {
throw new Error(`Boi you fukked up - ${path} became REACTIVE (oh shite)`);
}
for (const key in obj) {
if (!obj.hasOwnProperty(key)) continue;
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
const prop = obj[key];
if (typeof prop === "object") {
this.checkReactivity(prop, `${path}.${key}`);

View File

@ -28,7 +28,7 @@ class InfinityDimensionAutobuyerState extends IntervaledAutobuyerState {
}
get isUnlocked() {
return EternityMilestone.autobuyerID(this.tier).isReached || PelleUpgrade.IDAutobuyers.canBeApplied;
return EternityMilestone[`autobuyerID${this.tier}`].isReached || PelleUpgrade.IDAutobuyers.canBeApplied;
}
get resetTickOn() {

View File

@ -111,7 +111,6 @@ class AutomatorStackEntry {
export class AutomatorScript {
constructor(id) {
if (!id) throw new Error("Invalid Automator script ID");
this._id = id;
this.compile();
}
@ -183,7 +182,7 @@ export const AutomatorData = {
createNewScript(newScript, name) {
const newScriptID = Object.values(player.reality.automator.scripts).length + 1;
player.reality.automator.scripts[newScriptID] = {
id: `${newScriptID}`,
id: newScriptID,
name,
content: newScript
};
@ -243,12 +242,31 @@ export const AutomatorBackend = {
return this.isOn && this.mode === AUTOMATOR_MODE.RUN;
},
findRawScriptObject(id) {
const auto = player.reality.automator;
const index = Object.values(auto.scripts).findIndex(s => s.id === id);
return auto.scripts[parseInt(Object.keys(auto.scripts)[index], 10)];
},
get currentRunningScript() {
return this.findRawScriptObject(this.state.topLevelScript);
},
get currentEditingScript() {
return this.findRawScriptObject(player.reality.automator.state.editorScript);
},
get scriptName() {
return this.findScript(this.state.topLevelScript).name;
return this.currentRunningScript?.name ?? "";
},
hasDuplicateName(name) {
const nameArray = Object.values(player.reality.automator.scripts).map(s => s.name);
return nameArray.filter(n => n === name).length > 1;
},
get currentLineNumber() {
if (this.stack.top === null)
if (!this.stack.top)
return -1;
return this.stack.top.lineNumber;
},
@ -257,6 +275,14 @@ export const AutomatorBackend = {
return Math.clampMin(Math.pow(0.994, Currency.realities.value) * 500, 1);
},
get currentRawText() {
return this.currentRunningScript?.content ?? "";
},
get currentScriptLength() {
return this.currentRawText.split("\n").length;
},
update(diff) {
if (!this.isOn) return;
let stack;
@ -351,10 +377,7 @@ export const AutomatorBackend = {
},
findScript(id) {
// I tried really hard to convert IDs from strings into numbers for some cleanup but I just kept getting constant
// errors everywhere. It needs to be a number so that importing works properly without ID assignment being a mess,
// but apparently some deeper things seem to break in a way I can't easily fix.
return this._scripts.find(e => `${e.id}` === `${id}`);
return this._scripts.find(e => e.id === id);
},
_createDefaultScript() {
@ -365,13 +388,13 @@ export const AutomatorBackend = {
},
initializeFromSave() {
const scriptIds = Object.keys(player.reality.automator.scripts);
const scriptIds = Object.keys(player.reality.automator.scripts).map(id => parseInt(id, 10));
if (scriptIds.length === 0) {
scriptIds.push(this._createDefaultScript());
} else {
this._scripts = scriptIds.map(s => new AutomatorScript(s));
}
if (!scriptIds.includes(`${this.state.topLevelScript}`)) this.state.topLevelScript = scriptIds[0];
if (!scriptIds.includes(this.state.topLevelScript)) this.state.topLevelScript = scriptIds[0];
const currentScript = this.findScript(this.state.topLevelScript);
if (currentScript.commands) {
const commands = currentScript.commands;
@ -392,10 +415,14 @@ export const AutomatorBackend = {
return newScript;
},
// Note that deleting scripts leaves gaps in the automator script indexing since automator scripts can't be
// dynamically re-indexed while the automator is running without causing a stutter from recompiling scripts.
deleteScript(id) {
// We need to delete scripts from two places - in the savefile and compiled AutomatorScript Objects
const saveId = Object.values(player.reality.automator.scripts).findIndex(s => s.id === id);
delete player.reality.automator.scripts[parseInt(Object.keys(player.reality.automator.scripts)[saveId], 10)];
const idx = this._scripts.findIndex(e => e.id === id);
this._scripts.splice(idx, 1);
delete player.reality.automator.scripts[id];
if (this._scripts.length === 0) {
this._createDefaultScript();
}

View File

@ -35,19 +35,17 @@ export const AutomatorPoints = {
}
};
GameDatabase.reality.otherAutomatorPoints = (function() {
return [
{
name: "Reality Count",
automatorPoints: () => 2 * Math.clampMax(Currency.realities.value, 100),
shortDescription: () => `+${formatInt(2)} per Reality, up to ${formatInt(100)} Realities`,
symbol: "Ϟ",
},
{
name: "Black Hole",
automatorPoints: () => (BlackHole(1).isUnlocked ? 10 : 0),
shortDescription: () => `Unlocking gives ${formatInt(10)} AP`,
symbol: "<i class='fas fa-circle'></i>",
},
];
}());
GameDatabase.reality.otherAutomatorPoints = [
{
name: "Reality Count",
automatorPoints: () => 2 * Math.clampMax(Currency.realities.value, 100),
shortDescription: () => `+${formatInt(2)} per Reality, up to ${formatInt(100)} Realities`,
symbol: "Ϟ",
},
{
name: "Black Hole",
automatorPoints: () => (BlackHole(1).isUnlocked ? 10 : 0),
shortDescription: () => `Unlocking gives ${formatInt(10)} AP`,
symbol: "<i class='fas fa-circle'></i>",
},
];

View File

@ -1,10 +1,8 @@
import { GameMechanicState, RebuyableMechanicState, SetPurchasableMechanicState } from "./game-mechanics/index";
import { DC } from "./constants";
import FullScreenAnimationHandler from "./full-screen-animation-handler";
import { SpeedrunMilestones } from "./speedrun";
export function bigCrunchAnimation() {
FullScreenAnimationHandler.display("implode", 2);
FullScreenAnimationHandler.display("a-implode", 2);
}
function handleChallengeCompletion() {
@ -150,311 +148,6 @@ export function secondSoftReset(forcedNDReset = false) {
AchievementTimers.marathon2.reset();
}
class ChargedInfinityUpgradeState extends GameMechanicState {
constructor(config, upgrade) {
super(config);
this._upgrade = upgrade;
}
get isEffectActive() {
return this._upgrade.isBought && this._upgrade.isCharged;
}
}
export class InfinityUpgrade extends SetPurchasableMechanicState {
constructor(config, requirement) {
super(config);
if (Array.isArray(requirement) || typeof requirement === "function") {
this._requirements = requirement;
} else if (requirement === undefined) {
this._requirements = [];
} else {
this._requirements = [requirement];
}
if (config.charged) {
this._chargedEffect = new ChargedInfinityUpgradeState(config.charged, this);
}
}
get currency() {
return Currency.infinityPoints;
}
get set() {
return player.infinityUpgrades;
}
get isAvailableForPurchase() {
return typeof this._requirements === "function" ? this._requirements()
: this._requirements.every(x => x.isBought);
}
get isEffectActive() {
return this.isBought && !this.isCharged;
}
get chargedEffect() {
return this._chargedEffect;
}
purchase() {
if (super.purchase()) {
// This applies the 4th column of infinity upgrades retroactively
if (this.config.id.includes("skip")) skipResetsIfPossible();
EventHub.dispatch(GAME_EVENT.INFINITY_UPGRADE_BOUGHT);
return true;
}
if (this.canCharge) {
this.charge();
return true;
}
return false;
}
get hasChargeEffect() {
return this.config.charged !== undefined;
}
get isCharged() {
return player.celestials.ra.charged.has(this.id);
}
get canCharge() {
return this.isBought &&
this.hasChargeEffect &&
!this.isCharged &&
Ra.chargesLeft !== 0 &&
!Pelle.isDisabled("chargedInfinityUpgrades");
}
charge() {
player.celestials.ra.charged.add(this.id);
}
disCharge() {
player.celestials.ra.charged.delete(this.id);
}
}
export function totalIPMult() {
if (Effarig.isRunning && Effarig.currentStage === EFFARIG_STAGES.INFINITY) {
return DC.D1;
}
let ipMult = DC.D1
.times(ShopPurchase.IPPurchases.currentMult)
.timesEffectsOf(
TimeStudy(41),
TimeStudy(51),
TimeStudy(141),
TimeStudy(142),
TimeStudy(143),
Achievement(85),
Achievement(93),
Achievement(116),
Achievement(125),
Achievement(141).effects.ipGain,
InfinityUpgrade.ipMult,
DilationUpgrade.ipMultDT,
GlyphEffect.ipMult
);
ipMult = ipMult.times(Replicanti.amount.powEffectOf(AlchemyResource.exponential));
return ipMult;
}
export function disChargeAll() {
const upgrades = [
InfinityUpgrade.totalTimeMult,
InfinityUpgrade.dim18mult,
InfinityUpgrade.dim36mult,
InfinityUpgrade.resetBoost,
InfinityUpgrade.buy10Mult,
InfinityUpgrade.dim27mult,
InfinityUpgrade.dim45mult,
InfinityUpgrade.galaxyBoost,
InfinityUpgrade.thisInfinityTimeMult,
InfinityUpgrade.unspentIPMult,
InfinityUpgrade.dimboostMult,
InfinityUpgrade.ipGen
];
for (const upgrade of upgrades) {
if (upgrade.isCharged) {
upgrade.disCharge();
}
}
player.celestials.ra.disCharge = false;
}
(function() {
const db = GameDatabase.infinity.upgrades;
const upgrade = (config, requirement) => new InfinityUpgrade(config, requirement);
InfinityUpgrade.totalTimeMult = upgrade(db.totalTimeMult);
InfinityUpgrade.dim18mult = upgrade(db.dim18mult, InfinityUpgrade.totalTimeMult);
InfinityUpgrade.dim36mult = upgrade(db.dim36mult, InfinityUpgrade.dim18mult);
InfinityUpgrade.resetBoost = upgrade(db.resetBoost, InfinityUpgrade.dim36mult);
InfinityUpgrade.buy10Mult = upgrade(db.buy10Mult);
InfinityUpgrade.dim27mult = upgrade(db.dim27mult, InfinityUpgrade.buy10Mult);
InfinityUpgrade.dim45mult = upgrade(db.dim45mult, InfinityUpgrade.dim27mult);
InfinityUpgrade.galaxyBoost = upgrade(db.galaxyBoost, InfinityUpgrade.dim45mult);
InfinityUpgrade.thisInfinityTimeMult = upgrade(db.thisInfinityTimeMult);
InfinityUpgrade.unspentIPMult = upgrade(db.unspentIPMult, InfinityUpgrade.thisInfinityTimeMult);
InfinityUpgrade.dimboostMult = upgrade(db.dimboostMult, InfinityUpgrade.unspentIPMult);
InfinityUpgrade.ipGen = upgrade(db.ipGen, InfinityUpgrade.dimboostMult);
InfinityUpgrade.skipReset1 = upgrade(db.skipReset1);
InfinityUpgrade.skipReset2 = upgrade(db.skipReset2, InfinityUpgrade.skipReset1);
InfinityUpgrade.skipReset3 = upgrade(db.skipReset3, InfinityUpgrade.skipReset2);
InfinityUpgrade.skipResetGalaxy = upgrade(db.skipResetGalaxy, InfinityUpgrade.skipReset3);
InfinityUpgrade.ipOffline = upgrade(db.ipOffline, () => Achievement(41).isUnlocked);
}());
// The repeatable 2xIP upgrade has an odd cost structure - it follows a shallow exponential (step *10) up to e3M, at
// which point it follows a steeper one (step *1e10) up to e6M before finally hardcapping. At the hardcap, there's
// an extra bump that increases the multipler itself from e993k to e1M. All these numbers are specified in
// GameDatabase.infinity.upgrades.ipMult
class InfinityIPMultUpgrade extends GameMechanicState {
get cost() {
if (this.purchaseCount >= this.purchasesAtIncrease) {
return this.config.costIncreaseThreshold
.times(Decimal.pow(this.costIncrease, this.purchaseCount - this.purchasesAtIncrease));
}
return Decimal.pow(this.costIncrease, this.purchaseCount + 1);
}
get purchaseCount() {
return player.IPMultPurchases;
}
get purchasesAtIncrease() {
return this.config.costIncreaseThreshold.log10() - 1;
}
get hasIncreasedCost() {
return this.purchaseCount >= this.purchasesAtIncrease;
}
get costIncrease() {
return this.hasIncreasedCost ? 1e10 : 10;
}
get isCapped() {
return this.cost.gte(this.config.costCap);
}
get isBought() {
return this.isCapped;
}
get isRequirementSatisfied() {
return Achievement(41).isUnlocked;
}
get canBeBought() {
return !Pelle.isDoomed && !this.isCapped && Currency.infinityPoints.gte(this.cost) && this.isRequirementSatisfied;
}
// This is only ever called with amount = 1 or within buyMax under conditions that ensure the scaling doesn't
// change mid-purchase
purchase(amount = 1) {
if (!this.canBeBought) return;
if (!TimeStudy(181).isBought) {
Autobuyer.bigCrunch.bumpAmount(DC.D2.pow(amount));
}
Currency.infinityPoints.subtract(Decimal.sumGeometricSeries(amount, this.cost, this.costIncrease, 0));
player.IPMultPurchases += amount;
GameUI.update();
}
buyMax() {
if (!this.canBeBought) return;
if (!this.hasIncreasedCost) {
// Only allow IP below the softcap to be used
const availableIP = Currency.infinityPoints.value.clampMax(this.config.costIncreaseThreshold);
const purchases = Decimal.affordGeometricSeries(availableIP, this.cost, this.costIncrease, 0).toNumber();
if (purchases <= 0) return;
this.purchase(purchases);
}
// Do not replace it with `if else` - it's specifically designed to process two sides of threshold separately
// (for example, we have 1e4000000 IP and no mult - first it will go to (but not including) 1e3000000 and then
// it will go in this part)
if (this.hasIncreasedCost) {
const availableIP = Currency.infinityPoints.value.clampMax(this.config.costCap);
const purchases = Decimal.affordGeometricSeries(availableIP, this.cost, this.costIncrease, 0).toNumber();
if (purchases <= 0) return;
this.purchase(purchases);
}
}
}
InfinityUpgrade.ipMult = new InfinityIPMultUpgrade(GameDatabase.infinity.upgrades.ipMult);
export class BreakInfinityUpgrade extends SetPurchasableMechanicState {
get currency() {
return Currency.infinityPoints;
}
get set() {
return player.infinityUpgrades;
}
onPurchased() {
if (this.id === "postGalaxy") {
SpeedrunMilestones(7).tryComplete();
PelleStrikes.powerGalaxies.trigger();
}
}
}
(function() {
const db = GameDatabase.infinity.breakUpgrades;
const upgrade = props => new BreakInfinityUpgrade(props);
BreakInfinityUpgrade.totalAMMult = upgrade(db.totalAMMult);
BreakInfinityUpgrade.currentAMMult = upgrade(db.currentAMMult);
BreakInfinityUpgrade.galaxyBoost = upgrade(db.galaxyBoost);
BreakInfinityUpgrade.infinitiedMult = upgrade(db.infinitiedMult);
BreakInfinityUpgrade.achievementMult = upgrade(db.achievementMult);
BreakInfinityUpgrade.slowestChallengeMult = upgrade(db.slowestChallengeMult);
BreakInfinityUpgrade.infinitiedGen = upgrade(db.infinitiedGen);
BreakInfinityUpgrade.autobuyMaxDimboosts = upgrade(db.autobuyMaxDimboosts);
BreakInfinityUpgrade.autobuyerSpeed = upgrade(db.autobuyerSpeed);
}());
class RebuyableBreakInfinityUpgradeState extends RebuyableMechanicState {
get currency() {
return Currency.infinityPoints;
}
get boughtAmount() {
return player.infinityRebuyables[this.id];
}
set boughtAmount(value) {
player.infinityRebuyables[this.id] = value;
}
get isCapped() {
return this.boughtAmount === this.config.maxUpgrades;
}
}
BreakInfinityUpgrade.tickspeedCostMult = new class extends RebuyableBreakInfinityUpgradeState {
onPurchased() {
GameCache.tickSpeedMultDecrease.invalidate();
}
}(GameDatabase.infinity.breakUpgrades.tickspeedCostMult);
BreakInfinityUpgrade.dimCostMult = new class extends RebuyableBreakInfinityUpgradeState {
onPurchased() {
GameCache.dimensionMultDecrease.invalidate();
}
}(GameDatabase.infinity.breakUpgrades.dimCostMult);
BreakInfinityUpgrade.ipGen = new RebuyableBreakInfinityUpgradeState(GameDatabase.infinity.breakUpgrades.ipGen);
export function preProductionGenerateIP(diff) {
if (InfinityUpgrade.ipGen.isBought) {
const genPeriod = Time.bestInfinity.totalMilliseconds * 10;

View File

@ -0,0 +1,48 @@
import { RebuyableMechanicState, SetPurchasableMechanicState } from "./game-mechanics/index";
import { SpeedrunMilestones } from "./speedrun";
export class BreakInfinityUpgradeState extends SetPurchasableMechanicState {
get currency() {
return Currency.infinityPoints;
}
get set() {
return player.infinityUpgrades;
}
onPurchased() {
if (this.id === "postGalaxy") {
SpeedrunMilestones(7).tryComplete();
PelleStrikes.powerGalaxies.trigger();
}
}
}
class RebuyableBreakInfinityUpgradeState extends RebuyableMechanicState {
get currency() {
return Currency.infinityPoints;
}
get boughtAmount() {
return player.infinityRebuyables[this.id];
}
set boughtAmount(value) {
player.infinityRebuyables[this.id] = value;
}
get isCapped() {
return this.boughtAmount === this.config.maxUpgrades;
}
onPurchased() {
this.config.onPurchased?.();
}
}
export const BreakInfinityUpgrade = mapGameDataToObject(
GameDatabase.infinity.breakUpgrades,
config => (config.rebuyable
? new RebuyableBreakInfinityUpgradeState(config)
: new BreakInfinityUpgradeState(config))
);

View File

@ -178,41 +178,14 @@ class EffarigUnlockState extends BitUpgradeState {
purchase() {
if (this.isUnlocked || !Currency.relicShards.purchase(this.cost)) return;
this.unlock();
switch (this) {
case EffarigUnlock.adjuster:
Effarig.quotes.show(Effarig.quotes.UNLOCK_WEIGHTS);
ui.view.tabs.reality.openGlyphWeights = true;
Tab.reality.glyphs.show();
break;
case EffarigUnlock.glyphFilter:
Effarig.quotes.show(Effarig.quotes.UNLOCK_GLYPH_FILTER);
player.reality.showSidebarPanel = GLYPH_SIDEBAR_MODE.FILTER_SETTINGS;
break;
case EffarigUnlock.setSaves:
Effarig.quotes.show(Effarig.quotes.UNLOCK_SET_SAVES);
player.reality.showSidebarPanel = GLYPH_SIDEBAR_MODE.SAVED_SETS;
break;
case EffarigUnlock.run:
Effarig.quotes.show(Effarig.quotes.UNLOCK_RUN);
break;
default:
throw new Error("Unknown Effarig upgrade");
}
this.config.onPurchased?.();
}
}
export const EffarigUnlock = (function() {
const db = GameDatabase.celestials.effarig.unlocks;
return {
adjuster: new EffarigUnlockState(db.adjuster),
glyphFilter: new EffarigUnlockState(db.glyphFilter),
setSaves: new EffarigUnlockState(db.setSaves),
run: new EffarigUnlockState(db.run),
infinity: new EffarigUnlockState(db.infinity),
eternity: new EffarigUnlockState(db.eternity),
reality: new EffarigUnlockState(db.reality),
};
}());
export const EffarigUnlock = mapGameDataToObject(
GameDatabase.celestials.effarig.unlocks,
config => new EffarigUnlockState(config)
);
EventHub.logic.on(GAME_EVENT.TAB_CHANGED, () => {
if (Tab.celestials.effarig.isOpen) Effarig.quotes.show(Effarig.quotes.INITIAL);

View File

@ -266,19 +266,10 @@ class EnslavedProgressState extends BitUpgradeState {
}
}
export const EnslavedProgress = (function() {
const db = GameDatabase.celestials.enslaved.progress;
return {
hintsUnlocked: new EnslavedProgressState(db.hintsUnlocked),
ec1: new EnslavedProgressState(db.ec1),
feelEternity: new EnslavedProgressState(db.feelEternity),
ec6: new EnslavedProgressState(db.ec6),
c10: new EnslavedProgressState(db.c10),
secretStudy: new EnslavedProgressState(db.secretStudy),
storedTime: new EnslavedProgressState(db.storedTime),
challengeCombo: new EnslavedProgressState(db.challengeCombo),
};
}());
export const EnslavedProgress = mapGameDataToObject(
GameDatabase.celestials.enslaved.progress,
config => new EnslavedProgressState(config)
);
export const Tesseracts = {
get bought() {

View File

@ -31,14 +31,18 @@ class SingularityMilestoneState extends GameMechanicState {
return Currency.singularities.gte(this.start);
}
get increaseThreshold() {
return this.config.increaseThreshold;
}
nerfCompletions(completions) {
const softcap = this.config.increaseThreshold;
const softcap = this.increaseThreshold;
if (!softcap || (completions < softcap)) return completions;
return softcap + (completions - softcap) / 3;
}
unnerfCompletions(completions) {
const softcap = this.config.increaseThreshold;
const softcap = this.increaseThreshold;
if (!softcap || (completions < softcap)) return completions;
return softcap + (completions - softcap) * 3;
}
@ -95,42 +99,13 @@ class SingularityMilestoneState extends GameMechanicState {
}
}
export const SingularityMilestone = (function() {
const db = GameDatabase.celestials.singularityMilestones;
return {
continuumMult: new SingularityMilestoneState(db.continuumMult),
darkMatterMult: new SingularityMilestoneState(db.darkMatterMult),
darkEnergyMult: new SingularityMilestoneState(db.darkEnergyMult),
darkDimensionCostReduction: new SingularityMilestoneState(db.darkDimensionCostReduction),
singularityMult: new SingularityMilestoneState(db.singularityMult),
darkDimensionIntervalReduction: new SingularityMilestoneState(db.darkDimensionIntervalReduction),
ascensionIntervalScaling: new SingularityMilestoneState(db.ascensionIntervalScaling),
autoCondense: new SingularityMilestoneState(db.autoCondense),
darkDimensionAutobuyers: new SingularityMilestoneState(db.darkDimensionAutobuyers),
darkAutobuyerSpeed: new SingularityMilestoneState(db.darkAutobuyerSpeed),
improvedSingularityCap: new SingularityMilestoneState(db.improvedSingularityCap),
darkFromTesseracts: new SingularityMilestoneState(db.darkFromTesseracts),
dilatedTimeFromSingularities: new SingularityMilestoneState(db.dilatedTimeFromSingularities),
darkFromGlyphLevel: new SingularityMilestoneState(db.darkFromGlyphLevel),
gamespeedFromSingularities: new SingularityMilestoneState(db.gamespeedFromSingularities),
darkFromTheorems: new SingularityMilestoneState(db.darkFromTheorems),
dim4Generation: new SingularityMilestoneState(db.dim4Generation),
darkFromDM4: new SingularityMilestoneState(db.darkFromDM4),
theoremPowerFromSingularities: new SingularityMilestoneState(db.theoremPowerFromSingularities),
darkFromGamespeed: new SingularityMilestoneState(db.darkFromGamespeed),
glyphLevelFromSingularities: new SingularityMilestoneState(db.glyphLevelFromSingularities),
darkFromDilatedTime: new SingularityMilestoneState(db.darkFromDilatedTime),
tesseractMultFromSingularities: new SingularityMilestoneState(db.tesseractMultFromSingularities),
improvedAscensionDM: new SingularityMilestoneState(db.improvedAscensionDM),
realityDEMultiplier: new SingularityMilestoneState(db.realityDEMultiplier),
intervalCostScalingReduction: new SingularityMilestoneState(db.intervalCostScalingReduction),
multFromInfinitied: new SingularityMilestoneState(db.multFromInfinitied),
infinitiedPow: new SingularityMilestoneState(db.infinitiedPow),
};
}());
export const SingularityMilestone = mapGameDataToObject(
GameDatabase.celestials.singularityMilestones,
config => new SingularityMilestoneState(config)
);
export const SingularityMilestones = {
all: Object.values(SingularityMilestone),
all: SingularityMilestone.all,
lastNotified: player.celestials.laitela.lastCheckedMilestones,
get sorted() {
@ -228,7 +203,7 @@ export const SingularityMilestones = {
// Sorted list of all the values where a singularity milestone exists, used for "new milestone" styling
const SingularityMilestoneThresholds = (function() {
return Object.values(GameDatabase.celestials.singularityMilestones)
return SingularityMilestones.all
.map(m => Array.range(0, Math.min(50, m.limit))
.filter(r => !m.increaseThreshold || r <= m.increaseThreshold ||
(r > m.increaseThreshold && ((r - m.increaseThreshold) % 3) === 2))

View File

@ -115,9 +115,7 @@ export class GalaxyGeneratorUpgrade extends RebuyableMechanicState {
}
}
export const GalaxyGeneratorUpgrades = (function() {
return mapGameDataToObject(
GameDatabase.celestials.pelle.galaxyGeneratorUpgrades,
config => new GalaxyGeneratorUpgrade(config)
);
}());
export const GalaxyGeneratorUpgrades = mapGameDataToObject(
GameDatabase.celestials.pelle.galaxyGeneratorUpgrades,
config => new GalaxyGeneratorUpgrade(config)
);

View File

@ -118,7 +118,8 @@ export const Pelle = {
},
get disabledAchievements() {
return [143, 142, 141, 133, 125, 118, 117, 111, 104, 103, 92, 91, 78, 76, 74, 65, 55, 54, 37];
return [164, 143, 142, 141, 137, 134, 133, 132, 125, 118, 117, 113, 111, 104, 103, 93, 92, 91, 87, 85, 78, 76,
74, 65, 55, 54, 37];
},
get uselessInfinityUpgrades() {
@ -455,15 +456,13 @@ export class PelleUpgradeState extends SetPurchasableMechanicState {
}
export const PelleUpgrade = (function() {
return mapGameDataToObject(
GameDatabase.celestials.pelle.upgrades,
config => (config.rebuyable
? new RebuyablePelleUpgradeState(config)
: new PelleUpgradeState(config)
)
);
}());
export const PelleUpgrade = mapGameDataToObject(
GameDatabase.celestials.pelle.upgrades,
config => (config.rebuyable
? new RebuyablePelleUpgradeState(config)
: new PelleUpgradeState(config)
)
);
PelleUpgrade.rebuyables = PelleUpgrade.all.filter(u => u.isRebuyable);
PelleUpgrade.singles = PelleUpgrade.all.filter(u => !u.isRebuyable);

View File

@ -170,11 +170,9 @@ class RiftState extends GameMechanicState {
}
}
export const PelleRifts = (function() {
return mapGameDataToObject(
GameDatabase.celestials.pelle.rifts,
config => new RiftState(config)
);
}());
export const PelleRifts = mapGameDataToObject(
GameDatabase.celestials.pelle.rifts,
config => new RiftState(config)
);
PelleRifts.totalMilestones = () => PelleRifts.all.flatMap(x => x.milestones).countWhere(x => x.canBeApplied);

View File

@ -56,9 +56,7 @@ class PelleStrikeState extends BitUpgradeState {
}
}
export const PelleStrikes = (function() {
return mapGameDataToObject(
GameDatabase.celestials.pelle.strikes,
config => new PelleStrikeState(config)
);
}());
export const PelleStrikes = mapGameDataToObject(
GameDatabase.celestials.pelle.strikes,
config => new PelleStrikeState(config)
);

View File

@ -224,44 +224,16 @@ class AlchemyReaction {
}
}
export const AlchemyResource = (function() {
function createResource(resource) {
const config = GameDatabase.celestials.alchemy.resources[resource];
config.id = resource;
if (config.isBaseResource) {
return new BasicAlchemyResourceState(config);
}
return new AdvancedAlchemyResourceState(config);
}
return {
power: createResource(ALCHEMY_RESOURCE.POWER),
infinity: createResource(ALCHEMY_RESOURCE.INFINITY),
time: createResource(ALCHEMY_RESOURCE.TIME),
replication: createResource(ALCHEMY_RESOURCE.REPLICATION),
dilation: createResource(ALCHEMY_RESOURCE.DILATION),
cardinality: createResource(ALCHEMY_RESOURCE.CARDINALITY),
eternity: createResource(ALCHEMY_RESOURCE.ETERNITY),
dimensionality: createResource(ALCHEMY_RESOURCE.DIMENSIONALITY),
inflation: createResource(ALCHEMY_RESOURCE.INFLATION),
alternation: createResource(ALCHEMY_RESOURCE.ALTERNATION),
effarig: createResource(ALCHEMY_RESOURCE.EFFARIG),
synergism: createResource(ALCHEMY_RESOURCE.SYNERGISM),
momentum: createResource(ALCHEMY_RESOURCE.MOMENTUM),
decoherence: createResource(ALCHEMY_RESOURCE.DECOHERENCE),
exponential: createResource(ALCHEMY_RESOURCE.EXPONENTIAL),
force: createResource(ALCHEMY_RESOURCE.FORCE),
uncountability: createResource(ALCHEMY_RESOURCE.UNCOUNTABILITY),
boundless: createResource(ALCHEMY_RESOURCE.BOUNDLESS),
multiversal: createResource(ALCHEMY_RESOURCE.MULTIVERSAL),
unpredictability: createResource(ALCHEMY_RESOURCE.UNPREDICTABILITY),
reality: createResource(ALCHEMY_RESOURCE.REALITY)
};
}());
export const AlchemyResource = mapGameDataToObject(
GameDatabase.celestials.alchemy.resources,
config => (config.isBaseResource
? new BasicAlchemyResourceState(config)
: new AdvancedAlchemyResourceState(config))
);
export const AlchemyResources = {
all: Object.values(AlchemyResource),
base: Object.values(AlchemyResource).filter(r => r.isBaseResource)
all: AlchemyResource.all,
base: AlchemyResource.all.filter(r => r.isBaseResource)
};
export const AlchemyReactions = (function() {
@ -269,7 +241,7 @@ export const AlchemyReactions = (function() {
function mapReagents(resource) {
return resource.config.reagents
.map(r => ({
resource: AlchemyResources.all[r.resource],
resource: AlchemyResources.all.find(x => x.id === r.resource),
cost: r.amount
}));
}

View File

@ -173,17 +173,10 @@ export const TeresaUnlocks = mapGameDataToObject(
config => new TeresaUnlockState(config)
);
export const PerkShopUpgrade = (function() {
const db = GameDatabase.celestials.perkShop;
return {
glyphLevel: new PerkShopUpgradeState(db.glyphLevel),
rmMult: new PerkShopUpgradeState(db.rmMult),
bulkDilation: new PerkShopUpgradeState(db.bulkDilation),
autoSpeed: new PerkShopUpgradeState(db.autoSpeed),
musicGlyph: new PerkShopUpgradeState(db.musicGlyph),
fillMusicGlyph: new PerkShopUpgradeState(db.fillMusicGlyph),
};
}());
export const PerkShopUpgrade = mapGameDataToObject(
GameDatabase.celestials.perkShop,
config => new PerkShopUpgradeState(config)
);
EventHub.logic.on(GAME_EVENT.TAB_CHANGED, () => {
if (Tab.celestials.teresa.isOpen) Teresa.quotes.show(Teresa.quotes.INITIAL);

View File

@ -94,16 +94,16 @@ dev.tripleEverything = function() {
};
dev.barrelRoll = function() {
FullScreenAnimationHandler.display("barrelRoll", 5);
FullScreenAnimationHandler.display("a-barrel-roll", 5);
};
dev.spin3d = function() {
if (document.body.style.animation === "") document.body.style.animation = "spin3d 3s infinite";
if (document.body.style.animation === "") document.body.style.animation = "a-spin3d 3s infinite";
else document.body.style.animation = "";
};
dev.spin4d = function() {
if (document.body.style.animation === "") document.body.style.animation = "spin4d 3s infinite";
if (document.body.style.animation === "") document.body.style.animation = "a-spin4d 3s infinite";
else document.body.style.animation = "";
};
@ -166,7 +166,7 @@ dev.resetDilation = function() {
// when making a special glyph, so no max-params
// eslint-disable-next-line max-params
dev.giveSpecialGlyph = function(color, symbol, level, rawLevel = level) {
if (!specialGlyphSymbols.hasOwnProperty(symbol)) return;
if (!Object.prototype.hasOwnProperty.call(specialGlyphSymbols, symbol)) return;
if (Glyphs.freeInventorySpace === 0) return;
const glyph = GlyphGenerator.randomGlyph({ actualLevel: level, rawLevel });
glyph.symbol = symbol;

View File

@ -4,12 +4,12 @@ import FullScreenAnimationHandler from "./full-screen-animation-handler";
import { SpeedrunMilestones } from "./speedrun";
export function animateAndDilate() {
FullScreenAnimationHandler.display("dilate", 2);
FullScreenAnimationHandler.display("a-dilate", 2);
setTimeout(startDilatedEternity, 1000);
}
export function animateAndUndilate() {
FullScreenAnimationHandler.display("undilate", 2);
FullScreenAnimationHandler.display("a-undilate", 2);
setTimeout(() => {
eternity(false, false, { switchingDilation: true });
}, 1000);
@ -222,26 +222,12 @@ class RebuyableDilationUpgradeState extends RebuyableMechanicState {
}
}
export const DilationUpgrade = (function() {
const db = GameDatabase.eternity.dilation;
return {
dtGain: new RebuyableDilationUpgradeState(db.dtGain),
galaxyThreshold: new RebuyableDilationUpgradeState(db.galaxyThreshold),
tachyonGain: new RebuyableDilationUpgradeState(db.tachyonGain),
doubleGalaxies: new DilationUpgradeState(db.doubleGalaxies),
tdMultReplicanti: new DilationUpgradeState(db.tdMultReplicanti),
ndMultDT: new DilationUpgradeState(db.ndMultDT),
ipMultDT: new DilationUpgradeState(db.ipMultDT),
timeStudySplit: new DilationUpgradeState(db.timeStudySplit),
dilationPenalty: new DilationUpgradeState(db.dilationPenalty),
ttGenerator: new DilationUpgradeState(db.ttGenerator),
dtGainPelle: new RebuyableDilationUpgradeState(db.dtGainPelle),
galaxyMultiplier: new RebuyableDilationUpgradeState(db.galaxyMultiplier),
tickspeedPower: new RebuyableDilationUpgradeState(db.tickspeedPower),
galaxyThresholdPelle: new DilationUpgradeState(db.galaxyThresholdPelle),
flatDilationMult: new DilationUpgradeState(db.flatDilationMult),
};
}());
export const DilationUpgrade = mapGameDataToObject(
GameDatabase.eternity.dilation,
config => (config.rebuyable
? new RebuyableDilationUpgradeState(config)
: new DilationUpgradeState(config))
);
export const DilationUpgrades = {
rebuyable: [
@ -249,11 +235,5 @@ export const DilationUpgrades = {
DilationUpgrade.galaxyThreshold,
DilationUpgrade.tachyonGain,
],
fromId: (function() {
const upgradesById = [];
for (const upgrade of Object.values(DilationUpgrade)) {
upgradesById[upgrade.id] = upgrade;
}
return id => upgradesById[id];
}()),
fromId: id => DilationUpgrade.all.find(x => x.id === id)
};

View File

@ -58,7 +58,7 @@ function giveEternityRewards(auto) {
}
export function eternityAnimation() {
FullScreenAnimationHandler.display("eternify", 3);
FullScreenAnimationHandler.display("a-eternify", 3);
}
export function eternityResetRequest() {
@ -87,7 +87,7 @@ export function eternity(force, auto, specialConditions = {}) {
initializeChallengeCompletions();
initializeResourcesAfterEternity();
if (!EternityMilestone.keepAutobuyers.isReached) {
if (!EternityMilestone.keepAutobuyers.isReached && !(Pelle.isDoomed && PelleUpgrade.keepAutobuyers.canBeApplied)) {
// Fix infinity because it can only break after big crunch autobuyer interval is maxed
player.break = false;
}
@ -194,44 +194,12 @@ export class EternityMilestoneState {
return Currency.eternities.gte(this.config.eternities);
}
}
export const EternityMilestone = (function() {
const db = GameDatabase.eternity.milestones;
const infinityDims = Array.dimensionTiers
.map(tier => new EternityMilestoneState(db[`autobuyerID${tier}`]));
return {
autobuyerIPMult: new EternityMilestoneState(db.autobuyerIPMult),
keepAutobuyers: new EternityMilestoneState(db.keepAutobuyers),
autobuyerReplicantiGalaxy: new EternityMilestoneState(db.autobuyerReplicantiGalaxy),
keepInfinityUpgrades: new EternityMilestoneState(db.keepInfinityUpgrades),
bigCrunchModes: new EternityMilestoneState(db.bigCrunchModes),
autoEP: new EternityMilestoneState(db.autoEP),
autoIC: new EternityMilestoneState(db.autoIC),
autobuyMaxGalaxies: new EternityMilestoneState(db.autobuyMaxGalaxies),
unlockReplicanti: new EternityMilestoneState(db.unlockReplicanti),
autobuyerID: tier => infinityDims[tier - 1],
keepBreakUpgrades: new EternityMilestoneState(db.keepBreakUpgrades),
autoUnlockID: new EternityMilestoneState(db.autoUnlockID),
unlockAllND: new EternityMilestoneState(db.unlockAllND),
replicantiNoReset: new EternityMilestoneState(db.replicantiNoReset),
autobuyerReplicantiChance: new EternityMilestoneState(db.autobuyerReplicantiChance),
autobuyerReplicantiInterval: new EternityMilestoneState(db.autobuyerReplicantiInterval),
autobuyerReplicantiMaxGalaxies: new EternityMilestoneState(db.autobuyerReplicantiMaxGalaxies),
autobuyerEternity: new EternityMilestoneState(db.autobuyerEternity),
autoEternities: new EternityMilestoneState(db.autoEternities),
autoInfinities: new EternityMilestoneState(db.autoInfinities),
};
}());
export const EternityMilestones = {
// This is a bit of a hack because autobuyerID is a function that returns EternityMilestoneState objects instead of a
// EternityMilestoneState object itself
all: Object.values(EternityMilestone)
.filter(m => typeof m !== "function")
.concat(Array.dimensionTiers
.map(tier => new EternityMilestoneState(GameDatabase.eternity.milestones[`autobuyerID${tier}`]))
)
};
export const EternityMilestone = mapGameDataToObject(
GameDatabase.eternity.milestones,
config => (config.isBaseResource
? new EternityMilestoneState(config)
: new EternityMilestoneState(config))
);
class EternityUpgradeState extends SetPurchasableMechanicState {
get currency() {
@ -319,16 +287,9 @@ class EPMultiplierState extends GameMechanicState {
}
}
export const EternityUpgrade = mapGameDataToObject(
GameDatabase.eternity.upgrades,
config => new EternityUpgradeState(config)
);
export const EternityUpgrade = (function() {
const db = GameDatabase.eternity.upgrades;
return {
idMultEP: new EternityUpgradeState(db.idMultEP),
idMultEternities: new EternityUpgradeState(db.idMultEternities),
idMultICRecords: new EternityUpgradeState(db.idMultICRecords),
tdMultAchs: new EternityUpgradeState(db.tdMultAchs),
tdMultTheorems: new EternityUpgradeState(db.tdMultTheorems),
tdMultRealTime: new EternityUpgradeState(db.tdMultRealTime),
epMult: new EPMultiplierState(),
};
}());
EternityUpgrade.epMult = new EPMultiplierState();

View File

@ -68,6 +68,8 @@ export * from "./time-studies/index";
export * from "./dimboost";
export * from "./sacrifice";
export * from "./big_crunch";
export * from "./infinity-upgrades";
export * from "./break-infinity-upgrades";
export * from "./challenge";
export * from "./eternity";
export * from "./eternity_challenge";

View File

@ -640,18 +640,10 @@ export const Glyphs = {
class GlyphSacrificeState extends GameMechanicState { }
export const GlyphSacrifice = (function() {
const db = GameDatabase.reality.glyphSacrifice;
return {
time: new GlyphSacrificeState(db.time),
dilation: new GlyphSacrificeState(db.dilation),
replication: new GlyphSacrificeState(db.replication),
infinity: new GlyphSacrificeState(db.infinity),
power: new GlyphSacrificeState(db.power),
effarig: new GlyphSacrificeState(db.effarig),
reality: new GlyphSacrificeState(db.reality),
};
}());
export const GlyphSacrifice = mapGameDataToObject(
GameDatabase.reality.glyphSacrifice,
config => new GlyphSacrificeState(config)
);
export function recalculateAllGlyphs() {
for (let i = 0; i < player.reality.glyphs.active.length; i++) {

View File

@ -0,0 +1,213 @@
import { GameMechanicState, SetPurchasableMechanicState } from "./game-mechanics/index";
import { DC } from "./constants";
class ChargedInfinityUpgradeState extends GameMechanicState {
constructor(config, upgrade) {
super(config);
this._upgrade = upgrade;
}
get isEffectActive() {
return this._upgrade.isBought && this._upgrade.isCharged;
}
}
export class InfinityUpgradeState extends SetPurchasableMechanicState {
constructor(config) {
super(config);
if (config.charged) {
this._chargedEffect = new ChargedInfinityUpgradeState(config.charged, this);
}
}
get currency() {
return Currency.infinityPoints;
}
get set() {
return player.infinityUpgrades;
}
get isAvailableForPurchase() {
return this.config.checkRequirement?.() ?? true;
}
get isEffectActive() {
return this.isBought && !this.isCharged;
}
get chargedEffect() {
return this._chargedEffect;
}
purchase() {
if (super.purchase()) {
// This applies the 4th column of infinity upgrades retroactively
if (this.config.id.includes("skip")) skipResetsIfPossible();
EventHub.dispatch(GAME_EVENT.INFINITY_UPGRADE_BOUGHT);
return true;
}
if (this.canCharge) {
this.charge();
return true;
}
return false;
}
get hasChargeEffect() {
return this.config.charged !== undefined;
}
get isCharged() {
return player.celestials.ra.charged.has(this.id);
}
get canCharge() {
return this.isBought &&
this.hasChargeEffect &&
!this.isCharged &&
Ra.chargesLeft !== 0 &&
!Pelle.isDisabled("chargedInfinityUpgrades");
}
charge() {
player.celestials.ra.charged.add(this.id);
}
disCharge() {
player.celestials.ra.charged.delete(this.id);
}
}
export function totalIPMult() {
if (Effarig.isRunning && Effarig.currentStage === EFFARIG_STAGES.INFINITY) {
return DC.D1;
}
let ipMult = DC.D1
.times(ShopPurchase.IPPurchases.currentMult)
.timesEffectsOf(
TimeStudy(41),
TimeStudy(51),
TimeStudy(141),
TimeStudy(142),
TimeStudy(143),
Achievement(85),
Achievement(93),
Achievement(116),
Achievement(125),
Achievement(141).effects.ipGain,
InfinityUpgrade.ipMult,
DilationUpgrade.ipMultDT,
GlyphEffect.ipMult
);
ipMult = ipMult.times(Replicanti.amount.powEffectOf(AlchemyResource.exponential));
return ipMult;
}
export function disChargeAll() {
const upgrades = [
InfinityUpgrade.totalTimeMult,
InfinityUpgrade.dim18mult,
InfinityUpgrade.dim36mult,
InfinityUpgrade.resetBoost,
InfinityUpgrade.buy10Mult,
InfinityUpgrade.dim27mult,
InfinityUpgrade.dim45mult,
InfinityUpgrade.galaxyBoost,
InfinityUpgrade.thisInfinityTimeMult,
InfinityUpgrade.unspentIPMult,
InfinityUpgrade.dimboostMult,
InfinityUpgrade.ipGen
];
for (const upgrade of upgrades) {
if (upgrade.isCharged) {
upgrade.disCharge();
}
}
player.celestials.ra.disCharge = false;
}
// The repeatable 2xIP upgrade has an odd cost structure - it follows a shallow exponential (step *10) up to e3M, at
// which point it follows a steeper one (step *1e10) up to e6M before finally hardcapping. At the hardcap, there's
// an extra bump that increases the multipler itself from e993k to e1M. All these numbers are specified in
// GameDatabase.infinity.upgrades.ipMult
class InfinityIPMultUpgrade extends GameMechanicState {
get cost() {
if (this.purchaseCount >= this.purchasesAtIncrease) {
return this.config.costIncreaseThreshold
.times(Decimal.pow(this.costIncrease, this.purchaseCount - this.purchasesAtIncrease));
}
return Decimal.pow(this.costIncrease, this.purchaseCount + 1);
}
get purchaseCount() {
return player.IPMultPurchases;
}
get purchasesAtIncrease() {
return this.config.costIncreaseThreshold.log10() - 1;
}
get hasIncreasedCost() {
return this.purchaseCount >= this.purchasesAtIncrease;
}
get costIncrease() {
return this.hasIncreasedCost ? 1e10 : 10;
}
get isCapped() {
return this.cost.gte(this.config.costCap);
}
get isBought() {
return this.isCapped;
}
get isRequirementSatisfied() {
return Achievement(41).isUnlocked;
}
get canBeBought() {
return !Pelle.isDoomed && !this.isCapped && Currency.infinityPoints.gte(this.cost) && this.isRequirementSatisfied;
}
// This is only ever called with amount = 1 or within buyMax under conditions that ensure the scaling doesn't
// change mid-purchase
purchase(amount = 1) {
if (!this.canBeBought) return;
if (!TimeStudy(181).isBought) {
Autobuyer.bigCrunch.bumpAmount(DC.D2.pow(amount));
}
Currency.infinityPoints.subtract(Decimal.sumGeometricSeries(amount, this.cost, this.costIncrease, 0));
player.IPMultPurchases += amount;
GameUI.update();
}
buyMax() {
if (!this.canBeBought) return;
if (!this.hasIncreasedCost) {
// Only allow IP below the softcap to be used
const availableIP = Currency.infinityPoints.value.clampMax(this.config.costIncreaseThreshold);
const purchases = Decimal.affordGeometricSeries(availableIP, this.cost, this.costIncrease, 0).toNumber();
if (purchases <= 0) return;
this.purchase(purchases);
}
// Do not replace it with `if else` - it's specifically designed to process two sides of threshold separately
// (for example, we have 1e4000000 IP and no mult - first it will go to (but not including) 1e3000000 and then
// it will go in this part)
if (this.hasIncreasedCost) {
const availableIP = Currency.infinityPoints.value.clampMax(this.config.costCap);
const purchases = Decimal.affordGeometricSeries(availableIP, this.cost, this.costIncrease, 0).toNumber();
if (purchases <= 0) return;
this.purchase(purchases);
}
}
}
export const InfinityUpgrade = mapGameDataToObject(
GameDatabase.infinity.upgrades,
config => (config.id === "ipMult"
? new InfinityIPMultUpgrade(config)
: new InfinityUpgradeState(config))
);

View File

@ -30,7 +30,10 @@ export const GameIntervals = (function() {
// Not a getter because getter will cause stack overflow
all() {
return Object.values(GameIntervals)
.filter(i => i.hasOwnProperty("start") && i.hasOwnProperty("stop"));
.filter(i =>
Object.prototype.hasOwnProperty.call(i, "start") &&
Object.prototype.hasOwnProperty.call(i, "stop")
);
},
start() {
// eslint-disable-next-line no-shadow

View File

@ -60,17 +60,10 @@ class ShopPurchaseState extends RebuyableMechanicState {
}
}
export const ShopPurchase = (function() {
const db = GameDatabase.shopPurchases;
return {
dimPurchases: new ShopPurchaseState(db.dimPurchases),
IPPurchases: new ShopPurchaseState(db.IPPurchases),
EPPurchases: new ShopPurchaseState(db.EPPurchases),
allDimPurchases: new ShopPurchaseState(db.allDimPurchases)
};
}());
ShopPurchase.all = Object.values(ShopPurchase);
export const ShopPurchase = mapGameDataToObject(
GameDatabase.shopPurchases,
config => new ShopPurchaseState(config)
);
kong.purchaseTimeSkip = function(cost) {
if (player.IAP.totalSTD - player.IAP.spentSTD < cost) return;

View File

@ -49,7 +49,7 @@ export const PerformanceStats = {
function render(rootBlock) {
indentLevel++;
for (const blockName in rootBlock) {
if (!rootBlock.hasOwnProperty(blockName)) continue;
if (!Object.prototype.hasOwnProperty.call(rootBlock, blockName)) continue;
const block = rootBlock[blockName];
const records = block.records;
while (records.length > 1 && records.last().timestamp - records.first().timestamp > samplePeriod) {

View File

@ -49,61 +49,13 @@ class PerkState extends SetPurchasableMechanicState {
}
}
export const Perk = (function() {
const db = GameDatabase.reality.perks;
return {
firstPerk: new PerkState(db.firstPerk),
startAM: new PerkState(db.startAM),
startIP1: new PerkState(db.startIP1),
startIP2: new PerkState(db.startIP2),
startEP1: new PerkState(db.startEP1),
startEP2: new PerkState(db.startEP2),
startEP3: new PerkState(db.startEP3),
startTP: new PerkState(db.startTP),
antimatterNoReset: new PerkState(db.antimatterNoReset),
studyPassive: new PerkState(db.studyPassive),
autounlockEU1: new PerkState(db.autounlockEU1),
autounlockEU2: new PerkState(db.autounlockEU2),
autounlockDilation1: new PerkState(db.autounlockDilation1),
autounlockDilation2: new PerkState(db.autounlockDilation2),
autounlockDilation3: new PerkState(db.autounlockDilation3),
autounlockTD: new PerkState(db.autounlockTD),
autounlockReality: new PerkState(db.autounlockReality),
bypassIDAntimatter: new PerkState(db.bypassIDAntimatter),
bypassTGReset: new PerkState(db.bypassTGReset),
bypassECDilation: new PerkState(db.bypassECDilation),
bypassEC1Lock: new PerkState(db.bypassEC1Lock),
bypassEC2Lock: new PerkState(db.bypassEC2Lock),
bypassEC3Lock: new PerkState(db.bypassEC3Lock),
bypassEC5Lock: new PerkState(db.bypassEC5Lock),
autocompleteEC1: new PerkState(db.autocompleteEC1),
autocompleteEC2: new PerkState(db.autocompleteEC2),
autocompleteEC3: new PerkState(db.autocompleteEC3),
studyActiveEP: new PerkState(db.studyActiveEP),
studyIdleEP: new PerkState(db.studyIdleEP),
studyECRequirement: new PerkState(db.studyECRequirement),
studyECBulk: new PerkState(db.studyECBulk),
retroactiveTP1: new PerkState(db.retroactiveTP1),
retroactiveTP2: new PerkState(db.retroactiveTP2),
retroactiveTP3: new PerkState(db.retroactiveTP3),
retroactiveTP4: new PerkState(db.retroactiveTP4),
autobuyerDilation: new PerkState(db.autobuyerDilation),
autobuyerFasterID: new PerkState(db.autobuyerFasterID),
autobuyerFasterReplicanti: new PerkState(db.autobuyerFasterReplicanti),
autobuyerFasterDilation: new PerkState(db.autobuyerFasterDilation),
ttFree: new PerkState(db.ttFree),
ttBuySingle: new PerkState(db.ttBuySingle),
ttBuyMax: new PerkState(db.ttBuyMax),
achievementGroup1: new PerkState(db.achievementGroup1),
achievementGroup2: new PerkState(db.achievementGroup2),
achievementGroup3: new PerkState(db.achievementGroup3),
achievementGroup4: new PerkState(db.achievementGroup4),
achievementGroup5: new PerkState(db.achievementGroup5)
};
}());
export const Perk = mapGameDataToObject(
GameDatabase.reality.perks,
config => new PerkState(config)
);
export const Perks = {
all: Object.values(Perk),
all: Perk.all,
/**
* @param {number} id
* @returns {PerkState}

View File

@ -811,7 +811,8 @@ window.player = {
bigCrunch: true,
replicantiGalaxy: true,
antimatterGalaxy: true,
dimensionBoost: true
dimensionBoost: true,
switchAutomatorMode: true
},
awayProgress: {
antimatter: true,
@ -984,7 +985,7 @@ export function guardFromNaNValues(obj) {
}
for (const key in obj) {
if (!obj.hasOwnProperty(key)) continue;
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
// TODO: rework autobuyer saving
if (key === "automator") continue;

View File

@ -180,8 +180,8 @@ function triggerManualReality(realityProps) {
export function runRealityAnimation() {
document.getElementById("ui").style.userSelect = "none";
document.getElementById("ui").style.animation = "realize 10s 1";
document.getElementById("realityanimbg").style.animation = "realizebg 10s 1";
document.getElementById("ui").style.animation = "a-realize 10s 1";
document.getElementById("realityanimbg").style.animation = "a-realizebg 10s 1";
document.getElementById("realityanimbg").style.display = "block";
setTimeout(() => {
document.getElementById("realityanimbg").play();

View File

@ -702,7 +702,7 @@ GameDatabase.achievements.normal = [
id: 102,
name: "This mile took an eternity",
description: "Get all Eternity milestones.",
checkRequirement: () => EternityMilestones.all.every(m => m.isReached),
checkRequirement: () => EternityMilestone.all.every(m => m.isReached),
checkEvent: GAME_EVENT.GAME_TICK_AFTER
},
{

View File

@ -1,443 +1,462 @@
import { DC } from "../../constants";
import { GameDatabase } from "../game-database";
GameDatabase.celestials.alchemy = {
resources: {
// T1 resources (Non-Effarig "base" resources)
[ALCHEMY_RESOURCE.POWER]: {
name: "Power",
symbol: "Ω",
isBaseResource: true,
effect: amount => 1 + amount / 200000,
tier: 1,
uiOrder: 1,
unlockedAt: 2,
description: "provides a multiplier to Antimatter Dimensions",
formatEffect: value => `Antimatter Dimension multipliers ${formatPow(value, 4, 4)}`
},
[ALCHEMY_RESOURCE.INFINITY]: {
name: "Infinity",
symbol: "∞",
isBaseResource: true,
effect: amount => 1 + amount / 200000,
tier: 1,
uiOrder: 2,
unlockedAt: 3,
description: "provides a multiplier to Infinity Dimensions",
formatEffect: value => `Infinity Dimension multipliers ${formatPow(value, 4, 4)}`
},
[ALCHEMY_RESOURCE.TIME]: {
name: "Time",
symbol: "Δ",
isBaseResource: true,
effect: amount => 1 + amount / 200000,
tier: 1,
uiOrder: 3,
unlockedAt: 4,
description: "provides a multiplier to Time Dimensions",
formatEffect: value => `Time Dimension multipliers ${formatPow(value, 4, 4)}`
},
[ALCHEMY_RESOURCE.REPLICATION]: {
name: "Replication",
symbol: "Ξ",
isBaseResource: true,
effect: amount => Decimal.pow10(amount / 1000),
tier: 1,
uiOrder: 4,
unlockedAt: 5,
description: `increases Replication Speed`,
formatEffect: value => `Replication speed is increased by ${formatX(value, 2, 2)}`
},
[ALCHEMY_RESOURCE.DILATION]: {
name: "Dilation",
symbol: "Ψ",
isBaseResource: true,
effect: amount => Decimal.pow10(amount / 2000),
tier: 1,
uiOrder: 5,
unlockedAt: 6,
description: "increases Dilated Time production",
formatEffect: value => `Dilated Time production is increased by ${formatX(value, 2, 2)}`
},
GameDatabase.celestials.alchemy.resources = {
// T1 resources (Non-Effarig "base" resources)
"power": {
id: ALCHEMY_RESOURCE.POWER,
name: "Power",
symbol: "Ω",
isBaseResource: true,
effect: amount => 1 + amount / 200000,
tier: 1,
uiOrder: 1,
unlockedAt: 2,
description: "provides a multiplier to Antimatter Dimensions",
formatEffect: value => `Antimatter Dimension multipliers ${formatPow(value, 4, 4)}`
},
"infinity": {
id: ALCHEMY_RESOURCE.INFINITY,
name: "Infinity",
symbol: "∞",
isBaseResource: true,
effect: amount => 1 + amount / 200000,
tier: 1,
uiOrder: 2,
unlockedAt: 3,
description: "provides a multiplier to Infinity Dimensions",
formatEffect: value => `Infinity Dimension multipliers ${formatPow(value, 4, 4)}`
},
"time": {
id: ALCHEMY_RESOURCE.TIME,
name: "Time",
symbol: "Δ",
isBaseResource: true,
effect: amount => 1 + amount / 200000,
tier: 1,
uiOrder: 3,
unlockedAt: 4,
description: "provides a multiplier to Time Dimensions",
formatEffect: value => `Time Dimension multipliers ${formatPow(value, 4, 4)}`
},
"replication": {
id: ALCHEMY_RESOURCE.REPLICATION,
name: "Replication",
symbol: "Ξ",
isBaseResource: true,
effect: amount => Decimal.pow10(amount / 1000),
tier: 1,
uiOrder: 4,
unlockedAt: 5,
description: `increases Replication Speed`,
formatEffect: value => `Replication speed is increased by ${formatX(value, 2, 2)}`
},
"dilation": {
id: ALCHEMY_RESOURCE.DILATION,
name: "Dilation",
symbol: "Ψ",
isBaseResource: true,
effect: amount => Decimal.pow10(amount / 2000),
tier: 1,
uiOrder: 5,
unlockedAt: 6,
description: "increases Dilated Time production",
formatEffect: value => `Dilated Time production is increased by ${formatX(value, 2, 2)}`
},
// T2 resources (combinations of pairs of T1 resources)
[ALCHEMY_RESOURCE.CARDINALITY]: {
name: "Cardinality",
symbol: "α",
isBaseResource: false,
effect: amount => 1 + 0.2 / (1 + amount / 20000),
tier: 2,
uiOrder: 3,
unlockedAt: 8,
get description() { return `reduces the slowdown per ${format(Number.MAX_VALUE, 2)} Replicanti`; },
formatEffect: value => `Replicanti interval increases slower ${formatX(1.2, 1, 1)}` +
`${formatX(value, 4, 4)} per ${format(Number.MAX_VALUE, 2)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.TIME,
amount: 8
},
{
resource: ALCHEMY_RESOURCE.REPLICATION,
amount: 7
}
]
},
[ALCHEMY_RESOURCE.ETERNITY]: {
name: "Eternity",
symbol: "τ",
isBaseResource: false,
effect: amount => 1 + amount / 15000,
tier: 2,
uiOrder: 2,
unlockedAt: 9,
description: "increases Eternity generation",
formatEffect: value => `Eternity generation ${formatPow(value, 4, 4)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.TIME,
amount: 11
},
{
resource: ALCHEMY_RESOURCE.INFINITY,
amount: 4
}
]
},
[ALCHEMY_RESOURCE.DIMENSIONALITY]: {
name: "Dimensionality",
symbol: "ρ",
isBaseResource: false,
effect: amount => Decimal.pow10(5 * amount),
tier: 2,
uiOrder: 1,
unlockedAt: 10,
description: "provides a multiplier to all dimensions",
formatEffect: value => `All Dimensions ${formatX(value)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.POWER,
amount: 10
},
{
resource: ALCHEMY_RESOURCE.INFINITY,
amount: 5
}
]
},
[ALCHEMY_RESOURCE.INFLATION]: {
name: "Inflation",
symbol: "λ",
isBaseResource: false,
effect: amount => Decimal.pow10(6e9 - 3e5 * amount),
tier: 2,
uiOrder: 5,
unlockedAt: 11,
description: "increases multiplier effect over a threshold",
formatEffect: value => `All Antimatter Dimension multipliers are ${formatPow(1.05, 2, 2)}
if they are above ${format(value)} `,
reagents: [
{
resource: ALCHEMY_RESOURCE.POWER,
amount: 9
},
{
resource: ALCHEMY_RESOURCE.DILATION,
amount: 6
}
]
},
[ALCHEMY_RESOURCE.ALTERNATION]: {
name: "Alternation",
symbol: "ω",
isBaseResource: false,
effect: amount => amount / 200000,
tier: 2,
uiOrder: 4,
unlockedAt: 12,
description: "increases the strength of Tachyon Galaxies based on Replicanti",
formatEffect: value => `Tachyon Galaxies are ${formatPercents(value, 2, 2)} stronger ` +
`per ${format(DC.E1E6)} Replicanti`,
reagents: [
{
resource: ALCHEMY_RESOURCE.REPLICATION,
amount: 5
},
{
resource: ALCHEMY_RESOURCE.DILATION,
amount: 10
}
]
},
// T3 resources (Effarig and conbinations of T1/T2 with Effarig)
[ALCHEMY_RESOURCE.EFFARIG]: {
name: "Effarig",
symbol: "Ϙ",
isBaseResource: true,
effect: amount => Math.pow(10, amount / 2500),
tier: 2,
uiOrder: 3.5,
unlockedAt: 7,
description: "increases Relic Shard gain",
formatEffect: value => `Relic Shard gain is multiplied ${formatX(value, 2, 2)}`
},
[ALCHEMY_RESOURCE.SYNERGISM]: {
name: "Synergism",
symbol: "π",
isBaseResource: false,
effect: amount => Math.clampMax(0.3 + Math.sqrt(amount / 15000), 1),
tier: 3,
uiOrder: 2,
unlockedAt: 13,
description: "increases the effectiveness of Alchemy Reactions",
formatEffect(value) {
const baseEffect = `Alchemy reaction efficiency ${formatPercents(0.3)}${formatPercents(value, 2, 2)}`;
if (player.reality.glyphs.sac.reality === 0) {
return baseEffect;
}
const increasedYield = formatPercents(value * Effects.sum(GlyphSacrifice.reality), 2, 2);
return `${baseEffect} (${increasedYield} after Glyph Sacrifice)`;
// T2 resources (combinations of pairs of T1 resources)
"cardinality": {
id: ALCHEMY_RESOURCE.CARDINALITY,
name: "Cardinality",
symbol: "α",
isBaseResource: false,
effect: amount => 1 + 0.2 / (1 + amount / 20000),
tier: 2,
uiOrder: 3,
unlockedAt: 8,
get description() { return `reduces the slowdown per ${format(Number.MAX_VALUE, 2)} Replicanti`; },
formatEffect: value => `Replicanti interval increases slower ${formatX(1.2, 1, 1)}
${formatX(value, 4, 4)} per ${format(Number.MAX_VALUE, 2)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.TIME,
amount: 8
},
reagents: [
{
resource: ALCHEMY_RESOURCE.EFFARIG,
amount: 3
},
{
resource: ALCHEMY_RESOURCE.REPLICATION,
amount: 16
},
{
resource: ALCHEMY_RESOURCE.INFINITY,
amount: 14
}
]
},
[ALCHEMY_RESOURCE.MOMENTUM]: {
name: "Momentum",
symbol: "μ",
isBaseResource: false,
effect: amount => 1 + amount / 125000,
tier: 3,
uiOrder: 3,
unlockedAt: 15,
description: "provides a multiplier to all dimensions based on real time since unlock",
formatEffect: value => `All Dimensions ${formatPow(Ra.momentumValue, 4, 4)}, increasing by
${format(0.002 * Achievement(175).effectOrDefault(1), 3, 3)}
per real-time hour after the resource is unlocked, up to a maximum of ${formatPow(value, 4, 4)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.EFFARIG,
amount: 11
},
{
resource: ALCHEMY_RESOURCE.POWER,
amount: 4
},
{
resource: ALCHEMY_RESOURCE.TIME,
amount: 20
}
]
},
[ALCHEMY_RESOURCE.DECOHERENCE]: {
name: "Decoherence",
symbol: "ξ",
isBaseResource: false,
effect: amount => 0.10 * Math.sqrt(amount / 10000),
tier: 3,
uiOrder: 4,
unlockedAt: 14,
description: "causes refining to give all basic Alchemy Resources",
formatEffect: value => `Refined Glyphs also give ${formatPercents(value, 2)} of their value ` +
"to all other base resources",
reagents: [
{
resource: ALCHEMY_RESOURCE.EFFARIG,
amount: 13
},
{
resource: ALCHEMY_RESOURCE.ALTERNATION,
amount: 8
}
]
},
{
resource: ALCHEMY_RESOURCE.REPLICATION,
amount: 7
}
]
},
"eternity": {
id: ALCHEMY_RESOURCE.ETERNITY,
name: "Eternity",
symbol: "τ",
isBaseResource: false,
effect: amount => 1 + amount / 15000,
tier: 2,
uiOrder: 2,
unlockedAt: 9,
description: "increases Eternity generation",
formatEffect: value => `Eternity generation ${formatPow(value, 4, 4)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.TIME,
amount: 11
},
{
resource: ALCHEMY_RESOURCE.INFINITY,
amount: 4
}
]
},
"dimensionality": {
id: ALCHEMY_RESOURCE.DIMENSIONALITY,
name: "Dimensionality",
symbol: "ρ",
isBaseResource: false,
effect: amount => Decimal.pow10(5 * amount),
tier: 2,
uiOrder: 1,
unlockedAt: 10,
description: "provides a multiplier to all dimensions",
formatEffect: value => `All Dimensions ${formatX(value)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.POWER,
amount: 10
},
{
resource: ALCHEMY_RESOURCE.INFINITY,
amount: 5
}
]
},
"inflation": {
id: ALCHEMY_RESOURCE.INFLATION,
name: "Inflation",
symbol: "λ",
isBaseResource: false,
effect: amount => Decimal.pow10(6e9 - 3e5 * amount),
tier: 2,
uiOrder: 5,
unlockedAt: 11,
description: "increases multiplier effect over a threshold",
formatEffect: value => `All Antimatter Dimension multipliers are ${formatPow(1.05, 2, 2)}
if they are above ${format(value)} `,
reagents: [
{
resource: ALCHEMY_RESOURCE.POWER,
amount: 9
},
{
resource: ALCHEMY_RESOURCE.DILATION,
amount: 6
}
]
},
"alternation": {
id: ALCHEMY_RESOURCE.ALTERNATION,
name: "Alternation",
symbol: "ω",
isBaseResource: false,
effect: amount => amount / 200000,
tier: 2,
uiOrder: 4,
unlockedAt: 12,
description: "increases the strength of Tachyon Galaxies based on Replicanti",
formatEffect: value => `Tachyon Galaxies are ${formatPercents(value, 2, 2)} stronger
per ${format(DC.E1E6)} Replicanti`,
reagents: [
{
resource: ALCHEMY_RESOURCE.REPLICATION,
amount: 5
},
{
resource: ALCHEMY_RESOURCE.DILATION,
amount: 10
}
]
},
// T4 resources (resources which feed directly into the final resource)
[ALCHEMY_RESOURCE.EXPONENTIAL]: {
name: "Exponential",
symbol: "Γ",
isBaseResource: false,
effect: amount => 10 * Math.pow(amount / 10000, 2),
tier: 4,
uiOrder: 2,
unlockedAt: 18,
description: "multiplies Infinity Points by Replicanti",
formatEffect: value => `Infinity Points multiplied by Replicanti${formatPow(value, 2, 3)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.INFLATION,
amount: 18
},
{
resource: ALCHEMY_RESOURCE.SYNERGISM,
amount: 3
}
]
},
[ALCHEMY_RESOURCE.FORCE]: {
name: "Force",
symbol: "Φ",
isBaseResource: false,
effect: amount => 5 * amount,
tier: 4,
uiOrder: 2,
unlockedAt: 17,
description: "multiplies Antimatter Dimensions by Reality Machines",
formatEffect: value => `Multiply Antimatter Dimensions by Reality Machines${formatPow(value, 2, 2)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.DIMENSIONALITY,
amount: 7
},
{
resource: ALCHEMY_RESOURCE.MOMENTUM,
amount: 8
}
]
},
[ALCHEMY_RESOURCE.UNCOUNTABILITY]: {
name: "Uncountability",
symbol: "Θ",
isBaseResource: false,
effect: amount => Math.sqrt(amount),
tier: 4,
uiOrder: 3,
unlockedAt: 19,
description: "passively generates Realities and Perk Points",
formatEffect: value => `Generate ${format(value, 2, 2)} Realities and Perk Points per second`,
reagents: [
{
resource: ALCHEMY_RESOURCE.INFINITY,
amount: 20
},
{
resource: ALCHEMY_RESOURCE.EFFARIG,
amount: 6
},
{
resource: ALCHEMY_RESOURCE.CARDINALITY,
amount: 16
}
]
},
[ALCHEMY_RESOURCE.BOUNDLESS]: {
name: "Boundless",
symbol: "Π",
isBaseResource: false,
effect: amount => amount / 80000,
tier: 4,
uiOrder: 1,
unlockedAt: 20,
description: "makes Tesseracts stronger",
formatEffect: value => `Tesseracts are +${formatPercents(value, 2, 2)} stronger`,
reagents: [
{
resource: ALCHEMY_RESOURCE.ETERNITY,
amount: 13
},
{
resource: ALCHEMY_RESOURCE.INFLATION,
amount: 18
}
]
},
[ALCHEMY_RESOURCE.MULTIVERSAL]: {
name: "Multiversal",
symbol: "Σ",
isBaseResource: false,
effect: amount => 5 * Math.pow(amount / 10000, 2),
tier: 4,
uiOrder: 5,
unlockedAt: 16,
description: "makes each Reality simulate more Realities",
formatEffect: value => `Each Reality simulates ${format(value, 2, 3)} additional Realities, giving all
the same rewards as if it was amplified`,
reagents: [
{
resource: ALCHEMY_RESOURCE.ALTERNATION,
amount: 16
},
{
resource: ALCHEMY_RESOURCE.DECOHERENCE,
amount: 3
}
]
},
[ALCHEMY_RESOURCE.UNPREDICTABILITY]: {
name: "Unpredictability",
symbol: "Λ",
isBaseResource: false,
effect: amount => amount / (10000 + amount),
tier: 4,
uiOrder: 4,
unlockedAt: 21,
description: "makes each Alchemy Reaction have a chance to happen twice",
formatEffect: value => `Any alchemy reaction has a ${formatPercents(value, 2, 2)}
chance of triggering again`,
reagents: [
{
resource: ALCHEMY_RESOURCE.EFFARIG,
amount: 15
},
{
resource: ALCHEMY_RESOURCE.DECOHERENCE,
amount: 3
},
{
resource: ALCHEMY_RESOURCE.SYNERGISM,
amount: 10
}
]
// T3 resources (Effarig and conbinations of T1/T2 with Effarig)
"effarig": {
id: ALCHEMY_RESOURCE.EFFARIG,
name: "Effarig",
symbol: "Ϙ",
isBaseResource: true,
effect: amount => Math.pow(10, amount / 2500),
tier: 2,
uiOrder: 3.5,
unlockedAt: 7,
description: "increases Relic Shard gain",
formatEffect: value => `Relic Shard gain is multiplied ${formatX(value, 2, 2)}`
},
"synergism": {
id: ALCHEMY_RESOURCE.SYNERGISM,
name: "Synergism",
symbol: "π",
isBaseResource: false,
effect: amount => Math.clampMax(0.3 + Math.sqrt(amount / 15000), 1),
tier: 3,
uiOrder: 2,
unlockedAt: 13,
description: "increases the effectiveness of Alchemy Reactions",
formatEffect(value) {
const baseEffect = `Alchemy reaction efficiency ${formatPercents(0.3)}${formatPercents(value, 2, 2)}`;
if (player.reality.glyphs.sac.reality === 0) {
return baseEffect;
}
const increasedYield = formatPercents(value * Effects.sum(GlyphSacrifice.reality), 2, 2);
return `${baseEffect} (${increasedYield} after Glyph Sacrifice)`;
},
reagents: [
{
resource: ALCHEMY_RESOURCE.EFFARIG,
amount: 3
},
{
resource: ALCHEMY_RESOURCE.REPLICATION,
amount: 16
},
{
resource: ALCHEMY_RESOURCE.INFINITY,
amount: 14
}
]
},
"momentum": {
id: ALCHEMY_RESOURCE.MOMENTUM,
name: "Momentum",
symbol: "μ",
isBaseResource: false,
effect: amount => 1 + amount / 125000,
tier: 3,
uiOrder: 3,
unlockedAt: 15,
description: "provides a multiplier to all dimensions based on real time since unlock",
formatEffect: value => `All Dimensions ${formatPow(Ra.momentumValue, 4, 4)}, increasing by
${format(0.002 * Achievement(175).effectOrDefault(1), 3, 3)}
per real-time hour after the resource is unlocked, up to a maximum of ${formatPow(value, 4, 4)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.EFFARIG,
amount: 11
},
{
resource: ALCHEMY_RESOURCE.POWER,
amount: 4
},
{
resource: ALCHEMY_RESOURCE.TIME,
amount: 20
}
]
},
"decoherence": {
id: ALCHEMY_RESOURCE.DECOHERENCE,
name: "Decoherence",
symbol: "ξ",
isBaseResource: false,
effect: amount => 0.10 * Math.sqrt(amount / 10000),
tier: 3,
uiOrder: 4,
unlockedAt: 14,
description: "causes refining to give all basic Alchemy Resources",
formatEffect: value => `Refined Glyphs also give ${formatPercents(value, 2)} of their value ` +
"to all other base resources",
reagents: [
{
resource: ALCHEMY_RESOURCE.EFFARIG,
amount: 13
},
{
resource: ALCHEMY_RESOURCE.ALTERNATION,
amount: 8
}
]
},
// T5 (Reality)
[ALCHEMY_RESOURCE.REALITY]: {
name: "Reality",
symbol: "Ϟ",
isBaseResource: false,
effect: amount => Math.floor(amount),
tier: 5,
unlockedAt: 25,
description: "allows creation of Reality Glyphs",
formatEffect: value => `Consume all Reality resource to create a level ${formatInt(value)} Reality Glyph`,
reagents: [
{
resource: ALCHEMY_RESOURCE.EXPONENTIAL,
amount: 1
},
{
resource: ALCHEMY_RESOURCE.FORCE,
amount: 1
},
{
resource: ALCHEMY_RESOURCE.UNCOUNTABILITY,
amount: 1
},
{
resource: ALCHEMY_RESOURCE.BOUNDLESS,
amount: 1
},
{
resource: ALCHEMY_RESOURCE.MULTIVERSAL,
amount: 1
},
{
resource: ALCHEMY_RESOURCE.UNPREDICTABILITY,
amount: 1
}
]
},
// T4 resources (resources which feed directly into the final resource)
"exponential": {
id: ALCHEMY_RESOURCE.EXPONENTIAL,
name: "Exponential",
symbol: "Γ",
isBaseResource: false,
effect: amount => 10 * Math.pow(amount / 10000, 2),
tier: 4,
uiOrder: 2,
unlockedAt: 18,
description: "multiplies Infinity Points by Replicanti",
formatEffect: value => `Infinity Points multiplied by Replicanti${formatPow(value, 2, 3)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.INFLATION,
amount: 18
},
{
resource: ALCHEMY_RESOURCE.SYNERGISM,
amount: 3
}
]
},
"force": {
id: ALCHEMY_RESOURCE.FORCE,
name: "Force",
symbol: "Φ",
isBaseResource: false,
effect: amount => 5 * amount,
tier: 4,
uiOrder: 2,
unlockedAt: 17,
description: "multiplies Antimatter Dimensions by Reality Machines",
formatEffect: value => `Multiply Antimatter Dimensions by Reality Machines${formatPow(value, 2, 2)}`,
reagents: [
{
resource: ALCHEMY_RESOURCE.DIMENSIONALITY,
amount: 7
},
{
resource: ALCHEMY_RESOURCE.MOMENTUM,
amount: 8
}
]
},
"uncountability": {
id: ALCHEMY_RESOURCE.UNCOUNTABILITY,
name: "Uncountability",
symbol: "Θ",
isBaseResource: false,
effect: amount => Math.sqrt(amount),
tier: 4,
uiOrder: 3,
unlockedAt: 19,
description: "passively generates Realities and Perk Points",
formatEffect: value => `Generate ${format(value, 2, 2)} Realities and Perk Points per second`,
reagents: [
{
resource: ALCHEMY_RESOURCE.INFINITY,
amount: 20
},
{
resource: ALCHEMY_RESOURCE.EFFARIG,
amount: 6
},
{
resource: ALCHEMY_RESOURCE.CARDINALITY,
amount: 16
}
]
},
"boundless": {
id: ALCHEMY_RESOURCE.BOUNDLESS,
name: "Boundless",
symbol: "Π",
isBaseResource: false,
effect: amount => amount / 80000,
tier: 4,
uiOrder: 1,
unlockedAt: 20,
description: "makes Tesseracts stronger",
formatEffect: value => `Tesseracts are +${formatPercents(value, 2, 2)} stronger`,
reagents: [
{
resource: ALCHEMY_RESOURCE.ETERNITY,
amount: 13
},
{
resource: ALCHEMY_RESOURCE.INFLATION,
amount: 18
}
]
},
"multiversal": {
id: ALCHEMY_RESOURCE.MULTIVERSAL,
name: "Multiversal",
symbol: "Σ",
isBaseResource: false,
effect: amount => 5 * Math.pow(amount / 10000, 2),
tier: 4,
uiOrder: 5,
unlockedAt: 16,
description: "makes each Reality simulate more Realities",
formatEffect: value => `Each Reality simulates ${format(value, 2, 3)} additional Realities, giving all
the same rewards as if it was amplified`,
reagents: [
{
resource: ALCHEMY_RESOURCE.ALTERNATION,
amount: 16
},
{
resource: ALCHEMY_RESOURCE.DECOHERENCE,
amount: 3
}
]
},
"unpredictability": {
id: ALCHEMY_RESOURCE.UNPREDICTABILITY,
name: "Unpredictability",
symbol: "Λ",
isBaseResource: false,
effect: amount => amount / (10000 + amount),
tier: 4,
uiOrder: 4,
unlockedAt: 21,
description: "makes each Alchemy Reaction have a chance to happen twice",
formatEffect: value => `Any alchemy reaction has a ${formatPercents(value, 2, 2)}
chance of triggering again`,
reagents: [
{
resource: ALCHEMY_RESOURCE.EFFARIG,
amount: 15
},
{
resource: ALCHEMY_RESOURCE.DECOHERENCE,
amount: 3
},
{
resource: ALCHEMY_RESOURCE.SYNERGISM,
amount: 10
}
]
},
// T5 (Reality)
"reality": {
id: ALCHEMY_RESOURCE.REALITY,
name: "Reality",
symbol: "Ϟ",
isBaseResource: false,
effect: amount => Math.floor(amount),
tier: 5,
unlockedAt: 25,
description: "allows creation of Reality Glyphs",
formatEffect: value => `Consume all Reality resource to create a level ${formatInt(value)} Reality Glyph`,
reagents: [
{
resource: ALCHEMY_RESOURCE.EXPONENTIAL,
amount: 1
},
{
resource: ALCHEMY_RESOURCE.FORCE,
amount: 1
},
{
resource: ALCHEMY_RESOURCE.UNCOUNTABILITY,
amount: 1
},
{
resource: ALCHEMY_RESOURCE.BOUNDLESS,
amount: 1
},
{
resource: ALCHEMY_RESOURCE.MULTIVERSAL,
amount: 1
},
{
resource: ALCHEMY_RESOURCE.UNPREDICTABILITY,
amount: 1
}
]
},
};

View File

@ -1,56 +1,70 @@
import { DC } from "../../constants";
import { GameDatabase } from "../game-database";
GameDatabase.celestials.effarig = {
unlocks: {
adjuster: {
id: 0,
description: "Adjustable Glyph level factor weights",
cost: 1e7
},
glyphFilter: {
id: 1,
description: "Glyph Filtering",
cost: 2e8
},
setSaves: {
id: 2,
description: "Glyph Set Saves",
cost: 3e9
},
run: {
id: 3,
description: "Effarig's Reality",
cost: 5e11
},
infinity: {
id: 4,
label: "Infinity",
get description() {
if (Pelle.isDoomed) return "Any rewards from Effarig's Infinity have been disabled.";
return ` Infinities raise the Replicanti cap
GameDatabase.celestials.effarig.unlocks = {
adjuster: {
id: 0,
description: "Adjustable Glyph level factor weights",
cost: 1e7,
onPurchased: () => {
Effarig.quotes.show(Effarig.quotes.UNLOCK_WEIGHTS);
ui.view.tabs.reality.openGlyphWeights = true;
Tab.reality.glyphs.show();
}
},
glyphFilter: {
id: 1,
description: "Glyph Filtering",
cost: 2e8,
onPurchased: () => {
Effarig.quotes.show(Effarig.quotes.UNLOCK_GLYPH_FILTER);
player.reality.showSidebarPanel = GLYPH_SIDEBAR_MODE.FILTER_SETTINGS;
}
},
setSaves: {
id: 2,
description: "Glyph Set Saves",
cost: 3e9,
onPurchased: () => {
Effarig.quotes.show(Effarig.quotes.UNLOCK_SET_SAVES);
player.reality.showSidebarPanel = GLYPH_SIDEBAR_MODE.SAVED_SETS;
}
},
run: {
id: 3,
description: "Effarig's Reality",
cost: 5e11,
onPurchased: () => {
Effarig.quotes.show(Effarig.quotes.UNLOCK_RUN);
}
},
infinity: {
id: 4,
label: "Infinity",
get description() {
if (Pelle.isDoomed) return "Any rewards from Effarig's Infinity have been disabled.";
return ` Infinities raise the Replicanti cap
Infinities increase your max Replicanti Galaxies
Base Infinity Point gain is capped at ${format(DC.E200)} in Effarig's Reality
Each type of Infinity Point multiplier is capped at ${format(DC.E50)} in Effarig's Reality`;
},
},
eternity: {
id: 5,
label: "Eternity",
get description() {
if (Pelle.isDoomed) return "Any rewards from Effarig's Eternity have been disabled.";
return ` Eternities generates Infinities
Infinity Points are no longer limited in any way in Effarig's Reality
You have unlocked The Enslaved Ones`;
},
},
eternity: {
id: 5,
label: "Eternity",
get description() {
if (Pelle.isDoomed) return "Any rewards from Effarig's Eternity have been disabled.";
return ` Eternities generates Infinities
Infinity Points are no longer limited in any way in Effarig's Reality
You have unlocked The Enslaved Ones`;
},
},
reality: {
id: 6,
label: "Reality",
get description() {
if (Pelle.isDoomed) return "Any rewards from Effarig's Reality have been disabled.";
return " You have unlocked Effarig Glyphs (You may equip at most one)";
},
reality: {
id: 6,
label: "Reality",
get description() {
if (Pelle.isDoomed) return "Any rewards from Effarig's Reality have been disabled.";
return " You have unlocked Effarig Glyphs (You may equip at most one)";
},
}
}
};

View File

@ -60,7 +60,8 @@ GameDatabase.celestials.enslaved = {
glyphHints: [
"Infinity and Dilation Glyphs seem confined too tightly to be useful at all.",
"Power and Time Glyphs are particularly strong here.",
"Effarig Glyphs are only useful with the right effects, but you can complete the Reality without one. " +
"A Replication Glyph is very helpful, but it's not strictly necessary or quite as strong " +
"as Power and Time."]
`Effarig Glyphs are only useful with the right effects, but you can complete the Reality without one.
A Replication Glyph is very helpful, but it's not strictly necessary or quite as strong
as Power and Time.`
]
};

View File

@ -1,66 +1,65 @@
import { GameDatabase } from "../game-database";
GameDatabase.celestials.pelle.galaxyGeneratorUpgrades = (function() {
const formatCost = c => format(c, 2);
const formatCost = c => format(c, 2);
const rebuyable = config => {
const { id, description, cost, effect, formatEffect, currency, currencyLabel } = config;
return {
id,
description,
cost: () => cost(player.celestials.pelle.rebuyables[id]),
formatCost,
effect: (x = player.celestials.pelle.rebuyables[id]) => effect(x),
formatEffect,
currency,
currencyLabel
};
};
const rebuyable = config => {
const { id, description, cost, effect, formatEffect, currency, currencyLabel } = config;
return {
additive: rebuyable({
id: "galaxyGeneratorAdditive",
description: "Increase base Galaxy generation by 2",
cost: x => Math.pow(3, x),
effect: x => x * 2,
formatEffect: x => `${format(x, 2, 2)}/s`,
currency: () => Currency.galaxyGeneratorGalaxies,
currencyLabel: "Galaxy"
}),
multiplicative: rebuyable({
id: "galaxyGeneratorMultiplicative",
description: "Multiply Galaxy generation",
cost: x => Math.pow(10, x),
effect: x => Decimal.pow(2.5, x),
formatEffect: x => formatX(x, 2, 1),
currency: () => Currency.galaxyGeneratorGalaxies,
currencyLabel: "Galaxy"
}),
antimatterMult: rebuyable({
id: "galaxyGeneratorAntimatterMult",
description: "Multiply Galaxy generation",
cost: x => Decimal.pow("1e100000000", 10 ** x),
effect: x => Decimal.pow(2, x),
formatEffect: x => formatX(x, 2),
currency: () => Currency.antimatter,
currencyLabel: "Antimatter"
}),
IPMult: rebuyable({
id: "galaxyGeneratorIPMult",
description: "Multiply Galaxy generation",
cost: x => Decimal.pow("1e2000000", 100 ** x),
effect: x => Decimal.pow(2, x),
formatEffect: x => formatX(x, 2),
currency: () => Currency.infinityPoints,
currencyLabel: "Infinity Point"
}),
EPMult: rebuyable({
id: "galaxyGeneratorEPMult",
description: "Multiply Galaxy generation",
cost: x => Decimal.pow("1e10000", 1000 ** x),
effect: x => Decimal.pow(2, x),
formatEffect: x => formatX(x, 2),
currency: () => Currency.eternityPoints,
currencyLabel: "Eternity Point"
}),
id,
description,
cost: () => cost(player.celestials.pelle.rebuyables[id]),
formatCost,
effect: (x = player.celestials.pelle.rebuyables[id]) => effect(x),
formatEffect,
currency,
currencyLabel
};
}());
};
GameDatabase.celestials.pelle.galaxyGeneratorUpgrades = {
additive: rebuyable({
id: "galaxyGeneratorAdditive",
description: "Increase base Galaxy generation by 2",
cost: x => Math.pow(3, x),
effect: x => x * 2,
formatEffect: x => `${format(x, 2, 2)}/s`,
currency: () => Currency.galaxyGeneratorGalaxies,
currencyLabel: "Galaxy"
}),
multiplicative: rebuyable({
id: "galaxyGeneratorMultiplicative",
description: "Multiply Galaxy generation",
cost: x => Math.pow(10, x),
effect: x => Decimal.pow(2.5, x),
formatEffect: x => formatX(x, 2, 1),
currency: () => Currency.galaxyGeneratorGalaxies,
currencyLabel: "Galaxy"
}),
antimatterMult: rebuyable({
id: "galaxyGeneratorAntimatterMult",
description: "Multiply Galaxy generation",
cost: x => Decimal.pow("1e100000000", 10 ** x),
effect: x => Decimal.pow(2, x),
formatEffect: x => formatX(x, 2),
currency: () => Currency.antimatter,
currencyLabel: "Antimatter"
}),
IPMult: rebuyable({
id: "galaxyGeneratorIPMult",
description: "Multiply Galaxy generation",
cost: x => Decimal.pow("1e2000000", 100 ** x),
effect: x => Decimal.pow(2, x),
formatEffect: x => formatX(x, 2),
currency: () => Currency.infinityPoints,
currencyLabel: "Infinity Point"
}),
EPMult: rebuyable({
id: "galaxyGeneratorEPMult",
description: "Multiply Galaxy generation",
cost: x => Decimal.pow("1e10000", 1000 ** x),
effect: x => Decimal.pow(2, x),
formatEffect: x => formatX(x, 2),
currency: () => Currency.eternityPoints,
currencyLabel: "Eternity Point"
}),
};

File diff suppressed because it is too large Load Diff

View File

@ -1,190 +1,189 @@
import { GameDatabase } from "../game-database";
GameDatabase.celestials.pelle.upgrades = (function() {
const formatCost = c => format(c, 2);
// eslint-disable-next-line max-params
const expWithIncreasedScale = (base1, base2, incScale, coeff, x) =>
Decimal.pow(base1, x).times(Decimal.pow(base2, x - incScale).max(1)).times(coeff);
const formatCost = c => format(c, 2);
// eslint-disable-next-line max-params
const expWithIncreasedScale = (base1, base2, incScale, coeff, x) =>
Decimal.pow(base1, x).times(Decimal.pow(base2, x - incScale).max(1)).times(coeff);
const rebuyable = config => {
const { id, description, cost, effect, formatEffect, cap } = config;
return {
id,
description,
cost: () => expWithIncreasedScale(...cost, player.celestials.pelle.rebuyables[id]),
formatCost,
cap,
effect: (x = player.celestials.pelle.rebuyables[id]) => effect(x),
formatEffect,
rebuyable: true
};
};
const rebuyable = config => {
const { id, description, cost, effect, formatEffect, cap } = config;
return {
antimatterDimensionMult: rebuyable({
id: "antimatterDimensionMult",
description: "Gain a multiplier to Antimatter Dimensions",
cost: [10, 1e3, 41, 100],
effect: x => Pelle.antimatterDimensionMult(x),
formatEffect: x => formatX(x, 2, 2),
cap: 44
}),
timeSpeedMult: rebuyable({
id: "timeSpeedMult",
description: "Gain a multiplier to game speed",
cost: [20, 1e3, 30, 1e5],
effect: x => Decimal.pow(1.3, x),
formatEffect: x => formatX(x, 2, 2),
cap: 35
}),
glyphLevels: rebuyable({
id: "glyphLevels",
description: "Increase the Glyph level allowed in Pelle",
cost: [30, 1e3, 25, 1e15],
effect: x => Math.floor(((3 * (x + 1)) - 2) ** 1.6),
formatEffect: x => formatInt(x),
cap: 26
}),
infConversion: rebuyable({
id: "infConversion",
description: "Increase Infinity Power conversion rate",
cost: [40, 1e3, 20, 1e18],
effect: x => (x * 3.5) ** 0.37,
formatEffect: x => `+${format(x, 2, 2)}`,
cap: 21
}),
galaxyPower: rebuyable({
id: "galaxyPower",
description: "Multiply Galaxy power",
cost: [1000, 1e3, 10, 1e30],
effect: x => 1 + x / 50,
formatEffect: x => formatX(x, 2, 2),
cap: 9
}),
antimatterDimAutobuyers1: {
id: 0,
description: "Gain back Autobuyers for Antimatter Dimensions 1-4",
cost: 1e5,
formatCost,
},
dimBoostAutobuyer: {
id: 1,
description: "Gain back the Autobuyer for Dimension Boosts",
cost: 5e5,
formatCost,
},
keepAutobuyers: {
id: 2,
description: "Keep your Autobuyer upgrades on Armageddon",
cost: 5e6,
formatCost,
},
antimatterDimAutobuyers2: {
id: 3,
description: "Gain back Autobuyers for Antimatter Dimensions 5-8",
cost: 2.5e7,
formatCost,
},
galaxyAutobuyer: {
id: 4,
description: "Gain back the Autobuyer for Antimatter Galaxies",
cost: 1e8,
formatCost,
},
tickspeedAutobuyer: {
id: 5,
description: "Gain back the Autobuyer for Tickspeed",
cost: 1e9,
formatCost,
},
keepInfinityUpgrades: {
id: 6,
description: "Keep Infinity Upgrades on Armageddon",
cost: 1e10,
formatCost,
},
keepBreakInfinityUpgrades: {
id: 7,
description: "Keep Break Infinity Upgrades on Armageddon",
cost: 1e12,
formatCost,
},
IDAutobuyers: {
id: 8,
description: "Gain back Infinity Dimension Autobuyers",
cost: 1e14,
formatCost,
},
keepInfinityChallenges: {
id: 9,
description: "You keep your Infinity Challenge unlocks and completions through Armageddons",
cost: 1e15,
formatCost,
},
replicantiAutobuyers: {
id: 10,
description: "Gain back Replicanti Upgrade Autobuyers",
cost: 1e17,
formatCost,
},
replicantiGalaxyNoReset: {
id: 11,
description: "Replicanti Galaxies don't reset on Infinity",
cost: 1e19,
formatCost,
},
eternitiesNoReset: {
id: 12,
description: "Eternities do not reset on Armageddon",
cost: 1e20,
formatCost,
},
timeStudiesNoReset: {
id: 13,
description: "Time Studies and Theorems do not reset on Armageddon",
cost: 1e21,
formatCost,
},
replicantiStayUnlocked: {
id: 14,
description: "Replicanti stays unlocked on Armageddon",
cost: 1e22,
formatCost,
},
keepEternityUpgrades: {
id: 15,
description: "Keep Eternity Upgrades on Armageddon",
cost: 1e24,
formatCost,
},
TDAutobuyers: {
id: 16,
description: "Gain back Time Dimension Autobuyers",
cost: 1e25,
formatCost,
},
keepEternityChallenges: {
id: 17,
description: "You keep your Eternity Challenge completions through Armageddons",
cost: 1e26,
formatCost,
},
dimBoostResetsNothing: {
id: 18,
description: "Dimension Boosts no longer reset anything",
cost: 1e30,
formatCost,
},
dilationUpgradesNoReset: {
id: 19,
description: "Keep Dilation Upgrades on Armageddon",
cost: 1e45,
formatCost,
},
tachyonParticlesNoReset: {
id: 20,
description: "Keep Tachyon Particles on Armageddon",
cost: 1e50,
formatCost,
}
id,
description,
cost: () => expWithIncreasedScale(...cost, player.celestials.pelle.rebuyables[id]),
formatCost,
cap,
effect: (x = player.celestials.pelle.rebuyables[id]) => effect(x),
formatEffect,
rebuyable: true
};
}());
};
GameDatabase.celestials.pelle.upgrades = {
antimatterDimensionMult: rebuyable({
id: "antimatterDimensionMult",
description: "Gain a multiplier to Antimatter Dimensions",
cost: [10, 1e3, 41, 100],
effect: x => Pelle.antimatterDimensionMult(x),
formatEffect: x => formatX(x, 2, 2),
cap: 44
}),
timeSpeedMult: rebuyable({
id: "timeSpeedMult",
description: "Gain a multiplier to game speed",
cost: [20, 1e3, 30, 1e5],
effect: x => Decimal.pow(1.3, x),
formatEffect: x => formatX(x, 2, 2),
cap: 35
}),
glyphLevels: rebuyable({
id: "glyphLevels",
description: "Increase the Glyph level allowed in Pelle",
cost: [30, 1e3, 25, 1e15],
effect: x => Math.floor(((3 * (x + 1)) - 2) ** 1.6),
formatEffect: x => formatInt(x),
cap: 26
}),
infConversion: rebuyable({
id: "infConversion",
description: "Increase Infinity Power conversion rate",
cost: [40, 1e3, 20, 1e18],
effect: x => (x * 3.5) ** 0.37,
formatEffect: x => `+${format(x, 2, 2)}`,
cap: 21
}),
galaxyPower: rebuyable({
id: "galaxyPower",
description: "Multiply Galaxy power",
cost: [1000, 1e3, 10, 1e30],
effect: x => 1 + x / 50,
formatEffect: x => formatX(x, 2, 2),
cap: 9
}),
antimatterDimAutobuyers1: {
id: 0,
description: "Gain back Autobuyers for Antimatter Dimensions 1-4",
cost: 1e5,
formatCost,
},
dimBoostAutobuyer: {
id: 1,
description: "Gain back the Autobuyer for Dimension Boosts",
cost: 5e5,
formatCost,
},
keepAutobuyers: {
id: 2,
description: "Keep your Autobuyer upgrades on Armageddon",
cost: 5e6,
formatCost,
},
antimatterDimAutobuyers2: {
id: 3,
description: "Gain back Autobuyers for Antimatter Dimensions 5-8",
cost: 2.5e7,
formatCost,
},
galaxyAutobuyer: {
id: 4,
description: "Gain back the Autobuyer for Antimatter Galaxies",
cost: 1e8,
formatCost,
},
tickspeedAutobuyer: {
id: 5,
description: "Gain back the Autobuyer for Tickspeed",
cost: 1e9,
formatCost,
},
keepInfinityUpgrades: {
id: 6,
description: "Keep Infinity Upgrades on Armageddon",
cost: 1e10,
formatCost,
},
keepBreakInfinityUpgrades: {
id: 7,
description: "Keep Break Infinity Upgrades on Armageddon",
cost: 1e12,
formatCost,
},
IDAutobuyers: {
id: 8,
description: "Gain back Infinity Dimension Autobuyers",
cost: 1e14,
formatCost,
},
keepInfinityChallenges: {
id: 9,
description: "You keep your Infinity Challenge unlocks and completions through Armageddons",
cost: 1e15,
formatCost,
},
replicantiAutobuyers: {
id: 10,
description: "Gain back Replicanti Upgrade Autobuyers",
cost: 1e17,
formatCost,
},
replicantiGalaxyNoReset: {
id: 11,
description: "Replicanti Galaxies don't reset on Infinity",
cost: 1e19,
formatCost,
},
eternitiesNoReset: {
id: 12,
description: "Eternities do not reset on Armageddon",
cost: 1e20,
formatCost,
},
timeStudiesNoReset: {
id: 13,
description: "Time Studies and Theorems do not reset on Armageddon",
cost: 1e21,
formatCost,
},
replicantiStayUnlocked: {
id: 14,
description: "Replicanti stays unlocked on Armageddon",
cost: 1e22,
formatCost,
},
keepEternityUpgrades: {
id: 15,
description: "Keep Eternity Upgrades on Armageddon",
cost: 1e24,
formatCost,
},
TDAutobuyers: {
id: 16,
description: "Gain back Time Dimension Autobuyers",
cost: 1e25,
formatCost,
},
keepEternityChallenges: {
id: 17,
description: "You keep your Eternity Challenge completions through Armageddons",
cost: 1e26,
formatCost,
},
dimBoostResetsNothing: {
id: 18,
description: "Dimension Boosts no longer reset anything",
cost: 1e30,
formatCost,
},
dilationUpgradesNoReset: {
id: 19,
description: "Keep Dilation Upgrades on Armageddon",
cost: 1e45,
formatCost,
},
tachyonParticlesNoReset: {
id: 20,
description: "Keep Tachyon Particles on Armageddon",
cost: 1e50,
formatCost,
}
};

View File

@ -1,87 +1,87 @@
import { GameDatabase } from "../game-database";
GameDatabase.celestials.perkShop = (function() {
function rebuyableCost(initialCost, increment, id) {
return initialCost * Math.pow(increment, player.celestials.teresa.perkShop[id]);
}
function rebuyable(config) {
return {
id: config.id,
cost: () => (config.cost ? config.cost() : rebuyableCost(config.initialCost, config.increment, config.id)),
otherReq: config.otherReq,
cap: config.cap,
costCap: config.costCap,
description: config.description,
effect: () => config.effect(player.celestials.teresa.perkShop[config.id]),
formatEffect: config.formatEffect,
formatCost: config.formatCost,
rebuyable: true
};
}
function rebuyableCost(initialCost, increment, id) {
return initialCost * Math.pow(increment, player.celestials.teresa.perkShop[id]);
}
function rebuyable(config) {
const { id, otherReq, cap, costCap, description, formatEffect, formatCost } = config;
return {
glyphLevel: rebuyable({
id: 0,
initialCost: 1,
increment: 2,
description: () => `Increase Glyph levels by ${formatPercents(0.05)}`,
effect: bought => Math.pow(1.05, bought),
formatEffect: value => formatX(value, 2, 2),
formatCost: value => format(value, 2),
costCap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 1048576 : 2048),
cap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? Math.pow(1.05, 20) : Math.pow(1.05, 11))
}),
rmMult: rebuyable({
id: 1,
initialCost: 1,
increment: 2,
description: "Double Reality Machine gain",
effect: bought => Math.pow(2, bought),
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
costCap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 1048576 : 2048),
cap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 1048576 : 2048)
}),
bulkDilation: rebuyable({
id: 2,
initialCost: 100,
increment: 2,
description: "Buy twice as many Dilation Upgrades at once.",
effect: bought => Math.pow(2, bought),
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
costCap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 1638400 : 1600),
cap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 16384 : 16),
}),
autoSpeed: rebuyable({
id: 3,
initialCost: 1000,
increment: 2,
description: () => `Infinity Dimension, Time Dimension, Dilation,
and Replicanti autobuyers are ${formatX(2)} faster.`,
effect: bought => Math.pow(2, bought),
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
costCap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 64000 : 4000),
cap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 64 : 4)
}),
musicGlyph: rebuyable({
id: 4,
description: () => `Receive a Music Glyph of a random type that is ${formatPercents(0.8)} of your highest level.
(Try clicking it!)`,
cost: () => 1,
formatCost: value => formatInt(value),
costCap: () => Number.MAX_VALUE,
cap: () => Number.MAX_VALUE
}),
// Only appears with the perk shop increase upgrade
fillMusicGlyph: rebuyable({
id: 5,
description: () => `Fill all empty slots in your inventory with Music Glyphs`,
cost: () => Math.clampMin(Glyphs.freeInventorySpace, 1),
otherReq: () => Glyphs.freeInventorySpace > 0,
formatCost: value => formatInt(value),
costCap: () => Number.MAX_VALUE,
cap: () => Number.MAX_VALUE
}),
id,
cost: () => (config.cost ? config.cost() : rebuyableCost(config.initialCost, config.increment, config.id)),
otherReq,
cap,
costCap,
description,
effect: () => config.effect(player.celestials.teresa.perkShop[config.id]),
formatEffect,
formatCost,
rebuyable: true
};
}());
}
GameDatabase.celestials.perkShop = {
glyphLevel: rebuyable({
id: 0,
initialCost: 1,
increment: 2,
description: () => `Increase Glyph levels by ${formatPercents(0.05)}`,
effect: bought => Math.pow(1.05, bought),
formatEffect: value => formatX(value, 2, 2),
formatCost: value => format(value, 2),
costCap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 1048576 : 2048),
cap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? Math.pow(1.05, 20) : Math.pow(1.05, 11))
}),
rmMult: rebuyable({
id: 1,
initialCost: 1,
increment: 2,
description: "Double Reality Machine gain",
effect: bought => Math.pow(2, bought),
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
costCap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 1048576 : 2048),
cap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 1048576 : 2048)
}),
bulkDilation: rebuyable({
id: 2,
initialCost: 100,
increment: 2,
description: "Buy twice as many Dilation Upgrades at once.",
effect: bought => Math.pow(2, bought),
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
costCap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 1638400 : 1600),
cap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 16384 : 16),
}),
autoSpeed: rebuyable({
id: 3,
initialCost: 1000,
increment: 2,
description: () => `Infinity Dimension, Time Dimension, Dilation,
and Replicanti autobuyers are ${formatX(2)} faster.`,
effect: bought => Math.pow(2, bought),
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
costCap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 64000 : 4000),
cap: () => (Ra.unlocks.perkShopIncrease.canBeApplied ? 64 : 4)
}),
musicGlyph: rebuyable({
id: 4,
description: () => `Receive a Music Glyph of a random type that is ${formatPercents(0.8)} of your highest level.
(Try clicking it!)`,
cost: () => 1,
formatCost: value => formatInt(value),
costCap: () => Number.MAX_VALUE,
cap: () => Number.MAX_VALUE
}),
// Only appears with the perk shop increase upgrade
fillMusicGlyph: rebuyable({
id: 5,
description: () => `Fill all empty slots in your inventory with Music Glyphs`,
cost: () => Math.clampMin(Glyphs.freeInventorySpace, 1),
otherReq: () => Glyphs.freeInventorySpace > 0,
formatCost: value => formatInt(value),
costCap: () => Number.MAX_VALUE,
cap: () => Number.MAX_VALUE
}),
};

View File

@ -57,6 +57,10 @@ GameDatabase.confirmationTypes = [
name: "Glyph Undo",
option: "glyphUndo",
isUnlocked: () => TeresaUnlocks.undo.canBeApplied,
}, {
name: "Switch Automator Editor",
option: "switchAutomatorMode",
isUnlocked: () => Player.automatorUnlocked,
}, {
name: "Reset Celestial",
option: "resetCelestial",

View File

@ -1,190 +1,189 @@
import { DC } from "../../constants";
import { GameDatabase } from "../game-database";
GameDatabase.eternity.dilation = (function() {
function rebuyableCost(initialCost, increment, id) {
return Decimal.multiply(initialCost, Decimal.pow(increment, player.dilation.rebuyables[id]));
}
function rebuyable(config) {
return {
id: config.id,
cost: () => rebuyableCost(config.initialCost, config.increment, config.id),
initialCost: config.initialCost,
increment: config.increment,
description: config.description,
effect: () => config.effect(player.dilation.rebuyables[config.id]),
formatEffect: config.formatEffect,
formatCost: config.formatCost,
purchaseCap: config.purchaseCap,
reachedCap: () => player.dilation.rebuyables[config.id] >= config.purchaseCap,
pelleOnly: Boolean(config.pelleOnly),
rebuyable: true
};
}
function rebuyableCost(initialCost, increment, id) {
return Decimal.multiply(initialCost, Decimal.pow(increment, player.dilation.rebuyables[id]));
}
function rebuyable(config) {
return {
dtGain: rebuyable({
id: 1,
initialCost: 1e5,
increment: 10,
description: () =>
(SingularityMilestone.dilatedTimeFromSingularities.isUnlocked
? `${formatX(2 * SingularityMilestone.dilatedTimeFromSingularities.effectValue, 2, 2)} Dilated Time gain`
: "Double Dilated Time gain"),
effect: bought => {
const base = SingularityMilestone.dilatedTimeFromSingularities.isUnlocked
? 2 * SingularityMilestone.dilatedTimeFromSingularities.effectValue
: 2;
return Decimal.pow(base, bought);
},
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
purchaseCap: Number.MAX_VALUE
}),
galaxyThreshold: rebuyable({
id: 2,
initialCost: 1e6,
increment: 100,
description: () =>
(Perk.bypassTGReset.isBought
? "Reset Tachyon Galaxies, but lower their threshold"
: "Reset Dilated Time and Tachyon Galaxies, but lower their threshold"),
// The 38th purchase is at 1e80, and is the last purchase.
effect: bought => (bought < 38 ? Math.pow(0.8, bought) : 0),
formatEffect: effect => {
if (effect === 0) return `${formatX(getTachyonGalaxyMult(effect), 4, 4)}`;
const nextEffect = effect === Math.pow(0.8, 37) ? 0 : 0.8 * effect;
return `${formatX(getTachyonGalaxyMult(effect), 4, 4)}
Next: ${formatX(getTachyonGalaxyMult(nextEffect), 4, 4)}`;
},
formatCost: value => format(value, 2),
purchaseCap: 38
}),
tachyonGain: rebuyable({
id: 3,
initialCost: 1e7,
increment: 20,
description: () => {
if (Pelle.isDoomed) return `Multiply the amount of Tachyon Particles gained by ${formatInt(1)}`;
if (Enslaved.isRunning) return `Multiply the amount of Tachyon Particles gained
by ${Math.pow(3, Enslaved.tachyonNerf).toFixed(2)}`;
return "Triple the amount of Tachyon Particles gained";
},
effect: bought => {
if (Pelle.isDoomed) return DC.D1.pow(bought);
return DC.D3.pow(bought);
},
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
purchaseCap: Number.MAX_VALUE
}),
doubleGalaxies: {
id: 4,
cost: 5e6,
description: () => `Gain twice as many Tachyon Galaxies, up to ${formatInt(1000)}`,
effect: 2
},
tdMultReplicanti: {
id: 5,
cost: 1e9,
description: () => {
const rep10 = replicantiMult().pLog10();
let multiplier = "0.1";
if (rep10 > 9000) {
const ratio = DilationUpgrade.tdMultReplicanti.effectValue.pLog10() / rep10;
if (ratio < 0.095) {
multiplier = ratio.toFixed(2);
}
}
return `Time Dimensions are affected by Replicanti multiplier ${formatPow(multiplier, 1, 3)}, reduced
effect above ${formatX(DC.E9000)}`;
},
effect: () => {
let rep10 = replicantiMult().pLog10() * 0.1;
rep10 = rep10 > 9000 ? 9000 + 0.5 * (rep10 - 9000) : rep10;
return Decimal.pow10(rep10);
},
formatEffect: value => formatX(value, 2, 1)
},
ndMultDT: {
id: 6,
cost: 5e7,
description: "Antimatter Dimension multiplier based on Dilated Time, unaffected by Time Dilation",
effect: () => Currency.dilatedTime.value.pow(308).clampMin(1),
formatEffect: value => formatX(value, 2, 1)
},
ipMultDT: {
id: 7,
cost: 2e12,
description: "Gain a multiplier to Infinity Points based on Dilated Time",
effect: () => Currency.dilatedTime.value.pow(1000).clampMin(1),
formatEffect: value => formatX(value, 2, 1),
cap: () => Effarig.eternityCap
},
timeStudySplit: {
id: 8,
cost: 1e10,
description: "You can buy all three Time Study paths from the Dimension Split"
},
dilationPenalty: {
id: 9,
cost: 1e11,
description: () => `Reduce the Dilation penalty (${formatPow(1.05, 2, 2)} after reduction)`,
effect: 1.05,
},
ttGenerator: {
id: 10,
cost: 1e15,
description: "Generate Time Theorems based on Tachyon Particles",
effect: () => Currency.tachyonParticles.value.div(20000),
formatEffect: value => `${format(value, 2, 1)}/sec`
},
dtGainPelle: rebuyable({
id: 11,
initialCost: 1e14,
increment: 100,
pelleOnly: true,
description: () => `${formatX(5)} Dilated Time gain`,
effect: bought => Decimal.pow(5, bought),
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
purchaseCap: Number.MAX_VALUE
}),
galaxyMultiplier: rebuyable({
id: 12,
initialCost: 1e15,
increment: 1000,
pelleOnly: true,
description: () => "Multiply Tachyon Galaxies gained",
effect: bought => bought + 1,
formatEffect: value => `${formatX(value, 2)}${formatX(value + 1, 2)}`,
formatCost: value => format(value, 2),
purchaseCap: Number.MAX_VALUE
}),
tickspeedPower: rebuyable({
id: 13,
initialCost: 1e16,
increment: 1e4,
pelleOnly: true,
description: () => `Gain a power to tickspeed effect`,
effect: bought => 1 + bought * 0.03,
formatEffect: value => `${formatPow(value, 2, 2)}${formatPow(value + 0.03, 2, 2)}`,
formatCost: value => format(value, 2),
purchaseCap: Number.MAX_VALUE
}),
galaxyThresholdPelle: {
id: 14,
cost: 1e45,
pelleOnly: true,
description: "Cubic root Tachyon Galaxy threshold",
effect: 1 / 3
},
flatDilationMult: {
id: 15,
cost: 1e55,
pelleOnly: true,
description: () => `Gain more Dilated Time based on EP`,
effect: () => 1e9 ** Math.min((Math.max(player.eternityPoints.log10() - 1500, 0) / 2500) ** 1.2, 1),
formatEffect: value => formatX(value, 2, 2)
},
id: config.id,
cost: () => rebuyableCost(config.initialCost, config.increment, config.id),
initialCost: config.initialCost,
increment: config.increment,
description: config.description,
effect: () => config.effect(player.dilation.rebuyables[config.id]),
formatEffect: config.formatEffect,
formatCost: config.formatCost,
purchaseCap: config.purchaseCap,
reachedCap: () => player.dilation.rebuyables[config.id] >= config.purchaseCap,
pelleOnly: Boolean(config.pelleOnly),
rebuyable: true
};
}());
}
GameDatabase.eternity.dilation = {
dtGain: rebuyable({
id: 1,
initialCost: 1e5,
increment: 10,
description: () =>
(SingularityMilestone.dilatedTimeFromSingularities.isUnlocked
? `${formatX(2 * SingularityMilestone.dilatedTimeFromSingularities.effectValue, 2, 2)} Dilated Time gain`
: "Double Dilated Time gain"),
effect: bought => {
const base = SingularityMilestone.dilatedTimeFromSingularities.isUnlocked
? 2 * SingularityMilestone.dilatedTimeFromSingularities.effectValue
: 2;
return Decimal.pow(base, bought);
},
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
purchaseCap: Number.MAX_VALUE
}),
galaxyThreshold: rebuyable({
id: 2,
initialCost: 1e6,
increment: 100,
description: () =>
(Perk.bypassTGReset.isBought
? "Reset Tachyon Galaxies, but lower their threshold"
: "Reset Dilated Time and Tachyon Galaxies, but lower their threshold"),
// The 38th purchase is at 1e80, and is the last purchase.
effect: bought => (bought < 38 ? Math.pow(0.8, bought) : 0),
formatEffect: effect => {
if (effect === 0) return `${formatX(getTachyonGalaxyMult(effect), 4, 4)}`;
const nextEffect = effect === Math.pow(0.8, 37) ? 0 : 0.8 * effect;
return `${formatX(getTachyonGalaxyMult(effect), 4, 4)}
Next: ${formatX(getTachyonGalaxyMult(nextEffect), 4, 4)}`;
},
formatCost: value => format(value, 2),
purchaseCap: 38
}),
tachyonGain: rebuyable({
id: 3,
initialCost: 1e7,
increment: 20,
description: () => {
if (Pelle.isDoomed) return `Multiply the amount of Tachyon Particles gained by ${formatInt(1)}`;
if (Enslaved.isRunning) return `Multiply the amount of Tachyon Particles gained
by ${Math.pow(3, Enslaved.tachyonNerf).toFixed(2)}`;
return "Triple the amount of Tachyon Particles gained";
},
effect: bought => {
if (Pelle.isDoomed) return DC.D1.pow(bought);
return DC.D3.pow(bought);
},
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
purchaseCap: Number.MAX_VALUE
}),
doubleGalaxies: {
id: 4,
cost: 5e6,
description: () => `Gain twice as many Tachyon Galaxies, up to ${formatInt(1000)}`,
effect: 2
},
tdMultReplicanti: {
id: 5,
cost: 1e9,
description: () => {
const rep10 = replicantiMult().pLog10();
let multiplier = "0.1";
if (rep10 > 9000) {
const ratio = DilationUpgrade.tdMultReplicanti.effectValue.pLog10() / rep10;
if (ratio < 0.095) {
multiplier = ratio.toFixed(2);
}
}
return `Time Dimensions are affected by Replicanti multiplier ${formatPow(multiplier, 1, 3)}, reduced
effect above ${formatX(DC.E9000)}`;
},
effect: () => {
let rep10 = replicantiMult().pLog10() * 0.1;
rep10 = rep10 > 9000 ? 9000 + 0.5 * (rep10 - 9000) : rep10;
return Decimal.pow10(rep10);
},
formatEffect: value => formatX(value, 2, 1)
},
ndMultDT: {
id: 6,
cost: 5e7,
description: "Antimatter Dimension multiplier based on Dilated Time, unaffected by Time Dilation",
effect: () => Currency.dilatedTime.value.pow(308).clampMin(1),
formatEffect: value => formatX(value, 2, 1)
},
ipMultDT: {
id: 7,
cost: 2e12,
description: "Gain a multiplier to Infinity Points based on Dilated Time",
effect: () => Currency.dilatedTime.value.pow(1000).clampMin(1),
formatEffect: value => formatX(value, 2, 1),
cap: () => Effarig.eternityCap
},
timeStudySplit: {
id: 8,
cost: 1e10,
description: "You can buy all three Time Study paths from the Dimension Split"
},
dilationPenalty: {
id: 9,
cost: 1e11,
description: () => `Reduce the Dilation penalty (${formatPow(1.05, 2, 2)} after reduction)`,
effect: 1.05,
},
ttGenerator: {
id: 10,
cost: 1e15,
description: "Generate Time Theorems based on Tachyon Particles",
effect: () => Currency.tachyonParticles.value.div(20000),
formatEffect: value => `${format(value, 2, 1)}/sec`
},
dtGainPelle: rebuyable({
id: 11,
initialCost: 1e14,
increment: 100,
pelleOnly: true,
description: () => `${formatX(5)} Dilated Time gain`,
effect: bought => Decimal.pow(5, bought),
formatEffect: value => formatX(value, 2),
formatCost: value => format(value, 2),
purchaseCap: Number.MAX_VALUE
}),
galaxyMultiplier: rebuyable({
id: 12,
initialCost: 1e15,
increment: 1000,
pelleOnly: true,
description: () => "Multiply Tachyon Galaxies gained",
effect: bought => bought + 1,
formatEffect: value => `${formatX(value, 2)}${formatX(value + 1, 2)}`,
formatCost: value => format(value, 2),
purchaseCap: Number.MAX_VALUE
}),
tickspeedPower: rebuyable({
id: 13,
initialCost: 1e16,
increment: 1e4,
pelleOnly: true,
description: () => `Gain a power to tickspeed effect`,
effect: bought => 1 + bought * 0.03,
formatEffect: value => `${formatPow(value, 2, 2)}${formatPow(value + 0.03, 2, 2)}`,
formatCost: value => format(value, 2),
purchaseCap: Number.MAX_VALUE
}),
galaxyThresholdPelle: {
id: 14,
cost: 1e45,
pelleOnly: true,
description: "Cubic root Tachyon Galaxy threshold",
effect: 1 / 3
},
flatDilationMult: {
id: 15,
cost: 1e55,
pelleOnly: true,
description: () => `Gain more Dilated Time based on EP`,
effect: () => 1e9 ** Math.min((Math.max(player.eternityPoints.log10() - 1500, 0) / 2500) ** 1.2, 1),
formatEffect: value => formatX(value, 2, 2)
},
};

View File

@ -10,6 +10,8 @@ export const GameDatabase = {
glyphSacrifice: {},
},
celestials: {
effarig: {},
alchemy: {},
pelle: {},
descriptions: {},
}

View File

@ -1,145 +1,148 @@
import { DC } from "../../constants";
import { GameDatabase } from "../game-database";
GameDatabase.infinity.breakUpgrades = (function() {
function rebuyable(config) {
const effectFunction = config.effect || (x => x);
return {
id: config.id,
cost: () => config.initialCost * Math.pow(config.costIncrease, player.infinityRebuyables[config.id]),
maxUpgrades: config.maxUpgrades,
description: config.description,
effect: () => effectFunction(player.infinityRebuyables[config.id]),
isDisabled: config.isDisabled,
// There isn't enough room in the button to fit the EC reduction and "Next:" at the same time while still
// presenting all the information in an understandable way, so we only show it if the upgrade is maxed
formatEffect: config.formatEffect ||
(value => {
const afterECText = config.afterEC ? config.afterEC() : "";
return value === config.maxUpgrades
? `Default: ${formatX(10)} | Currently: ${formatX(10 - value)} ${afterECText}`
: `Default: ${formatX(10)} | Currently: ${formatX(10 - value)} Next: ${formatX(10 - value - 1)}`;
}),
formatCost: value => format(value, 2, 0),
noLabel: !config.label
};
}
function rebuyable(config) {
const effectFunction = config.effect || (x => x);
const { id, maxUpgrades, description, isDisabled, noLabel, onPurchased } = config;
return {
totalAMMult: {
id: "totalMult",
cost: 1e4,
description: "Antimatter Dimensions gain a multiplier based on total antimatter produced",
effect: () => Math.pow(player.records.totalAntimatter.exponent + 1, 0.5),
formatEffect: value => formatX(value, 2, 2)
},
currentAMMult: {
id: "currentMult",
cost: 5e4,
description: "Antimatter Dimensions gain a multiplier based on current antimatter",
effect: () => Math.pow(Currency.antimatter.exponent + 1, 0.5),
formatEffect: value => formatX(value, 2, 2)
},
galaxyBoost: {
id: "postGalaxy",
cost: 5e11,
description: () => `All Galaxies are ${formatPercents(0.5)} stronger`,
effect: 1.5
},
infinitiedMult: {
id: "infinitiedMult",
cost: 1e5,
description: "Antimatter Dimensions gain a multiplier based on Infinities",
effect: () => 1 + Currency.infinitiesTotal.value.pLog10() * 10,
formatEffect: value => formatX(value, 2, 2)
},
achievementMult: {
id: "achievementMult",
cost: 1e6,
description: "Additional multiplier to Antimatter Dimensions based on Achievements completed",
effect: () => Math.max(Math.pow((Achievements.effectiveCount - 30), 3) / 40, 1),
formatEffect: value => formatX(value, 2, 2)
},
slowestChallengeMult: {
id: "challengeMult",
cost: 1e7,
description: "Antimatter Dimensions gain a multiplier based on slowest challenge run",
effect: () => Decimal.clampMin(50 / Time.worstChallenge.totalMinutes, 1),
formatEffect: value => formatX(value, 2, 2),
hasCap: true,
cap: DC.D3E4
},
infinitiedGen: {
id: "infinitiedGeneration",
cost: 2e7,
description: () => (Pelle.isDoomed
? "This upgrade has no effect while in Doomed"
: "Passively generate Infinities based on your fastest Infinity"),
effect: () => player.records.bestInfinity.time,
formatEffect: value => {
if (Pelle.isDoomed) return "Disabled";
if (value === Number.MAX_VALUE && !Pelle.isDoomed) return "No Infinity generation";
let infinities = DC.D1;
infinities = infinities.timesEffectsOf(
RealityUpgrade(5),
RealityUpgrade(7),
Ra.unlocks.continuousTTBoost.effects.infinity
);
infinities = infinities.times(getAdjustedGlyphEffect("infinityinfmult"));
return `${quantify("Infinity", infinities)} every ${Time.bestInfinity.times(5).toStringShort()}`;
}
},
autobuyMaxDimboosts: {
id: "autobuyMaxDimboosts",
cost: 5e9,
description: "Unlock the buy max Dimension Boost Autobuyer mode"
},
autobuyerSpeed: {
id: "autoBuyerUpgrade",
cost: 1e15,
description: "Autobuyers unlocked or improved by Normal Challenges work twice as fast"
},
tickspeedCostMult: rebuyable({
id: 0,
initialCost: 1e6,
costIncrease: 5,
maxUpgrades: 8,
description: "Reduce post-infinity Tickspeed Upgrade cost multiplier scaling",
afterEC: () => (EternityChallenge(11).completions > 0
? `After EC11: ${formatX(Player.tickSpeedMultDecrease, 2, 2)}`
: ""
),
label: false,
}),
dimCostMult: rebuyable({
id: 1,
initialCost: 1e7,
costIncrease: 5e3,
maxUpgrades: 7,
description: "Reduce post-infinity Antimatter Dimension cost multiplier scaling",
afterEC: () => (EternityChallenge(6).completions > 0
? `After EC6: ${formatX(Player.dimensionMultDecrease, 2, 2)}`
: ""
),
label: false,
}),
ipGen: rebuyable({
id: 2,
initialCost: 1e7,
costIncrease: 10,
maxUpgrades: 10,
effect: value => Player.bestRunIPPM.times(value / 20),
description: () => {
let generation = `Generate ${formatInt(5 * player.infinityRebuyables[2])}%`;
if (!BreakInfinityUpgrade.ipGen.isCapped) {
generation += `${formatInt(5 * (1 + player.infinityRebuyables[2]))}%`;
}
const offlineString = player.options.offlineProgress ? ", works offline" : "";
return `${generation} of your best IP/min from your last 10 Infinities${offlineString}`;
},
isDisabled: effect => effect.eq(0),
formatEffect: value => `${format(value, 2, 1)} IP/min`,
label: true
})
rebuyable: true,
id,
cost: () => config.initialCost * Math.pow(config.costIncrease, player.infinityRebuyables[config.id]),
maxUpgrades,
description,
effect: () => effectFunction(player.infinityRebuyables[config.id]),
isDisabled,
// There isn't enough room in the button to fit the EC reduction and "Next:" at the same time while still
// presenting all the information in an understandable way, so we only show it if the upgrade is maxed
formatEffect: config.formatEffect ||
(value => {
const afterECText = config.afterEC ? config.afterEC() : "";
return value === config.maxUpgrades
? `Default: ${formatX(10)} | Currently: ${formatX(10 - value)} ${afterECText}`
: `Default: ${formatX(10)} | Currently: ${formatX(10 - value)} Next: ${formatX(10 - value - 1)}`;
}),
formatCost: value => format(value, 2, 0),
noLabel,
onPurchased
};
}());
}
GameDatabase.infinity.breakUpgrades = {
totalAMMult: {
id: "totalMult",
cost: 1e4,
description: "Antimatter Dimensions gain a multiplier based on total antimatter produced",
effect: () => Math.pow(player.records.totalAntimatter.exponent + 1, 0.5),
formatEffect: value => formatX(value, 2, 2)
},
currentAMMult: {
id: "currentMult",
cost: 5e4,
description: "Antimatter Dimensions gain a multiplier based on current antimatter",
effect: () => Math.pow(Currency.antimatter.exponent + 1, 0.5),
formatEffect: value => formatX(value, 2, 2)
},
galaxyBoost: {
id: "postGalaxy",
cost: 5e11,
description: () => `All Galaxies are ${formatPercents(0.5)} stronger`,
effect: 1.5
},
infinitiedMult: {
id: "infinitiedMult",
cost: 1e5,
description: "Antimatter Dimensions gain a multiplier based on Infinities",
effect: () => 1 + Currency.infinitiesTotal.value.pLog10() * 10,
formatEffect: value => formatX(value, 2, 2)
},
achievementMult: {
id: "achievementMult",
cost: 1e6,
description: "Additional multiplier to Antimatter Dimensions based on Achievements completed",
effect: () => Math.max(Math.pow((Achievements.effectiveCount - 30), 3) / 40, 1),
formatEffect: value => formatX(value, 2, 2)
},
slowestChallengeMult: {
id: "challengeMult",
cost: 1e7,
description: "Antimatter Dimensions gain a multiplier based on slowest challenge run",
effect: () => Decimal.clampMin(50 / Time.worstChallenge.totalMinutes, 1),
formatEffect: value => formatX(value, 2, 2),
hasCap: true,
cap: DC.D3E4
},
infinitiedGen: {
id: "infinitiedGeneration",
cost: 2e7,
description: () => (Pelle.isDoomed
? "This upgrade has no effect while in Doomed"
: "Passively generate Infinities based on your fastest Infinity"),
effect: () => player.records.bestInfinity.time,
formatEffect: value => {
if (Pelle.isDoomed) return "Disabled";
if (value === Number.MAX_VALUE && !Pelle.isDoomed) return "No Infinity generation";
let infinities = DC.D1;
infinities = infinities.timesEffectsOf(
RealityUpgrade(5),
RealityUpgrade(7),
Ra.unlocks.continuousTTBoost.effects.infinity
);
infinities = infinities.times(getAdjustedGlyphEffect("infinityinfmult"));
return `${quantify("Infinity", infinities)} every ${Time.bestInfinity.times(5).toStringShort()}`;
}
},
autobuyMaxDimboosts: {
id: "autobuyMaxDimboosts",
cost: 5e9,
description: "Unlock the buy max Dimension Boost Autobuyer mode"
},
autobuyerSpeed: {
id: "autoBuyerUpgrade",
cost: 1e15,
description: "Autobuyers unlocked or improved by Normal Challenges work twice as fast"
},
tickspeedCostMult: rebuyable({
id: 0,
initialCost: 1e6,
costIncrease: 5,
maxUpgrades: 8,
description: "Reduce post-infinity Tickspeed Upgrade cost multiplier scaling",
afterEC: () => (EternityChallenge(11).completions > 0
? `After EC11: ${formatX(Player.tickSpeedMultDecrease, 2, 2)}`
: ""
),
noLabel: true,
onPurchased: () => GameCache.tickSpeedMultDecrease.invalidate()
}),
dimCostMult: rebuyable({
id: 1,
initialCost: 1e7,
costIncrease: 5e3,
maxUpgrades: 7,
description: "Reduce post-infinity Antimatter Dimension cost multiplier scaling",
afterEC: () => (EternityChallenge(6).completions > 0
? `After EC6: ${formatX(Player.dimensionMultDecrease, 2, 2)}`
: ""
),
noLabel: true,
onPurchased: () => GameCache.dimensionMultDecrease.invalidate()
}),
ipGen: rebuyable({
id: 2,
initialCost: 1e7,
costIncrease: 10,
maxUpgrades: 10,
effect: value => Player.bestRunIPPM.times(value / 20),
description: () => {
let generation = `Generate ${formatInt(5 * player.infinityRebuyables[2])}%`;
if (!BreakInfinityUpgrade.ipGen.isCapped) {
generation += `${formatInt(5 * (1 + player.infinityRebuyables[2]))}%`;
}
const offlineString = player.options.offlineProgress ? ", works offline" : "";
return `${generation} of your best IP/min from your last 10 Infinities${offlineString}`;
},
isDisabled: effect => effect.eq(0),
formatEffect: value => `${format(value, 2, 1)} IP/min`,
noLabel: false
})
};

View File

@ -1,227 +1,241 @@
import { DC } from "../../constants";
import { GameDatabase } from "../game-database";
GameDatabase.infinity.upgrades = (function() {
function dimInfinityMult() {
return Currency.infinitiesTotal.value.times(0.2).plus(1);
}
function chargedDimInfinityMult() {
return 1 + Math.log10(Math.max(1, Currency.infinitiesTotal.value.pLog10())) * Math.sqrt(Ra.pets.teresa.level) / 150;
}
return {
totalTimeMult: {
id: "timeMult",
cost: 1,
description: "Antimatter Dimensions gain a multiplier based on time played",
effect: () => Math.pow(Time.totalTimePlayed.totalMinutes / 2, 0.15),
formatEffect: value => formatX(value, 2, 2),
charged: {
description: "Antimatter Dimensions gain a power effect based on time played and Teresa level",
effect: () => 1 +
Math.log10(Math.log10(Time.totalTimePlayed.totalMilliseconds)) *
Math.pow(Ra.pets.teresa.level, 0.5) / 150,
formatEffect: value => formatPow(value, 4, 4)
}
},
dim18mult: {
id: "18Mult",
cost: 1,
description: "1st and 8th Antimatter Dimensions gain a multiplier based on Infinities",
effect: () => dimInfinityMult(),
formatEffect: value => formatX(value, 1, 1),
charged: {
description: "1st and 8th Antimatter Dimensions gain a power effect based on Infinities and Teresa level",
effect: () => chargedDimInfinityMult(),
formatEffect: value => formatPow(value, 4, 4)
}
},
dim27mult: {
id: "27Mult",
cost: 1,
description: "2nd and 7th Antimatter Dimensions gain a multiplier based on Infinities",
effect: () => dimInfinityMult(),
formatEffect: value => formatX(value, 1, 1),
charged: {
description: "2nd and 7th Antimatter Dimensions gain a power effect based on Infinities and Teresa level",
effect: () => chargedDimInfinityMult(),
formatEffect: value => formatPow(value, 4, 4)
}
},
dim36mult: {
id: "36Mult",
cost: 1,
description: "3rd and 6th Antimatter Dimensions gain a multiplier based on Infinities",
effect: () => dimInfinityMult(),
formatEffect: value => formatX(value, 1, 1),
charged: {
description: "3rd and 6th Antimatter Dimensions gain a power effect based on Infinities and Teresa level",
effect: () => chargedDimInfinityMult(),
formatEffect: value => formatPow(value, 4, 4)
}
},
dim45mult: {
id: "45Mult",
cost: 1,
description: "4th and 5th Antimatter Dimensions gain a multiplier based on Infinities",
effect: () => dimInfinityMult(),
formatEffect: value => formatX(value, 1, 1),
charged: {
description: "4th and 5th Antimatter Dimensions gain a power effect based on Infinities and Teresa level",
effect: () => chargedDimInfinityMult(),
formatEffect: value => formatPow(value, 4, 4)
}
},
resetBoost: {
id: "resetBoost",
cost: 1,
description: () =>
`Decrease the number of Dimensions needed for Dimension Boosts and Antimatter Galaxies by ${formatInt(9)}`,
effect: 9,
charged: {
description: () => "Decrease Dimension Boost requirement based on Teresa level",
effect: () => 1 / (1 + Math.sqrt(Ra.pets.teresa.level) / 10),
formatEffect: value => `${formatX(value, 4, 4)}`
}
},
buy10Mult: {
id: "dimMult",
cost: 1,
description: () => `Increase the multiplier for buying ${formatInt(10)} Antimatter Dimensions`,
effect: () => 1.1,
formatEffect: () => `${formatX(2, 0, 1)}${formatX(2.2, 0, 1)}`,
charged: {
description: () => `The multiplier for buying ${formatInt(10)} Antimatter Dimensions gains ` +
"a power effect based on Teresa level",
effect: () => 1 + Ra.pets.teresa.level / 200,
formatEffect: value => formatPow(value, 3, 3)
}
},
galaxyBoost: {
id: "galaxyBoost",
cost: 2,
description: "All Galaxies are twice as strong",
effect: 2,
charged: {
description: "All Galaxies are stronger based on Teresa level",
effect: () => 2 + Math.sqrt(Ra.pets.teresa.level) / 100,
formatEffect: value => `+${formatPercents(value - 1)}`
}
},
thisInfinityTimeMult: {
id: "timeMult2",
cost: 3,
description: "Antimatter Dimensions gain a multiplier based on time spent in current Infinity",
effect: () => Decimal.max(Math.pow(Time.thisInfinity.totalMinutes / 4, 0.25), 1),
formatEffect: value => formatX(value, 2, 2),
charged: {
description:
"Antimatter Dimensions gain a power effect based on time spent in current Infinity and Teresa level",
effect: () => 1 +
Math.log10(Math.log10(Time.thisInfinity.totalMilliseconds + 100)) *
Math.sqrt(Ra.pets.teresa.level) / 150,
formatEffect: value => formatPow(value, 4, 4)
}
},
unspentIPMult: {
id: "unspentBonus",
cost: 5,
description: "Multiplier to 1st Antimatter Dimension based on unspent Infinity Points",
effect: () => Currency.infinityPoints.value.dividedBy(2).pow(1.5).plus(1),
formatEffect: value => formatX(value, 2, 2),
charged: {
description: "Multiplier to 1st Antimatter Dimension based on unspent Infinity Points, powered by Teresa level",
effect: () => Currency.infinityPoints.value.dividedBy(2).pow(Math.sqrt(Ra.pets.teresa.level) * 1.5).plus(1),
formatEffect: value => formatX(value, 2, 2)
}
},
dimboostMult: {
id: "resetMult",
cost: 7,
description: "Increase Dimension Boost multiplier",
effect: () => 2.5,
formatEffect: () => `${formatX(2, 0, 1)}${formatX(2.5, 0, 1)}`,
charged: {
description: "Dimension Boost multiplier gains a power effect based on Teresa level",
effect: () => 1 + Ra.pets.teresa.level / 200,
formatEffect: value => formatPow(value, 3, 3)
}
},
ipGen: {
id: "passiveGen",
cost: 10,
description: () => (Pelle.isDoomed
? "This upgrade has no effect while in Doomed"
: `Passively generate Infinity Points ${formatInt(10)} times slower than your fastest Infinity`),
// Cutting corners: this is not actual effect, but it is totalIPMult that is displyed on upgrade
effect: () => (Teresa.isRunning || V.isRunning || Pelle.isDoomed ? DC.D0 : GameCache.totalIPMult.value),
formatEffect: value => {
if (Teresa.isRunning || V.isRunning) return "Disabled in this reality";
if (Pelle.isDoomed) return "Disabled";
const income = format(value, 2, 0);
const period = player.records.bestInfinity.time >= 999999999999
? "∞"
: Time.bestInfinity.times(10).toStringShort();
return `${income} every ${period}`;
},
charged: {
description: () =>
`Gain a percentage of your Reality Machines gained on Reality each real-time second,
percent increases with Teresa level`,
effect: () => Math.sqrt(Ra.pets.teresa.level) / 1000 *
Ra.unlocks.continuousTTBoost.effects.autoPrestige.effectOrDefault(1),
formatEffect: value => `${formatPercents(value, 2)}`
}
},
skipReset1: {
id: "skipReset1",
cost: 20,
description: () =>
`Start every reset with ${formatInt(1)} Dimension Boost, automatically unlocking the 5th Antimatter Dimension`,
},
skipReset2: {
id: "skipReset2",
cost: 40,
description: () =>
`Start every reset with ${formatInt(2)} Dimension Boosts, automatically unlocking the 6th Antimatter Dimension`,
},
skipReset3: {
id: "skipReset3",
cost: 80,
description: () =>
`Start every reset with ${formatInt(3)} Dimension Boosts, automatically unlocking the 7th Antimatter Dimension`,
},
skipResetGalaxy: {
id: "skipResetGalaxy",
cost: 300,
description: () =>
`Start every reset with ${formatInt(4)} Dimension Boosts, automatically unlocking the 8th Antimatter Dimension;
and an Antimatter Galaxy`,
},
ipOffline: {
id: "ipOffline",
cost: 1000,
description: () => (player.options.offlineProgress
? `Only while offline, gain ${formatPercents(0.5)} of your best IP/min without using Max All`
: "This upgrade would give offline Infinity Point generation, but offline progress is currently disabled"),
effect: () => (player.options.offlineProgress
? player.records.thisEternity.bestIPMsWithoutMaxAll.times(TimeSpan.fromMinutes(1).totalMilliseconds / 2)
: DC.D0),
isDisabled: () => !player.options.offlineProgress,
formatEffect: value => `${format(value, 2, 2)} IP/min`,
},
ipMult: {
id: "ipMult",
cost: () => InfinityUpgrade.ipMult.cost,
costCap: DC.E6E6,
costIncreaseThreshold: DC.E3E6,
description: () => (Pelle.isDoomed
? "This upgrade has no effect while in Doomed"
: `Multiply Infinity Points from all sources by ${formatX(2)}`),
// Normally the multiplier caps at e993k or so with 3300000 purchases, but if the cost is capped then we just give
// an extra e7k to make the multiplier look nice
effect: () => (player.IPMultPurchases >= 3300000 ? DC.E1E6 : DC.D2.pow(player.IPMultPurchases)),
cap: () => Effarig.eternityCap ?? DC.E1E6,
formatEffect: value => formatX(value, 2, 2),
function dimInfinityMult() {
return Currency.infinitiesTotal.value.times(0.2).plus(1);
}
function chargedDimInfinityMult() {
return 1 + Math.log10(Math.max(1, Currency.infinitiesTotal.value.pLog10())) * Math.sqrt(Ra.pets.teresa.level) / 150;
}
GameDatabase.infinity.upgrades = {
totalTimeMult: {
id: "timeMult",
cost: 1,
description: "Antimatter Dimensions gain a multiplier based on time played",
effect: () => Math.pow(Time.totalTimePlayed.totalMinutes / 2, 0.15),
formatEffect: value => formatX(value, 2, 2),
charged: {
description: "Antimatter Dimensions gain a power effect based on time played and Teresa level",
effect: () => 1 +
Math.log10(Math.log10(Time.totalTimePlayed.totalMilliseconds)) *
Math.pow(Ra.pets.teresa.level, 0.5) / 150,
formatEffect: value => formatPow(value, 4, 4)
}
};
}());
},
dim18mult: {
id: "18Mult",
cost: 1,
checkRequirement: () => InfinityUpgrade.totalTimeMult.isBought,
description: "1st and 8th Antimatter Dimensions gain a multiplier based on Infinities",
effect: () => dimInfinityMult(),
formatEffect: value => formatX(value, 1, 1),
charged: {
description: "1st and 8th Antimatter Dimensions gain a power effect based on Infinities and Teresa level",
effect: () => chargedDimInfinityMult(),
formatEffect: value => formatPow(value, 4, 4)
}
},
dim27mult: {
id: "27Mult",
cost: 1,
checkRequirement: () => InfinityUpgrade.buy10Mult.isBought,
description: "2nd and 7th Antimatter Dimensions gain a multiplier based on Infinities",
effect: () => dimInfinityMult(),
formatEffect: value => formatX(value, 1, 1),
charged: {
description: "2nd and 7th Antimatter Dimensions gain a power effect based on Infinities and Teresa level",
effect: () => chargedDimInfinityMult(),
formatEffect: value => formatPow(value, 4, 4)
}
},
dim36mult: {
id: "36Mult",
cost: 1,
checkRequirement: () => InfinityUpgrade.dim18mult.isBought,
description: "3rd and 6th Antimatter Dimensions gain a multiplier based on Infinities",
effect: () => dimInfinityMult(),
formatEffect: value => formatX(value, 1, 1),
charged: {
description: "3rd and 6th Antimatter Dimensions gain a power effect based on Infinities and Teresa level",
effect: () => chargedDimInfinityMult(),
formatEffect: value => formatPow(value, 4, 4)
}
},
dim45mult: {
id: "45Mult",
cost: 1,
checkRequirement: () => InfinityUpgrade.dim27mult.isBought,
description: "4th and 5th Antimatter Dimensions gain a multiplier based on Infinities",
effect: () => dimInfinityMult(),
formatEffect: value => formatX(value, 1, 1),
charged: {
description: "4th and 5th Antimatter Dimensions gain a power effect based on Infinities and Teresa level",
effect: () => chargedDimInfinityMult(),
formatEffect: value => formatPow(value, 4, 4)
}
},
resetBoost: {
id: "resetBoost",
cost: 1,
checkRequirement: () => InfinityUpgrade.dim36mult.isBought,
description: () =>
`Decrease the number of Dimensions needed for Dimension Boosts and Antimatter Galaxies by ${formatInt(9)}`,
effect: 9,
charged: {
description: () => "Decrease Dimension Boost requirement based on Teresa level",
effect: () => 1 / (1 + Math.sqrt(Ra.pets.teresa.level) / 10),
formatEffect: value => `${formatX(value, 4, 4)}`
}
},
buy10Mult: {
id: "dimMult",
cost: 1,
description: () => `Increase the multiplier for buying ${formatInt(10)} Antimatter Dimensions`,
effect: () => 1.1,
formatEffect: () => `${formatX(2, 0, 1)}${formatX(2.2, 0, 1)}`,
charged: {
description: () => `The multiplier for buying ${formatInt(10)} Antimatter Dimensions gains ` +
"a power effect based on Teresa level",
effect: () => 1 + Ra.pets.teresa.level / 200,
formatEffect: value => formatPow(value, 3, 3)
}
},
galaxyBoost: {
id: "galaxyBoost",
cost: 2,
checkRequirement: () => InfinityUpgrade.dim45mult.isBought,
description: "All Galaxies are twice as strong",
effect: 2,
charged: {
description: "All Galaxies are stronger based on Teresa level",
effect: () => 2 + Math.sqrt(Ra.pets.teresa.level) / 100,
formatEffect: value => `+${formatPercents(value - 1)}`
}
},
thisInfinityTimeMult: {
id: "timeMult2",
cost: 3,
description: "Antimatter Dimensions gain a multiplier based on time spent in current Infinity",
effect: () => Decimal.max(Math.pow(Time.thisInfinity.totalMinutes / 4, 0.25), 1),
formatEffect: value => formatX(value, 2, 2),
charged: {
description:
"Antimatter Dimensions gain a power effect based on time spent in current Infinity and Teresa level",
effect: () => 1 +
Math.log10(Math.log10(Time.thisInfinity.totalMilliseconds + 100)) *
Math.sqrt(Ra.pets.teresa.level) / 150,
formatEffect: value => formatPow(value, 4, 4)
}
},
unspentIPMult: {
id: "unspentBonus",
cost: 5,
checkRequirement: () => InfinityUpgrade.thisInfinityTimeMult.isBought,
description: "Multiplier to 1st Antimatter Dimension based on unspent Infinity Points",
effect: () => Currency.infinityPoints.value.dividedBy(2).pow(1.5).plus(1),
formatEffect: value => formatX(value, 2, 2),
charged: {
description: "Multiplier to 1st Antimatter Dimension based on unspent Infinity Points, powered by Teresa level",
effect: () => Currency.infinityPoints.value.dividedBy(2).pow(Math.sqrt(Ra.pets.teresa.level) * 1.5).plus(1),
formatEffect: value => formatX(value, 2, 2)
}
},
dimboostMult: {
id: "resetMult",
cost: 7,
checkRequirement: () => InfinityUpgrade.unspentIPMult.isBought,
description: "Increase Dimension Boost multiplier",
effect: () => 2.5,
formatEffect: () => `${formatX(2, 0, 1)}${formatX(2.5, 0, 1)}`,
charged: {
description: "Dimension Boost multiplier gains a power effect based on Teresa level",
effect: () => 1 + Ra.pets.teresa.level / 200,
formatEffect: value => formatPow(value, 3, 3)
}
},
ipGen: {
id: "passiveGen",
cost: 10,
checkRequirement: () => InfinityUpgrade.dimboostMult.isBought,
description: () => (Pelle.isDoomed
? "This upgrade has no effect while in Doomed"
: `Passively generate Infinity Points ${formatInt(10)} times slower than your fastest Infinity`),
// Cutting corners: this is not actual effect, but it is totalIPMult that is displyed on upgrade
effect: () => (Teresa.isRunning || V.isRunning || Pelle.isDoomed ? DC.D0 : GameCache.totalIPMult.value),
formatEffect: value => {
if (Teresa.isRunning || V.isRunning) return "Disabled in this reality";
if (Pelle.isDoomed) return "Disabled";
const income = format(value, 2, 0);
const period = player.records.bestInfinity.time >= 999999999999
? "∞"
: Time.bestInfinity.times(10).toStringShort();
return `${income} every ${period}`;
},
charged: {
description: () =>
`Gain a percentage of your Reality Machines gained on Reality each real-time second,
percent increases with Teresa level`,
effect: () => Math.sqrt(Ra.pets.teresa.level) / 1000 *
Ra.unlocks.continuousTTBoost.effects.autoPrestige.effectOrDefault(1),
formatEffect: value => `${formatPercents(value, 2)}`
}
},
skipReset1: {
id: "skipReset1",
cost: 20,
description: () =>
`Start every reset with ${formatInt(1)} Dimension Boost, automatically unlocking the 5th Antimatter Dimension`,
},
skipReset2: {
id: "skipReset2",
cost: 40,
checkRequirement: () => InfinityUpgrade.skipReset1.isBought,
description: () =>
`Start every reset with ${formatInt(2)} Dimension Boosts, automatically unlocking the 6th Antimatter Dimension`,
},
skipReset3: {
id: "skipReset3",
cost: 80,
checkRequirement: () => InfinityUpgrade.skipReset2.isBought,
description: () =>
`Start every reset with ${formatInt(3)} Dimension Boosts, automatically unlocking the 7th Antimatter Dimension`,
},
skipResetGalaxy: {
id: "skipResetGalaxy",
cost: 300,
checkRequirement: () => InfinityUpgrade.skipReset3.isBought,
description: () =>
`Start every reset with ${formatInt(4)} Dimension Boosts, automatically unlocking the 8th Antimatter Dimension;
and an Antimatter Galaxy`,
},
ipOffline: {
id: "ipOffline",
cost: 1000,
checkRequirement: () => Achievement(41).isUnlocked,
description: () => (player.options.offlineProgress
? `Only while offline, gain ${formatPercents(0.5)} of your best IP/min without using Max All`
: "This upgrade would give offline Infinity Point generation, but offline progress is currently disabled"),
effect: () => (player.options.offlineProgress
? player.records.thisEternity.bestIPMsWithoutMaxAll.times(TimeSpan.fromMinutes(1).totalMilliseconds / 2)
: DC.D0),
isDisabled: () => !player.options.offlineProgress,
formatEffect: value => `${format(value, 2, 2)} IP/min`,
},
ipMult: {
id: "ipMult",
cost: () => InfinityUpgrade.ipMult.cost,
checkRequirement: () => Achievement(41).isUnlocked,
costCap: DC.E6E6,
costIncreaseThreshold: DC.E3E6,
description: () => (Pelle.isDoomed
? "This upgrade has no effect while in Doomed"
: `Multiply Infinity Points from all sources by ${formatX(2)}`),
// Normally the multiplier caps at e993k or so with 3300000 purchases, but if the cost is capped then we just give
// an extra e7k to make the multiplier look nice
effect: () => (player.IPMultPurchases >= 3300000 ? DC.E1E6 : DC.D2.pow(player.IPMultPurchases)),
cap: () => Effarig.eternityCap ?? DC.E1E6,
formatEffect: value => formatX(value, 2, 2),
}
};

View File

@ -915,7 +915,7 @@ GameDatabase.news = [
id: "a174",
text:
`<span style='font-family: runescape; color: yellow; text-shadow: 0.1rem 0.1rem black; letter-spacing: 0.1rem;
font-size: 2rem; line-height: 0; animation: text-flash 1s steps(1, end) infinite;'
font-size: 2rem; line-height: 0; animation: a-text-flash 1s steps(1, end) infinite;'
>FREE RUNE ARMOR TRIMMING</span>`,
},
{
@ -992,12 +992,12 @@ GameDatabase.news = [
{
id: "a184",
text:
`<span style='animation: text-grow 1s infinite'>R̵̬̙͋͂̀̋͑̈́̇͠Ê̵͇͎͂̂̍̓̌̐̋̋̀̀̔M̶̨̲̯̘͙̬̥̮̣͚̱̫͛̽̃͌̚͝
"Ą̴͍̝͐Į̷̛̲̯̫̘͌́̄̏͌̀̈́͝͝Ṅ̶̛̻̠̠̤̦̞̞͗̎̊̌̊͝͠</span><span style='animation: text-shrink 1s infinite'>
`<span style='animation: a-text-grow 1s infinite'>R̵̬̙͋͂̀̋͑̈́̇͠Ê̵͇͎͂̂̍̓̌̐̋̋̀̀̔M̶̨̲̯̘͙̬̥̮̣͚̱̫͛̽̃͌̚͝
"Ą̴͍̝͐Į̷̛̲̯̫̘͌́̄̏͌̀̈́͝͝Ṅ̶̛̻̠̠̤̦̞̞͗̎̊̌̊͝͠</span><span style='animation: a-text-shrink 1s infinite'>
Ḁ̷̛͂̈́͗̎̃̓͛́͘ͅW̶̡̖͓̗̦̃̇̌̀͝A̵͇̭͉̓̎̈̿̊́̄̚͜R̶̝͚̲̭͎͇͎͓͖͚͇̀̈́͗̃̏̂̌͝͝Ę̴̡̤͙͈̝̬̰͒͘</span><span style
='animation: text-grow 1s infinite'> ̶̺̈́́̆̓͘͘Ồ̸̢̢̮͓̯̗͙͚̬̉͊̿F̶̠̤̱̱̱͊̂̍̔̃͆̆̑̿͘</span><span style='animation:
text-shrink 1s infinite'> ̴̨̞̠̮͚̱͉͋̔͗̽̈́́́̅ͅỴ̶̣̙̹͚̲͔̲̼̬̥̀͌̒̾͘͘O̵̪̠̗̝̗̘̜͚̮̊͒͆̃̀̌̒͝ͅU̸͎͗̍̑̎̅̅͝R̵̗͑̽̏̓͆͒̈́͌͘̕
</span><span style='animation: text-grow 1s infinite'> ̸̑̽̇̆͊̔̍̊̈́̈́͘ͅS̸̘͐͝U̴̥̭̚͘R̸̖̜͍͒́̋͆̈́̓
='animation: a-text-grow 1s infinite'> ̶̺̈́́̆̓͘͘Ồ̸̢̢̮͓̯̗͙͚̬̉͊̿F̶̠̤̱̱̱͊̂̍̔̃͆̆̑̿͘</span><span style='animation:
a-text-shrink 1s infinite'> ̴̨̞̠̮͚̱͉͋̔͗̽̈́́́̅ͅỴ̶̣̙̹͚̲͔̲̼̬̥̀͌̒̾͘͘O̵̪̠̗̝̗̘̜͚̮̊͒͆̃̀̌̒͝ͅU̸͎͗̍̑̎̅̅͝R̵̗͑̽̏̓͆͒̈́͌͘̕
</span><span style='animation: a-text-grow 1s infinite'> ̸̑̽̇̆͊̔̍̊̈́̈́͘ͅS̸̘͐͝U̴̥̭̚͘R̸̖̜͍͒́̋͆̈́̓
R̸̡̛̛̪̝̟̱̣̹̭̟̣̀̈̀̏̉̌͝͠Õ̶͙͈͖̠͇̬͍̟̰U̵̩̫͉̝͔̼͎̦̔̓̽͌͊̏̇̓̀̓̀Ņ̸͍͇̘̙̥̰͉̲͕͈̥̍͛̃̑͝Ḑ̵̤̻̖̱̘̯̝̖̈̌̄̕͝
Ī̶̜̱̈́̑̃̉̄̋̔͐͋͠Ṅ̴͎̞͍̽͊͛̈́̅͛̈̅̚͠Ģ̸̢̾͊S̷̫̼̜̼͇̋͛̎͑͆̅̓̇</span>`,
},
@ -1014,10 +1014,10 @@ GameDatabase.news = [
{
id: "a186",
text:
`<span style='animation: text-shrink 1s infinite'>/(^_^)/</span> <span style='animation: text-grow 1s infinite
'>\\(^_^)\\</span> <span style='animation: text-shrink 1s infinite'>/(^_^)/</span> <span style='animation:
text-grow 1s infinite'>\\(^_^)\\</span> <span style='animation: text-shrink 1s infinite'>/(^_^)/</span> <span
style='animation: text-grow 1s infinite'>\\(^_^)\\</span>`,
`<span style='animation: a-text-shrink 1s infinite'>/(^_^)/</span> <span style='animation: a-text-grow 1s infinite
'>\\(^_^)\\</span> <span style='animation: a-text-shrink 1s infinite'>/(^_^)/</span> <span style='animation:
a-text-grow 1s infinite'>\\(^_^)\\</span> <span style='animation: a-text-shrink 1s infinite'>/(^_^)/</span> <span
style='animation: a-text-grow 1s infinite'>\\(^_^)\\</span>`,
},
{
id: "a187",
@ -1083,7 +1083,7 @@ GameDatabase.news = [
random *= 255;
const color = `hsl(${random}, 90%, 60%)`;
return `<span style='color: ${color}; text-shadow: 0 0 0.5rem ${color};
animation: text-grow 0.4s infinite;'>Disco Time!</span>`;
animation: a-text-grow 0.4s infinite;'>Disco Time!</span>`;
},
},
{
@ -1352,8 +1352,8 @@ GameDatabase.news = [
id: "a238",
get text() {
return `AD Player: "How many orders of magnitude are you on?" Normal person: "Like, maybe 5 or 6 right now, my
dude." AD Player: "You are like a little baby. Watch this: <span style='animation: text-crunch ${newsAnimSpd(22)}s
1; font-size: 0;'>C R O N C H</span>"`;
dude." AD Player: "You are like a little baby. Watch this: <span style='animation: a-text-crunch
${newsAnimSpd(22)}s 1; font-size: 0;'>C R O N C H</span>"`;
},
},
{
@ -1441,7 +1441,7 @@ GameDatabase.news = [
},
{
id: "a246",
text: "<span style='animation: fade-out 3s infinite'>OoooOOOOooOOO, it's me, the infamous news ghost!</span>",
text: "<span style='animation: a-fade-out 3s infinite'>OoooOOOOooOOO, it's me, the infamous news ghost!</span>",
},
(function() {
let isFlipped = false;
@ -1505,7 +1505,7 @@ GameDatabase.news = [
{
id: "a252",
get text() {
return `<span style='animation: text-stretch ${newsAnimSpd(30)}s 1'>This message is dilated.</span>`;
return `<span style='animation: a-text-stretch ${newsAnimSpd(30)}s 1'>This message is dilated.</span>`;
},
},
{
@ -2256,7 +2256,7 @@ GameDatabase.news = [
{
id: "a352",
get text() {
return `<span style='opacity: 0; animation: disappear ${newsAnimSpd(20)}s 1'>
return `<span style='opacity: 0; animation: a-disappear ${newsAnimSpd(20)}s 1'>
This news message is antimemetic. You will forget that it exists shortly.</span>`;
}
},

View File

@ -1,7 +1,7 @@
import { GameDatabase } from "../game-database";
GameDatabase.reality.glyphSacrifice = [
{
GameDatabase.reality.glyphSacrifice = {
"power": {
id: "power",
effect: added => {
if (Pelle.isDisabled("glyphsac")) return 0;
@ -19,7 +19,8 @@ GameDatabase.reality.glyphSacrifice = [
: "";
return `Distant Galaxy scaling starts ${formatInt(amount)} later${nextGalaxyText}`;
}
}, {
},
"infinity": {
id: "infinity",
effect: added => {
if (Pelle.isDisabled("glyphsac")) return 1;
@ -31,7 +32,8 @@ GameDatabase.reality.glyphSacrifice = [
if (Pelle.isDisabled("glyphsac")) return `Glyph Sacrifice is disabled in Pelle`;
return `${formatX(amount, 2, 2)} bigger multiplier when buying 8th Infinity Dimension.`;
}
}, {
},
"time": {
id: "time",
effect: added => {
if (Pelle.isDisabled("glyphsac")) return 1;
@ -43,7 +45,8 @@ GameDatabase.reality.glyphSacrifice = [
if (Pelle.isDisabled("glyphsac")) return `Glyph Sacrifice is disabled in Pelle`;
return `${formatX(amount, 2, 2)} bigger multiplier when buying 8th Time Dimension.`;
}
}, {
},
"replication": {
id: "replication",
effect: added => {
if (Pelle.isDisabled("glyphsac")) return 0;
@ -61,7 +64,8 @@ GameDatabase.reality.glyphSacrifice = [
: "";
return `Replicanti Galaxy scaling starts ${formatInt(amount)} later${nextGalaxyText}`;
}
}, {
},
"dilation": {
id: "dilation",
effect: added => {
if (Pelle.isDisabled("glyphsac")) return 1;
@ -75,7 +79,8 @@ GameDatabase.reality.glyphSacrifice = [
if (Pelle.isDisabled("glyphsac")) return `Glyph Sacrifice is disabled in Pelle`;
return `Multiply Tachyon Particle gain by ${formatX(amount, 2, 2)}`;
}
}, {
},
"effarig": {
id: "effarig",
effect: added => {
if (Pelle.isDisabled("glyphsac")) return 0;
@ -87,7 +92,8 @@ GameDatabase.reality.glyphSacrifice = [
if (Pelle.isDisabled("glyphsac")) return `Glyph Sacrifice is disabled in Pelle`;
return `+${formatPercents(amount / 100, 2)} additional Glyph rarity`;
}
}, {
},
"reality": {
id: "reality",
effect: added => {
if (Pelle.isDisabled("glyphsac")) return 0;
@ -99,4 +105,4 @@ GameDatabase.reality.glyphSacrifice = [
return `${formatPercents(amount - 1, 2)} increased Alchemy yield`;
}
}
].mapToObject(g => g.id, g => g);
};

View File

@ -1,293 +1,292 @@
import { DC } from "../../constants";
import { GameDatabase } from "../game-database";
GameDatabase.reality.imaginaryUpgrades = (function() {
const rebuyable = props => {
props.cost = () => props.initialCost * Math.pow(props.costMult, player.reality.imaginaryRebuyables[props.id]);
const { effect } = props;
if (props.isDecimal) props.effect = () => Decimal.pow(effect, player.reality.imaginaryRebuyables[props.id]);
else props.effect = () => effect * player.reality.imaginaryRebuyables[props.id];
if (!props.formatEffect) props.formatEffect = value => `+${format(value, 2, 2)}`;
props.formatCost = value => format(value, 2, 0);
return props;
};
return [
rebuyable({
name: "Temporal Intensifier",
id: 1,
initialCost: 3,
costMult: 60,
description: () => `Increase Temporal Amplifier multiplier by +${format(0.15, 2, 2)}`,
effect: 0.15
}),
rebuyable({
name: "Replicative Intensifier",
id: 2,
initialCost: 4,
costMult: 60,
description: () => `Increase Replicative Amplifier multiplier by +${format(0.15, 2, 2)}`,
effect: 0.15
}),
rebuyable({
name: "Eternal Intensifier",
id: 3,
initialCost: 1,
costMult: 40,
description: () => `Increase Eternal Amplifier multiplier by +${format(0.4, 2, 2)}`,
effect: 0.4
}),
rebuyable({
name: "Superluminal Intensifier",
id: 4,
initialCost: 5,
costMult: 80,
description: () => `Increase Superluminal Amplifier multiplier by +${format(0.15, 2, 2)}`,
effect: 0.15
}),
rebuyable({
name: "Boundless Intensifier",
id: 5,
initialCost: 1,
costMult: 30,
description: () => `Increase Boundless Amplifier multiplier by +${format(0.6, 2, 2)}`,
effect: 0.6
}),
rebuyable({
name: "Elliptic Materiality",
id: 6,
initialCost: 1e4,
costMult: 500,
description: () => `Increase the Reality Machine cap by ${formatX(1e100)}`,
effect: 1e100,
formatEffect: value => `${formatX(value)}`,
isDecimal: true
}),
rebuyable({
name: "Runic Assurance",
id: 7,
initialCost: 2e5,
costMult: 500,
description: () => `Delay Glyph Instability starting level by ${formatInt(200)}`,
effect: 200,
formatEffect: value => `+${formatInt(value)} levels`
}),
rebuyable({
name: "Hyperbolic Apeirogon",
id: 8,
initialCost: 1e7,
costMult: 800,
description: () => `Multiply Infinity Dimensions by ${format("1e100000")}`,
effect: DC.E100000,
formatEffect: value => `${formatX(value)}`,
isDecimal: true
}),
rebuyable({
name: "Cosmic Filament",
id: 9,
initialCost: 1e9,
costMult: 1000,
description: () => `Increase Galaxy strength`,
effect: 0.03,
formatEffect: value => `+${formatPercents(value)}`
}),
rebuyable({
name: "Entropic Condensing",
id: 10,
initialCost: 8e9,
costMult: 2000,
description: () => `Increase Singularity gain`,
effect: 1,
formatEffect: value => `${formatX(1 + value, 2)}`,
}),
{
name: "Suspicion of Interference",
id: 11,
cost: 5e7,
requirement: () => `${format(1e90)} total Relic Shards
(You have ${format(player.celestials.effarig.relicShards, 2)})`,
hasFailed: () => false,
checkRequirement: () => player.celestials.effarig.relicShards >= 1e90,
checkEvent: GAME_EVENT.REALITY_RESET_AFTER,
description: "Time Dimension power based on total antimatter",
effect: () => 1 + Math.log10(player.records.totalAntimatter.log10()) / 100,
formatEffect: value => `${formatPow(value, 0, 4)}`,
},
{
name: "Consequences of Illusions",
id: 12,
cost: 5e7,
requirement: () => `Make a level ${formatInt(9000)} Glyph with a single Glyph level factor weight at
${formatInt(100)}`,
hasFailed: () => false,
checkRequirement: () => Object.values(player.celestials.effarig.glyphWeights).some(w => w === 100) &&
gainedGlyphLevel().actualLevel >= 9000,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Gain free Dimboosts based on Imaginary rebuyable count",
effect: () => 2e4 * ImaginaryUpgrades.totalRebuyables,
formatEffect: value => `${format(value, 1)}`,
},
{
name: "Transience of Information",
id: 13,
cost: 5e7,
requirement: () => `Reach ${format(Number.MAX_VALUE, 2)} projected Reality Machines within
The Enslaved Ones' Reality`,
hasFailed: () => !Enslaved.isRunning,
checkRequirement: () => Enslaved.isRunning && MachineHandler.uncappedRM.gte(Number.MAX_VALUE),
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Increase Imaginary Machine Cap based on Imaginary Upgrades purchased",
effect: () => 1 + ImaginaryUpgrades.totalRebuyables / 20 + ImaginaryUpgrades.totalSinglePurchase / 2,
formatEffect: value => `${formatX(value, 2, 1)}`,
},
{
name: "Recollection of Intrusion",
id: 14,
cost: 3.5e8,
requirement: () => `Reach a tickspeed of ${format("1e75000000000")} / sec within Eternity Challenge 5`,
hasFailed: () => false,
checkRequirement: () => EternityChallenge(5).isRunning && Tickspeed.perSecond.exponent >= 7.5e10,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: () => `Raise all Dimension per-purchase multipliers to ${formatPow(1.5, 0, 1)}`,
effect: 1.5
},
{
name: "Fabrication of Ideals",
id: 15,
cost: 1e9,
requirement: () => `Reach ${format("1e1500000000000")} antimatter without
ever having any 1st Infinity Dimensions`,
hasFailed: () => player.requirementChecks.reality.maxID1.gt(0),
checkRequirement: () => player.requirementChecks.reality.maxID1.eq(0) && player.antimatter.exponent >= 1.5e12,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Convert Antimatter Dimensions to Continuum and unlock Lai'tela, Celestial of Dimensions",
},
{
name: "Massless Momentum",
id: 16,
cost: 3.5e9,
formatCost: x => format(x, 1),
requirement: () => `Destabilize Lai'tela's Reality in under ${formatInt(30)} seconds twice`,
hasFailed: () => false,
checkRequirement: () => Laitela.maxAllowedDimension <= 6,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Unlock the 2nd Dark Matter Dimension",
},
{
name: "Chiral Oscillation",
id: 17,
cost: 6e9,
requirement: () => `Automatically condense at least ${formatInt(20)} Singularities at once`,
hasFailed: () => false,
checkRequirement: () => Singularity.singularitiesGained >= 20 &&
Currency.darkEnergy.gte(Singularity.cap * SingularityMilestone.autoCondense.effectValue),
checkEvent: GAME_EVENT.SINGULARITY_RESET_BEFORE,
description: "Unlock the 3rd Dark Matter Dimension",
},
{
name: "Dimensional Symmetry",
id: 18,
cost: 1.5e10,
formatCost: x => format(x, 1),
requirement: () => `Have ${formatInt(80000)} total Galaxies`,
hasFailed: () => false,
checkRequirement: () => Replicanti.galaxies.total + player.galaxies +
player.dilation.totalTachyonGalaxies >= 80000,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Unlock the 4th Dark Matter Dimension",
},
{
name: "Deterministic Radiation",
id: 19,
cost: 2.8e10,
formatCost: x => format(x, 1),
requirement: () => `Reach ${formatInt(3.85e6)} Tickspeed Continuum without ever having more than
${formatInt(8)} Time Studies in this Reality`,
hasFailed: () => player.requirementChecks.reality.maxStudies > 8,
checkRequirement: () => player.requirementChecks.reality.maxStudies <= 8 &&
Tickspeed.continuumValue >= 3.85e6,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Unlock Dark Matter Annihilation",
},
{
name: "Vacuum Acceleration",
id: 20,
cost: 3e12,
requirement: () => `Have a Continuum increase of at least ${formatPercents(1)}`,
hasFailed: () => false,
checkRequirement: () => Laitela.matterExtraPurchaseFactor >= 2,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: () => `Unlock Autobuyers for repeatable Imaginary Upgrades and generate Imaginary Machines
${formatInt(10)} times faster`,
effect: 10,
},
{
name: "Existential Elimination",
id: 21,
cost: 1e13,
requirement: () => `Reach ${format("1e7400000000000")} antimatter with Continuum disabled`,
hasFailed: () => !player.requirementChecks.reality.noContinuum,
checkRequirement: () => player.requirementChecks.reality.noContinuum &&
Currency.antimatter.value.log10() >= 7.4e12,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Annihilation multiplier gain is improved based on Imaginary Machines",
effect: () => Math.clampMin(Math.pow(Math.log10(Currency.imaginaryMachines.value) - 10, 3), 1),
formatEffect: value => `${formatX(value, 2, 1)}`,
},
{
name: "Total Termination",
id: 22,
cost: 1.5e14,
formatCost: x => format(x, 1),
requirement: () => `Reach ${format("1e150000000000")} antimatter in Effarig's Reality with
at least ${formatInt(4)} Cursed Glyphs equipped`,
// Note: 4 cursed glyphs is -12 glyph count, but equipping a positive glyph in the last slot is allowed
hasFailed: () => !Effarig.isRunning || player.requirementChecks.reality.maxGlyphs > -10,
checkRequirement: () => Effarig.isRunning && player.requirementChecks.reality.maxGlyphs < -10 &&
Currency.antimatter.value.exponent >= 1.5e11,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: () => `Glyph Sacrifice totals for basic Glyphs are increased to ${format(1e100)}`,
effect: 1e100,
},
{
name: "Planar Purification",
id: 23,
cost: 6e14,
requirement: () => `Reach Glyph level ${formatInt(20000)} in Ra's Reality with
at most ${formatInt(0)} Glyphs equipped`,
hasFailed: () => !Ra.isRunning || player.requirementChecks.reality.maxGlyphs > 0,
checkRequirement: () => Ra.isRunning && player.requirementChecks.reality.maxGlyphs <= 0 &&
gainedGlyphLevel().actualLevel >= 20000,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Increase free Dimboost count based on Tesseract count",
effect: () => Math.floor(0.25 * Math.pow(Tesseracts.effectiveCount, 2)),
formatEffect: value => `${formatX(value)}`,
},
{
name: "Absolute Annulment",
id: 24,
cost: 6e14,
requirement: () => `Have ${formatInt(13000)} Antimatter Galaxies in Ra's Reality
with a fully inverted Black Hole`,
hasFailed: () => !Ra.isRunning || player.requirementChecks.reality.slowestBH > 1e-300,
checkRequirement: () => Ra.isRunning && player.requirementChecks.reality.slowestBH <= 1e-300 &&
player.galaxies >= 13000,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Increase free Dimboost strength based on Singularity count",
effect: () => Decimal.pow(player.celestials.laitela.singularities, 300),
formatEffect: value => `${formatX(value, 2, 1)}`,
},
{
name: "Omnipresent Obliteration",
id: 25,
cost: 1.6e15,
formatCost: x => format(x, 1),
requirement: () => `Reach Reality in Lai'tela's Reality with all Dimensions disabled and
at least ${formatInt(4)} empty Glyph slots`,
hasFailed: () => !Laitela.isRunning || Laitela.maxAllowedDimension !== 0 || Glyphs.activeList.length > 1,
checkRequirement: () => Laitela.isRunning && Laitela.maxAllowedDimension === 0 &&
Glyphs.activeList.length <= 1,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Unlock Pelle, Celestial of Antimatter",
},
];
}());
const rebuyable = props => {
props.cost = () => props.initialCost * Math.pow(props.costMult, player.reality.imaginaryRebuyables[props.id]);
const { effect } = props;
if (props.isDecimal) props.effect = () => Decimal.pow(effect, player.reality.imaginaryRebuyables[props.id]);
else props.effect = () => effect * player.reality.imaginaryRebuyables[props.id];
if (!props.formatEffect) props.formatEffect = value => `+${format(value, 2, 2)}`;
props.formatCost = value => format(value, 2, 0);
return props;
};
GameDatabase.reality.imaginaryUpgrades = [
rebuyable({
name: "Temporal Intensifier",
id: 1,
initialCost: 3,
costMult: 60,
description: () => `Increase Temporal Amplifier multiplier by +${format(0.15, 2, 2)}`,
effect: 0.15
}),
rebuyable({
name: "Replicative Intensifier",
id: 2,
initialCost: 4,
costMult: 60,
description: () => `Increase Replicative Amplifier multiplier by +${format(0.15, 2, 2)}`,
effect: 0.15
}),
rebuyable({
name: "Eternal Intensifier",
id: 3,
initialCost: 1,
costMult: 40,
description: () => `Increase Eternal Amplifier multiplier by +${format(0.4, 2, 2)}`,
effect: 0.4
}),
rebuyable({
name: "Superluminal Intensifier",
id: 4,
initialCost: 5,
costMult: 80,
description: () => `Increase Superluminal Amplifier multiplier by +${format(0.15, 2, 2)}`,
effect: 0.15
}),
rebuyable({
name: "Boundless Intensifier",
id: 5,
initialCost: 1,
costMult: 30,
description: () => `Increase Boundless Amplifier multiplier by +${format(0.6, 2, 2)}`,
effect: 0.6
}),
rebuyable({
name: "Elliptic Materiality",
id: 6,
initialCost: 1e4,
costMult: 500,
description: () => `Increase the Reality Machine cap by ${formatX(1e100)}`,
effect: 1e100,
formatEffect: value => `${formatX(value)}`,
isDecimal: true
}),
rebuyable({
name: "Runic Assurance",
id: 7,
initialCost: 2e5,
costMult: 500,
description: () => `Delay Glyph Instability starting level by ${formatInt(200)}`,
effect: 200,
formatEffect: value => `+${formatInt(value)} levels`
}),
rebuyable({
name: "Hyperbolic Apeirogon",
id: 8,
initialCost: 1e7,
costMult: 800,
description: () => `Multiply Infinity Dimensions by ${format("1e100000")}`,
effect: DC.E100000,
formatEffect: value => `${formatX(value)}`,
isDecimal: true
}),
rebuyable({
name: "Cosmic Filament",
id: 9,
initialCost: 1e9,
costMult: 1000,
description: () => `Increase Galaxy strength`,
effect: 0.03,
formatEffect: value => `+${formatPercents(value)}`
}),
rebuyable({
name: "Entropic Condensing",
id: 10,
initialCost: 8e9,
costMult: 2000,
description: () => `Increase Singularity gain`,
effect: 1,
formatEffect: value => `${formatX(1 + value, 2)}`,
}),
{
name: "Suspicion of Interference",
id: 11,
cost: 5e7,
requirement: () => `${format(1e90)} total Relic Shards
(You have ${format(player.celestials.effarig.relicShards, 2)})`,
hasFailed: () => false,
checkRequirement: () => player.celestials.effarig.relicShards >= 1e90,
checkEvent: GAME_EVENT.REALITY_RESET_AFTER,
description: "Time Dimension power based on total antimatter",
effect: () => 1 + Math.log10(player.records.totalAntimatter.log10()) / 100,
formatEffect: value => `${formatPow(value, 0, 4)}`,
},
{
name: "Consequences of Illusions",
id: 12,
cost: 5e7,
requirement: () => `Make a level ${formatInt(9000)} Glyph with a single Glyph level factor weight at
${formatInt(100)}`,
hasFailed: () => false,
checkRequirement: () => Object.values(player.celestials.effarig.glyphWeights).some(w => w === 100) &&
gainedGlyphLevel().actualLevel >= 9000,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Gain free Dimboosts based on Imaginary rebuyable count",
effect: () => 2e4 * ImaginaryUpgrades.totalRebuyables,
formatEffect: value => `${format(value, 1)}`,
},
{
name: "Transience of Information",
id: 13,
cost: 5e7,
requirement: () => `Reach ${format(Number.MAX_VALUE, 2)} projected Reality Machines within
The Enslaved Ones' Reality`,
hasFailed: () => !Enslaved.isRunning,
checkRequirement: () => Enslaved.isRunning && MachineHandler.uncappedRM.gte(Number.MAX_VALUE),
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Increase Imaginary Machine Cap based on Imaginary Upgrades purchased",
effect: () => 1 + ImaginaryUpgrades.totalRebuyables / 20 + ImaginaryUpgrades.totalSinglePurchase / 2,
formatEffect: value => `${formatX(value, 2, 1)}`,
},
{
name: "Recollection of Intrusion",
id: 14,
cost: 3.5e8,
requirement: () => `Reach a tickspeed of ${format("1e75000000000")} / sec within Eternity Challenge 5`,
hasFailed: () => false,
checkRequirement: () => EternityChallenge(5).isRunning && Tickspeed.perSecond.exponent >= 7.5e10,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: () => `Raise all Dimension per-purchase multipliers to ${formatPow(1.5, 0, 1)}`,
effect: 1.5
},
{
name: "Fabrication of Ideals",
id: 15,
cost: 1e9,
requirement: () => `Reach ${format("1e1500000000000")} antimatter without
ever having any 1st Infinity Dimensions`,
hasFailed: () => player.requirementChecks.reality.maxID1.gt(0),
checkRequirement: () => player.requirementChecks.reality.maxID1.eq(0) && player.antimatter.exponent >= 1.5e12,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Convert Antimatter Dimensions to Continuum and unlock Lai'tela, Celestial of Dimensions",
},
{
name: "Massless Momentum",
id: 16,
cost: 3.5e9,
formatCost: x => format(x, 1),
requirement: () => `Destabilize Lai'tela's Reality in under ${formatInt(30)} seconds twice`,
hasFailed: () => false,
checkRequirement: () => Laitela.maxAllowedDimension <= 6,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Unlock the 2nd Dark Matter Dimension",
},
{
name: "Chiral Oscillation",
id: 17,
cost: 6e9,
requirement: () => `Automatically condense at least ${formatInt(20)} Singularities at once`,
hasFailed: () => false,
checkRequirement: () => Singularity.singularitiesGained >= 20 &&
Currency.darkEnergy.gte(Singularity.cap * SingularityMilestone.autoCondense.effectValue),
checkEvent: GAME_EVENT.SINGULARITY_RESET_BEFORE,
description: "Unlock the 3rd Dark Matter Dimension",
},
{
name: "Dimensional Symmetry",
id: 18,
cost: 1.5e10,
formatCost: x => format(x, 1),
requirement: () => `Have ${formatInt(80000)} total Galaxies`,
hasFailed: () => false,
checkRequirement: () => Replicanti.galaxies.total + player.galaxies +
player.dilation.totalTachyonGalaxies >= 80000,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Unlock the 4th Dark Matter Dimension",
},
{
name: "Deterministic Radiation",
id: 19,
cost: 2.8e10,
formatCost: x => format(x, 1),
requirement: () => `Reach ${formatInt(3.85e6)} Tickspeed Continuum without ever having more than
${formatInt(8)} Time Studies in this Reality`,
hasFailed: () => player.requirementChecks.reality.maxStudies > 8,
checkRequirement: () => player.requirementChecks.reality.maxStudies <= 8 &&
Tickspeed.continuumValue >= 3.85e6,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Unlock Dark Matter Annihilation",
},
{
name: "Vacuum Acceleration",
id: 20,
cost: 3e12,
requirement: () => `Have a Continuum increase of at least ${formatPercents(1)}`,
hasFailed: () => false,
checkRequirement: () => Laitela.matterExtraPurchaseFactor >= 2,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: () => `Unlock Autobuyers for repeatable Imaginary Upgrades and generate Imaginary Machines
${formatInt(10)} times faster`,
effect: 10,
},
{
name: "Existential Elimination",
id: 21,
cost: 1e13,
requirement: () => `Reach ${format("1e7400000000000")} antimatter with Continuum disabled`,
hasFailed: () => !player.requirementChecks.reality.noContinuum,
checkRequirement: () => player.requirementChecks.reality.noContinuum &&
Currency.antimatter.value.log10() >= 7.4e12,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Annihilation multiplier gain is improved based on Imaginary Machines",
effect: () => Math.clampMin(Math.pow(Math.log10(Currency.imaginaryMachines.value) - 10, 3), 1),
formatEffect: value => `${formatX(value, 2, 1)}`,
},
{
name: "Total Termination",
id: 22,
cost: 1.5e14,
formatCost: x => format(x, 1),
requirement: () => `Reach ${format("1e150000000000")} antimatter in Effarig's Reality with
at least ${formatInt(4)} Cursed Glyphs equipped`,
// Note: 4 cursed glyphs is -12 glyph count, but equipping a positive glyph in the last slot is allowed
hasFailed: () => !Effarig.isRunning || player.requirementChecks.reality.maxGlyphs > -10,
checkRequirement: () => Effarig.isRunning && player.requirementChecks.reality.maxGlyphs < -10 &&
Currency.antimatter.value.exponent >= 1.5e11,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: () => `Glyph Sacrifice totals for basic Glyphs are increased to ${format(1e100)}`,
effect: 1e100,
},
{
name: "Planar Purification",
id: 23,
cost: 6e14,
requirement: () => `Reach Glyph level ${formatInt(20000)} in Ra's Reality with
at most ${formatInt(0)} Glyphs equipped`,
hasFailed: () => !Ra.isRunning || player.requirementChecks.reality.maxGlyphs > 0,
checkRequirement: () => Ra.isRunning && player.requirementChecks.reality.maxGlyphs <= 0 &&
gainedGlyphLevel().actualLevel >= 20000,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Increase free Dimboost count based on Tesseract count",
effect: () => Math.floor(0.25 * Math.pow(Tesseracts.effectiveCount, 2)),
formatEffect: value => `${formatX(value)}`,
},
{
name: "Absolute Annulment",
id: 24,
cost: 6e14,
requirement: () => `Have ${formatInt(13000)} Antimatter Galaxies in Ra's Reality
with a fully inverted Black Hole`,
hasFailed: () => !Ra.isRunning || player.requirementChecks.reality.slowestBH > 1e-300,
checkRequirement: () => Ra.isRunning && player.requirementChecks.reality.slowestBH <= 1e-300 &&
player.galaxies >= 13000,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Increase free Dimboost strength based on Singularity count",
effect: () => Decimal.pow(player.celestials.laitela.singularities, 300),
formatEffect: value => `${formatX(value, 2, 1)}`,
},
{
name: "Omnipresent Obliteration",
id: 25,
cost: 1.6e15,
formatCost: x => format(x, 1),
requirement: () => `Reach Reality in Lai'tela's Reality with all Dimensions disabled and
at least ${formatInt(4)} empty Glyph slots`,
hasFailed: () => !Laitela.isRunning || Laitela.maxAllowedDimension !== 0 || Glyphs.activeList.length > 1,
checkRequirement: () => Laitela.isRunning && Laitela.maxAllowedDimension === 0 &&
Glyphs.activeList.length <= 1,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Unlock Pelle, Celestial of Antimatter",
},
];

View File

@ -1,345 +1,345 @@
import { DC } from "../../constants";
import { GameDatabase } from "../game-database";
GameDatabase.reality.upgrades = (function() {
const rebuyable = props => {
props.cost = () => getHybridCostScaling(
player.reality.rebuyables[props.id],
1e30,
props.initialCost,
props.costMult,
props.costMult / 10,
DC.E309,
1e3,
props.initialCost * props.costMult
);
const { effect } = props;
props.effect = () => Math.pow(
effect + ImaginaryUpgrade(props.id).effectOrDefault(0),
player.reality.rebuyables[props.id] * getAdjustedGlyphEffect("realityrow1pow"));
props.description = () => props.textTemplate.replace("{value}",
ImaginaryUpgrade(props.id).effectValue === 0
? formatInt(effect)
: format(effect + ImaginaryUpgrade(props.id).effectValue, 2, 2));
props.formatEffect = value => formatX(value, 2, 0);
props.formatCost = value => format(value, 2, 0);
return props;
};
return [
rebuyable({
name: "Temporal Amplifier",
id: 1,
initialCost: 1,
costMult: 30,
textTemplate: "You gain Dilated Time {value} times faster",
effect: 3
}),
rebuyable({
name: "Replicative Amplifier",
id: 2,
initialCost: 1,
costMult: 30,
textTemplate: "You gain Replicanti {value} times faster",
effect: 3
}),
rebuyable({
name: "Eternal Amplifier",
id: 3,
initialCost: 2,
costMult: 30,
textTemplate: "You gain {value} times more Eternities",
effect: 3
}),
rebuyable({
name: "Superluminal Amplifier",
id: 4,
initialCost: 2,
costMult: 30,
textTemplate: "You gain {value} times more Tachyon Particles",
effect: 3
}),
rebuyable({
name: "Boundless Amplifier",
id: 5,
initialCost: 3,
costMult: 50,
textTemplate: "You gain {value} times more Infinities",
effect: 5
}),
{
name: "Cosmically Duplicate",
id: 6,
cost: 15,
requirement: "Complete your first Eternity without using Replicanti Galaxies",
// Note that while noRG resets on eternity, the reality-level check will be false after the first eternity.
// The noRG variable is eternity-level as it's also used for an achievement check
hasFailed: () => !(player.requirementChecks.eternity.noRG && player.requirementChecks.reality.noEternities),
checkRequirement: () => player.requirementChecks.eternity.noRG && player.requirementChecks.reality.noEternities,
checkEvent: GAME_EVENT.ETERNITY_RESET_BEFORE,
description: "Replicanti speed is multiplied based on Replicanti Galaxies",
effect: () => 1 + Replicanti.galaxies.total / 50,
formatEffect: value => formatX(value, 2, 2)
const rebuyable = props => {
props.cost = () => getHybridCostScaling(
player.reality.rebuyables[props.id],
1e30,
props.initialCost,
props.costMult,
props.costMult / 10,
DC.E309,
1e3,
props.initialCost * props.costMult
);
const { effect } = props;
props.effect = () => Math.pow(
effect + ImaginaryUpgrade(props.id).effectOrDefault(0),
player.reality.rebuyables[props.id] * getAdjustedGlyphEffect("realityrow1pow"));
props.description = () => props.textTemplate.replace("{value}",
ImaginaryUpgrade(props.id).effectValue === 0
? formatInt(effect)
: format(effect + ImaginaryUpgrade(props.id).effectValue, 2, 2));
props.formatEffect = value => formatX(value, 2, 0);
props.formatCost = value => format(value, 2, 0);
return props;
};
GameDatabase.reality.upgrades = [
rebuyable({
name: "Temporal Amplifier",
id: 1,
initialCost: 1,
costMult: 30,
textTemplate: "You gain Dilated Time {value} times faster",
effect: 3
}),
rebuyable({
name: "Replicative Amplifier",
id: 2,
initialCost: 1,
costMult: 30,
textTemplate: "You gain Replicanti {value} times faster",
effect: 3
}),
rebuyable({
name: "Eternal Amplifier",
id: 3,
initialCost: 2,
costMult: 30,
textTemplate: "You gain {value} times more Eternities",
effect: 3
}),
rebuyable({
name: "Superluminal Amplifier",
id: 4,
initialCost: 2,
costMult: 30,
textTemplate: "You gain {value} times more Tachyon Particles",
effect: 3
}),
rebuyable({
name: "Boundless Amplifier",
id: 5,
initialCost: 3,
costMult: 50,
textTemplate: "You gain {value} times more Infinities",
effect: 5
}),
{
name: "Cosmically Duplicate",
id: 6,
cost: 15,
requirement: "Complete your first Eternity without using Replicanti Galaxies",
// Note that while noRG resets on eternity, the reality-level check will be false after the first eternity.
// The noRG variable is eternity-level as it's also used for an achievement check
hasFailed: () => !(player.requirementChecks.eternity.noRG && player.requirementChecks.reality.noEternities),
checkRequirement: () => player.requirementChecks.eternity.noRG && player.requirementChecks.reality.noEternities,
checkEvent: GAME_EVENT.ETERNITY_RESET_BEFORE,
description: "Replicanti speed is multiplied based on Replicanti Galaxies",
effect: () => 1 + Replicanti.galaxies.total / 50,
formatEffect: value => formatX(value, 2, 2)
},
{
name: "Innumerably Construct",
id: 7,
cost: 15,
requirement: "Complete your first Infinity with at most 1 Antimatter Galaxy",
hasFailed: () => !(player.galaxies <= 1 && player.requirementChecks.reality.noInfinities),
checkRequirement: () => player.galaxies <= 1 && player.requirementChecks.reality.noInfinities,
checkEvent: GAME_EVENT.BIG_CRUNCH_BEFORE,
description: "Infinity gain is boosted from Antimatter Galaxy count",
effect: () => 1 + player.galaxies / 30,
formatEffect: value => formatX(value, 2, 2)
},
{
name: "Paradoxically Attain",
id: 8,
cost: 15,
requirement: "Get to Eternity without any automatic Achievements",
hasFailed: () => player.reality.gainedAutoAchievements,
checkRequirement: () => !player.reality.gainedAutoAchievements,
checkEvent: GAME_EVENT.ETERNITY_RESET_BEFORE,
description: "Tachyon Particle gain is boosted based on Achievement multiplier",
effect: () => Math.sqrt(Achievements.power),
formatEffect: value => formatX(value, 2, 2)
},
{
name: "Linguistically Expand",
id: 9,
cost: 15,
requirement: () => `Eternity for ${format("1e4000")} Eternity Points using
only a single level ${formatInt(3)}+ Glyph.`,
hasFailed: () => {
const invalidEquippedGlyphs = Glyphs.activeList.length > 1 ||
(Glyphs.activeList.length === 1 && Glyphs.activeList[0].level < 3);
const hasValidGlyphInInventory = Glyphs.inventory.countWhere(g => g && g.level >= 3) > 0;
return invalidEquippedGlyphs || (Glyphs.activeList.length === 0 && !hasValidGlyphInInventory);
},
{
name: "Innumerably Construct",
id: 7,
cost: 15,
requirement: "Complete your first Infinity with at most 1 Antimatter Galaxy",
hasFailed: () => !(player.galaxies <= 1 && player.requirementChecks.reality.noInfinities),
checkRequirement: () => player.galaxies <= 1 && player.requirementChecks.reality.noInfinities,
checkEvent: GAME_EVENT.BIG_CRUNCH_BEFORE,
description: "Infinity gain is boosted from Antimatter Galaxy count",
effect: () => 1 + player.galaxies / 30,
formatEffect: value => formatX(value, 2, 2)
checkRequirement: () => Currency.eternityPoints.exponent >= 4000 &&
Glyphs.activeList.length === 1 && Glyphs.activeList[0].level >= 3,
checkEvent: GAME_EVENT.ETERNITY_RESET_AFTER,
description: "Gain another Glyph slot",
effect: () => 1
},
{
name: "Existentially Prolong",
id: 10,
cost: 15,
requirement: () => `Complete your first Eternity with at least ${formatPostBreak(DC.E450)} Infinity Points`,
hasFailed: () => !player.requirementChecks.reality.noEternities,
checkRequirement: () => Currency.infinityPoints.exponent >= 450 &&
player.requirementChecks.reality.noEternities,
checkEvent: GAME_EVENT.ETERNITY_RESET_BEFORE,
description: () => `Start every Reality with ${formatInt(100)} Eternities (also applies to current Reality)`,
automatorPoints: 15,
shortDescription: () => `Start with ${formatInt(100)} Eternities`,
effect: () => 100
},
{
name: "The Boundless Flow",
id: 11,
cost: 50,
requirement: () => `${format(Currency.infinitiesBanked.value, 2)}/${format(DC.E12)} Banked Infinities`,
checkRequirement: () => Currency.infinitiesBanked.exponent >= 12,
checkEvent: [GAME_EVENT.ETERNITY_RESET_AFTER, GAME_EVENT.REALITY_FIRST_UNLOCKED],
description: "Every second, gain 10% of the Infinities you would normally gain by Infinitying",
automatorPoints: 5,
shortDescription: () => `Continuous Infinity generation`,
effect: () => gainedInfinities().times(0.1),
formatEffect: value => `${format(value)} per second`
},
{
name: "The Knowing Existence",
id: 12,
cost: 50,
requirement: () => `Eternity for ${format(DC.E70)} Eternity Points without Eternity Challenge 1`,
hasFailed: () => EternityChallenge(1).completions !== 0,
checkRequirement: () => Currency.eternityPoints.exponent >= 70 && EternityChallenge(1).completions === 0,
checkEvent: GAME_EVENT.ETERNITY_RESET_AFTER,
description: "Eternity Point multiplier based on Reality and Time Theorem count",
effect: () => Currency.timeTheorems.value
.minus(DC.E3).clampMin(2)
.pow(Math.log2(Math.min(Currency.realities.value, 1e4))).clampMin(1),
formatEffect: value => formatX(value, 2, 2)
},
{
name: "The Telemechanical Process",
id: 13,
cost: 50,
requirement: () => `Eternity for ${format(DC.E4000)} Eternity Points without Time Dimensions 5-8`,
hasFailed: () => !Array.range(5, 4).every(i => TimeDimension(i).amount.equals(0)),
checkRequirement: () => Currency.eternityPoints.exponent >= 4000 &&
Array.range(5, 4).every(i => TimeDimension(i).amount.equals(0)),
checkEvent: GAME_EVENT.ETERNITY_RESET_AFTER,
description: () => `Unlock Time Dimension, ${formatX(5)} Eternity Point multiplier,
and improved Eternity autobuyers`,
automatorPoints: 10,
shortDescription: () => `TD and ${formatX(5)} EP Autobuyers, improved Eternity Autobuyer`,
},
{
name: "The Eternal Flow",
id: 14,
cost: 50,
requirement: () => `${format(Currency.eternities.value, 2)}/${format(1e7)} Eternities`,
checkRequirement: () => Currency.eternities.gte(1e7),
checkEvent: [GAME_EVENT.ETERNITY_RESET_AFTER, GAME_EVENT.REALITY_FIRST_UNLOCKED],
description: "Gain Eternities per second equal to your Reality count",
automatorPoints: 5,
shortDescription: () => `Continuous Eternity generation`,
effect: () => Currency.realities.value * Ra.unlocks.continuousTTBoost.effects.eternity.effectOrDefault(1),
formatEffect: value => `${format(value)} per second`
},
{
name: "The Paradoxical Forever",
id: 15,
cost: 50,
requirement: () => `Have ${format(DC.E10)} Eternity Points without purchasing
the ${formatX(5)} Eternity Point upgrade`,
hasFailed: () => player.epmultUpgrades !== 0,
checkRequirement: () => Currency.eternityPoints.exponent >= 10 && player.epmultUpgrades === 0,
checkEvent: GAME_EVENT.ETERNITY_RESET_AFTER,
description: () => `Boost Tachyon Particle gain based on ${formatX(5)} Eternity Point multiplier`,
effect: () => Math.max(Math.sqrt(Decimal.log10(EternityUpgrade.epMult.effectValue)) / 3, 1),
formatEffect: value => formatX(value, 2, 2)
},
{
name: "Disparity of Rarity",
id: 16,
cost: 1500,
requirement: () => `Reality with ${formatInt(4)} Glyphs equipped of uncommon or better rarity
(${formatInt(Glyphs.activeList.countWhere(g => g && g.strength >= 1.5))} equipped)`,
hasFailed: () => {
const availableGlyphs = Glyphs.inventory.countWhere(g => g && g.strength >= 1.5);
const equipped = Glyphs.activeList.countWhere(g => g.strength >= 1.5);
const availableSlots = Glyphs.activeSlotCount - Glyphs.activeList.length;
return equipped + Math.min(availableGlyphs, availableSlots) < 4;
},
{
name: "Paradoxically Attain",
id: 8,
cost: 15,
requirement: "Get to Eternity without any automatic Achievements",
hasFailed: () => player.reality.gainedAutoAchievements,
checkRequirement: () => !player.reality.gainedAutoAchievements,
checkEvent: GAME_EVENT.ETERNITY_RESET_BEFORE,
description: "Tachyon Particle gain is boosted based on Achievement multiplier",
effect: () => Math.sqrt(Achievements.power),
formatEffect: value => formatX(value, 2, 2)
checkRequirement: () => Glyphs.activeList.countWhere(g => g.strength >= 1.5) === 4,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Improve the Glyph rarity formula",
effect: 1.3,
formatCost: value => format(value, 1, 0)
},
{
name: "Duplicity of Potency",
id: 17,
cost: 1500,
requirement: () => `Reality with ${formatInt(4)} Glyphs equipped, each having at least ${formatInt(2)} effects
(${formatInt(Glyphs.activeList.countWhere(g => g && countValuesFromBitmask(g.effects) >= 2))} equipped)`,
hasFailed: () => {
const availableGlyphs = Glyphs.inventory.countWhere(g => g && countValuesFromBitmask(g.effects) >= 2);
const equipped = Glyphs.activeList.countWhere(g => countValuesFromBitmask(g.effects) >= 2);
const availableSlots = Glyphs.activeSlotCount - Glyphs.activeList.length;
return equipped + Math.min(availableGlyphs, availableSlots) < 4;
},
{
name: "Linguistically Expand",
id: 9,
cost: 15,
requirement: () => `Eternity for ${format("1e4000")} Eternity Points using
only a single level ${formatInt(3)}+ Glyph.`,
hasFailed: () => {
const invalidEquippedGlyphs = Glyphs.activeList.length > 1 ||
(Glyphs.activeList.length === 1 && Glyphs.activeList[0].level < 3);
const hasValidGlyphInInventory = Glyphs.inventory.countWhere(g => g && g.level >= 3) > 0;
return invalidEquippedGlyphs || (Glyphs.activeList.length === 0 && !hasValidGlyphInInventory);
},
checkRequirement: () => Currency.eternityPoints.exponent >= 4000 &&
Glyphs.activeList.length === 1 && Glyphs.activeList[0].level >= 3,
checkEvent: GAME_EVENT.ETERNITY_RESET_AFTER,
description: "Gain another Glyph slot",
effect: () => 1
checkRequirement: () => Glyphs.activeList.countWhere(g => countValuesFromBitmask(g.effects) >= 2) === 4,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: () => `${formatPercents(0.5)} chance to get an additional effect on Glyphs`,
effect: 0.5,
formatCost: value => format(value, 1, 0)
},
{
name: "Measure of Forever",
id: 18,
cost: 1500,
requirement: () => `Reality with ${formatInt(4)} Glyphs equipped, each at level ${formatInt(10)} or higher
(${formatInt(Glyphs.activeList.countWhere(g => g && g.level >= 10))} equipped)`,
hasFailed: () => {
const availableGlyphs = Glyphs.inventory.countWhere(g => g && g.level >= 10);
const equipped = Glyphs.activeList.countWhere(g => g.level >= 10);
const availableSlots = Glyphs.activeSlotCount - Glyphs.activeList.length;
return equipped + Math.min(availableGlyphs, availableSlots) < 4;
},
{
name: "Existentially Prolong",
id: 10,
cost: 15,
requirement: () => `Complete your first Eternity with at least ${formatPostBreak(DC.E450)} Infinity Points`,
hasFailed: () => !player.requirementChecks.reality.noEternities,
checkRequirement: () => Currency.infinityPoints.exponent >= 450 &&
player.requirementChecks.reality.noEternities,
checkEvent: GAME_EVENT.ETERNITY_RESET_BEFORE,
description: () => `Start every Reality with ${formatInt(100)} Eternities (also applies to current Reality)`,
automatorPoints: 15,
shortDescription: () => `Start with ${formatInt(100)} Eternities`,
effect: () => 100
},
{
name: "The Boundless Flow",
id: 11,
cost: 50,
requirement: () => `${format(Currency.infinitiesBanked.value, 2)}/${format(DC.E12)} Banked Infinities`,
checkRequirement: () => Currency.infinitiesBanked.exponent >= 12,
checkEvent: [GAME_EVENT.ETERNITY_RESET_AFTER, GAME_EVENT.REALITY_FIRST_UNLOCKED],
description: "Every second, gain 10% of the Infinities you would normally gain by Infinitying",
automatorPoints: 5,
shortDescription: () => `Continuous Infinity generation`,
effect: () => gainedInfinities().times(0.1),
formatEffect: value => `${format(value)} per second`
},
{
name: "The Knowing Existence",
id: 12,
cost: 50,
requirement: () => `Eternity for ${format(DC.E70)} Eternity Points without Eternity Challenge 1`,
hasFailed: () => EternityChallenge(1).completions !== 0,
checkRequirement: () => Currency.eternityPoints.exponent >= 70 && EternityChallenge(1).completions === 0,
checkEvent: GAME_EVENT.ETERNITY_RESET_AFTER,
description: "Eternity Point multiplier based on Reality and Time Theorem count",
effect: () => Currency.timeTheorems.value
.minus(DC.E3).clampMin(2)
.pow(Math.log2(Math.min(Currency.realities.value, 1e4))).clampMin(1),
formatEffect: value => formatX(value, 2, 2)
},
{
name: "The Telemechanical Process",
id: 13,
cost: 50,
requirement: () => `Eternity for ${format(DC.E4000)} Eternity Points without Time Dimensions 5-8`,
hasFailed: () => !Array.range(5, 4).every(i => TimeDimension(i).amount.equals(0)),
checkRequirement: () => Currency.eternityPoints.exponent >= 4000 &&
Array.range(5, 4).every(i => TimeDimension(i).amount.equals(0)),
checkEvent: GAME_EVENT.ETERNITY_RESET_AFTER,
description: () => `Unlock Time Dimension, ${formatX(5)} Eternity Point multiplier,
and improved Eternity autobuyers`,
automatorPoints: 10,
shortDescription: () => `TD and ${formatX(5)} EP Autobuyers, improved Eternity Autobuyer`,
},
{
name: "The Eternal Flow",
id: 14,
cost: 50,
requirement: () => `${format(Currency.eternities.value, 2)}/${format(1e7)} Eternities`,
checkRequirement: () => Currency.eternities.gte(1e7),
checkEvent: [GAME_EVENT.ETERNITY_RESET_AFTER, GAME_EVENT.REALITY_FIRST_UNLOCKED],
description: "Gain Eternities per second equal to your Reality count",
automatorPoints: 5,
shortDescription: () => `Continuous Eternity generation`,
effect: () => Currency.realities.value * Ra.unlocks.continuousTTBoost.effects.eternity.effectOrDefault(1),
formatEffect: value => `${format(value)} per second`
},
{
name: "The Paradoxical Forever",
id: 15,
cost: 50,
requirement: () => `Have ${format(DC.E10)} Eternity Points without purchasing
the ${formatX(5)} Eternity Point upgrade`,
hasFailed: () => player.epmultUpgrades !== 0,
checkRequirement: () => Currency.eternityPoints.exponent >= 10 && player.epmultUpgrades === 0,
checkEvent: GAME_EVENT.ETERNITY_RESET_AFTER,
description: () => `Boost Tachyon Particle gain based on ${formatX(5)} Eternity Point multiplier`,
effect: () => Math.max(Math.sqrt(Decimal.log10(EternityUpgrade.epMult.effectValue)) / 3, 1),
formatEffect: value => formatX(value, 2, 2)
},
{
name: "Disparity of Rarity",
id: 16,
cost: 1500,
requirement: () => `Reality with ${formatInt(4)} Glyphs equipped of uncommon or better rarity
(${formatInt(Glyphs.activeList.countWhere(g => g && g.strength >= 1.5))} equipped)`,
hasFailed: () => {
const availableGlyphs = Glyphs.inventory.countWhere(g => g && g.strength >= 1.5);
const equipped = Glyphs.activeList.countWhere(g => g.strength >= 1.5);
const availableSlots = Glyphs.activeSlotCount - Glyphs.activeList.length;
return equipped + Math.min(availableGlyphs, availableSlots) < 4;
},
checkRequirement: () => Glyphs.activeList.countWhere(g => g.strength >= 1.5) === 4,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Improve the Glyph rarity formula",
effect: 1.3,
formatCost: value => format(value, 1, 0)
},
{
name: "Duplicity of Potency",
id: 17,
cost: 1500,
requirement: () => `Reality with ${formatInt(4)} Glyphs equipped, each having at least ${formatInt(2)} effects
(${formatInt(Glyphs.activeList.countWhere(g => g && countValuesFromBitmask(g.effects) >= 2))} equipped)`,
hasFailed: () => {
const availableGlyphs = Glyphs.inventory.countWhere(g => g && countValuesFromBitmask(g.effects) >= 2);
const equipped = Glyphs.activeList.countWhere(g => countValuesFromBitmask(g.effects) >= 2);
const availableSlots = Glyphs.activeSlotCount - Glyphs.activeList.length;
return equipped + Math.min(availableGlyphs, availableSlots) < 4;
},
checkRequirement: () => Glyphs.activeList.countWhere(g => countValuesFromBitmask(g.effects) >= 2) === 4,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: () => `${formatPercents(0.5)} chance to get an additional effect on Glyphs`,
effect: 0.5,
formatCost: value => format(value, 1, 0)
},
{
name: "Measure of Forever",
id: 18,
cost: 1500,
requirement: () => `Reality with ${formatInt(4)} Glyphs equipped, each at level ${formatInt(10)} or higher
(${formatInt(Glyphs.activeList.countWhere(g => g && g.level >= 10))} equipped)`,
hasFailed: () => {
const availableGlyphs = Glyphs.inventory.countWhere(g => g && g.level >= 10);
const equipped = Glyphs.activeList.countWhere(g => g.level >= 10);
const availableSlots = Glyphs.activeSlotCount - Glyphs.activeList.length;
return equipped + Math.min(availableGlyphs, availableSlots) < 4;
},
checkRequirement: () => Glyphs.activeList.countWhere(g => g.level >= 10) === 4,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Eternity count boosts Glyph level",
effect: () => Math.max(Math.sqrt(Currency.eternities.value.plus(1).log10()) * 0.45, 1),
formatCost: value => format(value, 1, 0)
},
{
name: "Scour to Empower",
id: 19,
cost: 1500,
requirement: () => `Have a total of ${formatInt(30)} or more Glyphs at once
(You have ${formatInt(Glyphs.allGlyphs.countWhere(g => g))})`,
hasFailed: () => Glyphs.allGlyphs.countWhere(g => g) < 30,
checkRequirement: () => Glyphs.allGlyphs.countWhere(g => g) >= 30,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "You can sacrifice Glyphs for permanent bonuses (Shift + click)",
formatCost: value => format(value, 1, 0)
},
{
name: "Parity of Singularity",
id: 20,
cost: 1500,
requirement: () => `${formatInt(1)} year total play time and the Black Hole unlocked
(Currently: ${Time.totalTimePlayed.toStringShort(false)})`,
hasFailed: () => !BlackHole(1).isUnlocked && Currency.realityMachines.lt(100),
checkRequirement: () => Time.totalTimePlayed.totalYears >= 1 && BlackHole(1).isUnlocked,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Unlock Black Hole 2",
automatorPoints: 10,
shortDescription: () => `Second Black Hole`,
formatCost: value => format(value, 1, 0)
},
{
name: "Cosmic Conglomerate",
id: 21,
cost: 100000,
requirement: () => `${formatInt(Replicanti.galaxies.total + player.galaxies +
player.dilation.totalTachyonGalaxies)}/${formatInt(2800)} total Galaxies from all types`,
checkRequirement: () =>
Replicanti.galaxies.total + player.galaxies + player.dilation.totalTachyonGalaxies >= 2800,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: () => `Remote Antimatter Galaxy scaling is moved to ${formatInt(1e5)} galaxies`,
effect: 1e5
},
{
name: "Temporal Transcendence",
id: 22,
cost: 100000,
requirement: () => `${format(Currency.timeShards.value, 1)}/${format(DC.E28000)} Time Shards`,
checkRequirement: () => Currency.timeShards.exponent >= 28000,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Time Dimension multiplier based on days spent in this Reality",
effect: () => Decimal.pow10(Math.pow(1 + 2 * Math.log10(Time.thisReality.totalDays + 1), 1.6)),
formatEffect: value => formatX(value, 2, 2)
},
{
name: "Replicative Rapidity",
id: 23,
cost: 100000,
requirement: () => `Reality in under ${formatInt(15)} minutes (Best: ${Time.bestReality.toStringShort()})`,
hasFailed: () => Time.thisReality.totalMinutes >= 15,
checkRequirement: () => Time.thisReality.totalMinutes < 15,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Replicanti speed is boosted based on your fastest Reality",
effect: () => 15 / Math.clamp(Time.bestReality.totalMinutes, 1 / 12, 15),
cap: 180,
formatEffect: value => formatX(value, 2, 2)
},
{
name: "Synthetic Symbolism",
id: 24,
cost: 100000,
requirement: () => `Reality for ${formatInt(5000)} Reality Machines without Glyphs`,
hasFailed: () => Glyphs.activeList.length > 0,
checkRequirement: () => MachineHandler.gainedRealityMachines.gte(5000) && Glyphs.activeList.length === 0,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Gain another Glyph slot",
effect: () => 1
},
{
name: "Effortless Existence",
id: 25,
cost: 100000,
requirement: () => `Reach ${format(DC.E11111)} EP (Best: ${format(player.records.bestReality.bestEP, 2)} EP)`,
checkRequirement: () => player.records.bestReality.bestEP.exponent >= 11111,
checkEvent: GAME_EVENT.ETERNITY_RESET_AFTER,
description: "Unlock the Reality autobuyer and Automator command",
automatorPoints: 100,
shortDescription: () => `Reality Autobuyer`,
},
];
}());
checkRequirement: () => Glyphs.activeList.countWhere(g => g.level >= 10) === 4,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Eternity count boosts Glyph level",
effect: () => Math.max(Math.sqrt(Currency.eternities.value.plus(1).log10()) * 0.45, 1),
formatCost: value => format(value, 1, 0)
},
{
name: "Scour to Empower",
id: 19,
cost: 1500,
requirement: () => `Have a total of ${formatInt(30)} or more Glyphs at once
(You have ${formatInt(Glyphs.allGlyphs.countWhere(g => g))})`,
hasFailed: () => Glyphs.allGlyphs.countWhere(g => g) < 30,
checkRequirement: () => Glyphs.allGlyphs.countWhere(g => g) >= 30,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "You can sacrifice Glyphs for permanent bonuses (Shift + click)",
formatCost: value => format(value, 1, 0)
},
{
name: "Parity of Singularity",
id: 20,
cost: 1500,
requirement: () => `${formatInt(1)} year total play time and the Black Hole unlocked
(Currently: ${Time.totalTimePlayed.toStringShort(false)})`,
hasFailed: () => !BlackHole(1).isUnlocked && Currency.realityMachines.lt(100),
checkRequirement: () => Time.totalTimePlayed.totalYears >= 1 && BlackHole(1).isUnlocked,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Unlock Black Hole 2",
automatorPoints: 10,
shortDescription: () => `Second Black Hole`,
formatCost: value => format(value, 1, 0)
},
{
name: "Cosmic Conglomerate",
id: 21,
cost: 100000,
requirement: () => `${formatInt(Replicanti.galaxies.total + player.galaxies +
player.dilation.totalTachyonGalaxies)}/${formatInt(2800)} total Galaxies from all types`,
checkRequirement: () =>
Replicanti.galaxies.total + player.galaxies + player.dilation.totalTachyonGalaxies >= 2800,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: () => `Remote Antimatter Galaxy scaling is moved to ${formatInt(1e5)} galaxies`,
effect: 1e5
},
{
name: "Temporal Transcendence",
id: 22,
cost: 100000,
requirement: () => `${format(Currency.timeShards.value, 1)}/${format(DC.E28000)} Time Shards`,
checkRequirement: () => Currency.timeShards.exponent >= 28000,
checkEvent: GAME_EVENT.GAME_TICK_AFTER,
description: "Time Dimension multiplier based on days spent in this Reality",
effect: () => Decimal.pow10(Math.pow(1 + 2 * Math.log10(Time.thisReality.totalDays + 1), 1.6)),
formatEffect: value => formatX(value, 2, 2)
},
{
name: "Replicative Rapidity",
id: 23,
cost: 100000,
requirement: () => `Reality in under ${formatInt(15)} minutes (Best: ${Time.bestReality.toStringShort()})`,
hasFailed: () => Time.thisReality.totalMinutes >= 15,
checkRequirement: () => Time.thisReality.totalMinutes < 15,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Replicanti speed is boosted based on your fastest Reality",
effect: () => 15 / Math.clamp(Time.bestReality.totalMinutes, 1 / 12, 15),
cap: 180,
formatEffect: value => formatX(value, 2, 2)
},
{
name: "Synthetic Symbolism",
id: 24,
cost: 100000,
requirement: () => `Reality for ${formatInt(5000)} Reality Machines without Glyphs`,
hasFailed: () => Glyphs.activeList.length > 0,
checkRequirement: () => MachineHandler.gainedRealityMachines.gte(5000) && Glyphs.activeList.length === 0,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,
description: "Gain another Glyph slot",
effect: () => 1
},
{
name: "Effortless Existence",
id: 25,
cost: 100000,
requirement: () => `Reach ${format(DC.E11111)} EP (Best: ${format(player.records.bestReality.bestEP, 2)} EP)`,
checkRequirement: () => player.records.bestReality.bestEP.exponent >= 11111,
checkEvent: GAME_EVENT.ETERNITY_RESET_AFTER,
description: "Unlock the Reality autobuyer and Automator command",
automatorPoints: 100,
shortDescription: () => `Reality Autobuyer`,
},
];

View File

@ -86,7 +86,7 @@ GameDatabase.speedrunMilestones = [
key: "allEternityMilestones",
name: "All Eternity Milestones",
description: "Unlock all Eternity Milestones",
checkRequirement: () => EternityMilestones.all.every(m => m.isReached),
checkRequirement: () => EternityMilestone.all.every(m => m.isReached),
checkEvent: GAME_EVENT.ETERNITY_RESET_AFTER,
},
{

View File

@ -1318,6 +1318,11 @@ GameStorage.devMigrations = {
delete player.celestials.effarig.unlocksBits;
delete player.celestials.ra.unlocksBits;
},
player => {
for (const script of Object.values(player.reality.automator.scripts)) {
script.id = parseInt(script.id, 10);
}
},
],
patch(player) {

View File

@ -30,19 +30,7 @@ class TabNotificationState {
}
}
export const TabNotification = (function() {
const db = GameDatabase.tabNotifications;
return {
firstInfinity: new TabNotificationState(db.firstInfinity),
IDUnlock: new TabNotificationState(db.ICUnlock),
ICUnlock: new TabNotificationState(db.ICUnlock),
breakInfinity: new TabNotificationState(db.breakInfinity),
firstEternity: new TabNotificationState(db.firstEternity),
dilationAfterUnlock: new TabNotificationState(db.dilationAfterUnlock),
realityUnlock: new TabNotificationState(db.realityUnlock),
blackHoleUnlock: new TabNotificationState(db.blackHoleUnlock),
automatorUnlock: new TabNotificationState(db.automatorUnlock),
teresaUnlock: new TabNotificationState(db.teresaUnlock),
alchemyUnlock: new TabNotificationState(db.alchemyUnlock),
};
}());
export const TabNotification = mapGameDataToObject(
GameDatabase.tabNotifications,
config => new TabNotificationState(config)
);

View File

@ -683,7 +683,7 @@ function applyAutoUnlockPerks() {
if (Perk.autounlockDilation3.isBought) buyDilationUpgrade(DilationUpgrade.ttGenerator.id);
if (Perk.autounlockReality.isBought) TimeStudy.reality.purchase(true);
if (player.eternityUpgrades.size < 6 && Perk.autounlockEU2.isBought) {
const secondRow = Object.values(EternityUpgrade).filter(u => u.id > 3);
const secondRow = EternityUpgrade.all.filter(u => u.id > 3);
for (const upgrade of secondRow) {
if (player.eternityPoints.gte(upgrade.cost / 1e10)) player.eternityUpgrades.add(upgrade.id);
}

View File

@ -132,21 +132,20 @@
border-radius: 0;
}
.l-automator-pane__controls {
flex: 0 0 auto;
}
.c-automator__controls {
background-color: #262626;
}
.l-automator__controls {
display: flex;
flex-direction: row;
flex: none;
flex-direction: column;
}
/* for corner buttons */
position: relative;
justify-content: flex-start;
.l-automator-button-row {
display: flex;
flex-direction: row;
height: 3rem;
align-items: center;
}
@ -163,23 +162,6 @@
right: 0;
}
.l-automator__script-names {
display: flex;
flex-grow: 1;
flex-direction: row;
justify-content: space-evenly;
align-items: center;
}
.l-automator__scripts-dropdown {
width: 90%;
height: 90%;
border-width: 0.1rem;
border-radius: 0;
margin: 0.4rem;
padding: 0.2rem 0 0.3rem;
}
.l-automator__rename-input {
width: 90%;
height: 90%;

View File

@ -67,7 +67,7 @@ body.t-s9 {
height: 7rem;
justify-content: center;
align-items: center;
background-color: var(--color-base);
background-color: var(--color-prestige--accent);
border-right: 0.1rem solid var(--color-accent);
border-bottom: 0.1rem solid var(--color-accent);
padding: 1rem;
@ -312,7 +312,7 @@ body.t-s9 {
line-height: 2.8rem;
opacity: 0;
color: var(--color-text);
background: var(--color-base);
background: var(--color-prestige--accent);
border: 0.1rem solid var(--color-accent);
margin-left: -7.7rem;
transition-duration: 0.2s;
@ -346,7 +346,6 @@ body.t-s9 {
.o-tab-btn--infinity .o-subtab__tooltip {
color: var(--color-infinity);
background: var(--color-prestige--accent);
border-color: var(--color-infinity);
}
@ -356,7 +355,6 @@ body.t-s9 {
.o-tab-btn--eternity .o-subtab__tooltip {
color: var(--color-eternity);
background: var(--color-prestige--accent);
border-color: var(--color-eternity);
}
@ -366,7 +364,6 @@ body.t-s9 {
.o-tab-btn--reality .o-subtab__tooltip {
color: var(--color-reality);
background: var(--color-prestige--accent);
border-color: var(--color-reality);
}
@ -376,7 +373,6 @@ body.t-s9 {
.o-tab-btn--celestial .o-subtab__tooltip {
color: var(--color-celestials);
background: var(--color-prestige--accent);
border-color: var(--color-celestials);
}

View File

@ -17,6 +17,11 @@ html {
border-radius: 0.5rem;
}
::-webkit-scrollbar-corner {
-webkit-appearance: none;
appearance: none;
}
.s-base--metro::-webkit-scrollbar-thumb {
border-radius: 0;
}
@ -154,7 +159,7 @@ html {
--color-reality: #afa3a5;
--color-reality-light: #e8e3e4;
--color-celestials: #f2d6c1;
--color-prestige--accent: black;
--color-prestige--accent: #dbd242;
--color-pelle--base: #7cb727;
}
@ -510,7 +515,6 @@ button:focus {
position: absolute;
right: 0.5rem;
bottom: 0.5rem;
animation: weee 4s infinite;
}
.o-time-study-selection-btn {
@ -535,7 +539,7 @@ button:focus {
font-size: 1.8rem;
font-weight: bold;
color: var(--color-text);
background-color: var(--color-base);
background-color: var(--color-prestige--accent);
border: var(--var-border-width, 0.2rem) solid var(--color-accent);
border-radius: var(--var-border-radius, 0.4rem);
transition-duration: 0.2s;
@ -550,51 +554,43 @@ button:focus {
}
.o-tab-btn:hover {
color: var(--color-text-inverted);
color: var(--color-prestige--accent);
background: var(--color-accent);
}
.o-tab-btn--infinity {
color: var(--color-infinity);
background: var(--color-prestige--accent);
border-color: var(--color-infinity);
}
.o-tab-btn--infinity:hover {
color: var(--color-prestige--accent);
background: var(--color-infinity);
}
.o-tab-btn--eternity {
color: var(--color-eternity);
background: var(--color-prestige--accent);
border-color: var(--color-eternity);
}
.o-tab-btn--eternity:hover {
color: var(--color-prestige--accent);
background: var(--color-eternity);
}
.o-tab-btn--reality {
color: var(--color-reality);
background: var(--color-prestige--accent);
border-color: var(--color-reality);
}
.o-tab-btn--reality:hover {
color: var(--color-prestige--accent);
background: var(--color-reality);
}
.o-tab-btn--celestial {
color: var(--color-celestials);
background: var(--color-prestige--accent);
border-color: var(--color-celestials);
}
.o-tab-btn--celestial:hover {
color: var(--color-prestige--accent);
background: var(--color-celestials);
}
@ -1131,26 +1127,25 @@ br {
}
}
/* stylelint-disable-next-line keyframes-name-pattern */
@keyframes barrelRoll {
@keyframes a-barrel-roll {
0% { transform: rotateZ(0deg); }
50%,
100% { transform: rotateZ(360deg); }
}
@keyframes spin3d {
@keyframes a-spin3d {
0% { transform: rotate3d(5.2, -2.8, 1.4, 0deg); }
100% { transform: rotate3d(5.2, -2.8, 1.4, 360deg); }
}
@keyframes spin4d {
@keyframes a-spin4d {
0%,
100% { transform: scale(1) rotate3d(5.2, -2.8, 1.4, 0deg); }
50% { transform: scale(0) rotate3d(5.2, -2.8, 1.4, 360deg); }
}
@keyframes float {
@keyframes a-float {
0% {
bottom: 0;
opacity: 0;
@ -1166,7 +1161,7 @@ br {
}
}
@keyframes implode {
@keyframes a-implode {
0%,
100% {
transform: scale(1);
@ -1179,7 +1174,7 @@ br {
}
}
@keyframes eternify {
@keyframes a-eternify {
0% {
opacity: 1;
filter: blur(0);
@ -1221,7 +1216,7 @@ br {
}
}
@keyframes dilate {
@keyframes a-dilate {
0% {
opacity: 1;
transform: scaleX(1);
@ -1243,7 +1238,7 @@ br {
}
}
@keyframes undilate {
@keyframes a-undilate {
0% {
opacity: 1;
transform: scaleX(1);
@ -1265,14 +1260,14 @@ br {
}
}
@keyframes realize {
@keyframes a-realize {
0% { opacity: 1; }
20% { opacity: 0; }
80% { opacity: 0; }
100% { opacity: 1; }
}
@keyframes realizebg {
@keyframes a-realizebg {
0% { opacity: 0; }
20% { opacity: 0; }
30% { opacity: 1; }
@ -1281,41 +1276,41 @@ br {
100% { opacity: 0; }
}
@keyframes text-grow {
@keyframes a-text-grow {
0% { font-size: 1.3rem; }
50% { font-size: 1.8rem; }
100% { font-size: 1.3rem; }
}
@keyframes text-shrink {
@keyframes a-text-shrink {
0% { font-size: 1.8rem; }
50% { font-size: 1.3rem; }
100% { font-size: 1.8rem; }
}
@keyframes text-crunch {
@keyframes a-text-crunch {
0% { font-size: 1.5rem; }
90% { font-size: 1.5rem; }
100% { font-size: 0; }
}
@keyframes text-flash {
@keyframes a-text-flash {
0% { color: yellow; }
50% { color: red; }
}
@keyframes fade-out {
@keyframes a-fade-out {
0% { opacity: 1; }
50% { opacity: 0; }
100% { opacity: 1; }
}
@keyframes disappear {
@keyframes a-disappear {
0% { opacity: 1; }
100% { opacity: 0; }
}
@keyframes text-stretch {
@keyframes a-text-stretch {
0% { letter-spacing: 0; }
100% { letter-spacing: 30rem; }
}
@ -7776,8 +7771,6 @@ kbd {
display: flex;
flex-direction: column;
width: 60rem;
text-align: left;
font-size: 1.2rem;
padding: 0.25rem 1rem;
}
@ -9269,7 +9262,7 @@ input.o-automator-block-input {
font: 1rem Typewriter, serif;
font-weight: bold;
color: var(--color-text);
background-color: var(--color-base);
background-color: var(--color-text-inverted);
border: 0.1rem solid black;
border-radius: var(--var-border-radius, 0.4rem);
box-shadow: none;
@ -9305,45 +9298,37 @@ input.o-automator-block-input {
.c-hide-modal-tab-button--infinity {
color: var(--color-infinity);
background: var(--color-prestige--accent);
border-color: var(--color-infinity);
}
.c-hide-modal-tab-button--infinity:hover {
color: var(--color-prestige--accent);
background: var(--color-infinity);
}
.c-hide-modal-tab-button--eternity {
color: var(--color-eternity);
background: var(--color-prestige--accent);
border-color: var(--color-eternity);
}
.c-hide-modal-tab-button--eternity:hover {
color: var(--color-prestige--accent);
background: var(--color-eternity);
}
.c-hide-modal-tab-button--reality {
color: var(--color-reality);
background: var(--color-prestige--accent);
border-color: var(--color-reality);
}
.c-hide-modal-tab-button--reality:hover {
color: var(--color-prestige--accent);
background: var(--color-reality);
}
.c-hide-modal-tab-button--celestials {
color: var(--color-celestials);
background: var(--color-prestige--accent);
border-color: var(--color-celestials);
}
.c-hide-modal-tab-button--celestials:hover {
color: var(--color-prestige--accent);
background: var(--color-celestials);
}
@ -9354,7 +9339,7 @@ input.o-automator-block-input {
font-family: "Font Awesome 6 Free" !important;
}
@keyframes opacity {
@keyframes a-opacity {
0% { opacity: 0; }
50% { opacity: 0.4; }
100% { opacity: 0; }
@ -9373,7 +9358,7 @@ input.o-automator-block-input {
left: 0;
background: gold;
border-radius: var(--var-border-radius, inherit);
animation: opacity 3s infinite;
animation: a-opacity 3s infinite;
}
.o-celestial-nav__hoverable .tooltiptext {

View File

@ -45,18 +45,17 @@ body.t-s1 {
z-index: 0;
opacity: 1;
background-image: url("../images/snow1.png"), url("../images/snow2.png"), url("../images/snow3.png");
animation: snow 10s linear infinite, snowFade 10s cubic-bezier(0, 0.3, 1, 0.7) infinite;
animation: a-snow 10s linear infinite, a-snow-fade 10s cubic-bezier(0, 0.3, 1, 0.7) infinite;
pointer-events: none;
}
@keyframes snow {
@keyframes a-snow {
0% { background-position: 0 0, 0 0, 0 0; }
50% { background-position: 500px 500px, 100px 200px, -100px 150px; }
100% { background-position: 1000px 1000px, 200px 400px, -200px 300px; }
}
/* stylelint-disable-next-line keyframes-name-pattern */
@keyframes snowFade {
@keyframes a-snow-fade {
0% { opacity: 0; }
50% { opacity: 1; }
100% { opacity: 0; }

View File

@ -5,10 +5,10 @@ body {
.t-s3 #ui,
.t-s3 #ui-fixed,
.t-s3 .c-glyph-tooltip {
animation: glasses 7s infinite;
animation: a-glasses 7s infinite;
}
@keyframes glasses {
@keyframes a-glasses {
0% { filter: blur(0); }
10% { filter: blur(3px); }
20% { filter: blur(0); }

View File

@ -78,8 +78,6 @@ export default {
name: this.text,
glyphSet: this.glyphs,
closeOn: GAME_EVENT.GLYPH_SET_SAVE_CHANGE,
isGlyphSelection: false,
showSetName: true,
displaySacrifice: this.showSacrifice,
});
}

View File

@ -59,6 +59,6 @@ export default {
}
.t-s3 .o-save-timer {
animation: glasses 7s infinite;
animation: a-glasses 7s infinite;
}
</style>

View File

@ -7,9 +7,21 @@ export default {
ModalWrapper,
},
props: {
modalConfig: {
type: Object,
required: true
warnings: {
type: Function,
required: true,
},
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
inputs: {
type: Array,
required: true,
}
},
data() {
@ -24,14 +36,14 @@ export default {
computed: {
presets: () => player.timestudy.presets,
params: () => GameDatabase.reality.automator.templates.paramTypes,
warnings() {
validWarnings() {
return this.invalidInputCount === 0
? this.modalConfig.warnings().concat(this.templateScript?.warnings)
: this.modalConfig.warnings();
? this.warnings().concat(this.templateScript?.warnings)
: this.warnings();
},
templateScript() {
if (this.invalidInputCount !== 0) return null;
return new ScriptTemplate(this.templateProps, this.modalConfig.name);
return new ScriptTemplate(this.templateProps, this.name);
}
},
// Many props in this component are generated dynamically from a GameDB entry, but Vue can only give reactive
@ -39,7 +51,7 @@ export default {
// specifically $set them here on initialization; additionally we give them a default value so that later function
// calls don't error out from undefined inputs.
created() {
for (const input of this.modalConfig.inputs) {
for (const input of this.inputs) {
const boolProp = this.paramTypeObject(input.type).boolDisplay;
if (boolProp) {
this.$set(this.templateInputs, input.name, false);
@ -77,7 +89,7 @@ export default {
updateTemplateProps() {
this.templateProps = {};
this.invalidInputCount = 0;
for (const input of this.modalConfig.inputs) {
for (const input of this.inputs) {
const typeObj = this.paramTypeObject(input.type);
const mapFn = x => (typeObj.map ? typeObj.map(x) : x);
this.templateProps[input.name] = mapFn(this.templateInputs[input.name]);
@ -108,10 +120,10 @@ export default {
<template>
<ModalWrapper class="c-automator-template-container">
<template #header>
{{ modalConfig.name }} Template
{{ name }} Template
</template>
<div class="c-automator-template-description">
{{ modalConfig.description }}
{{ description }}
</div>
<div class="c-automator-template-inputs">
<b>Required Information:</b>
@ -132,7 +144,7 @@ export default {
<i>Current Tree</i>
</button>
<div
v-for="input in modalConfig.inputs"
v-for="input in inputs"
:key="input.name"
class="c-automator-template-entry"
>
@ -159,9 +171,9 @@ export default {
</div>
<div class="c-automator-template-warnings">
<b>Possible things to consider:</b>
<div v-if="warnings.length !== 0">
<div v-if="validWarnings.length !== 0">
<div
v-for="warning in warnings"
v-for="warning in validWarnings"
:key="warning"
class="c-automator-template-entry"
>

View File

@ -9,10 +9,18 @@ export default {
ModalWrapper,
},
props: {
modalConfig: {
playerBefore: {
type: Object,
required: true
}
required: true,
},
playerAfter: {
type: Object,
required: true,
},
seconds: {
type: Number,
required: true,
},
},
data() {
return {
@ -23,17 +31,11 @@ export default {
nothingHappened() {
return Theme.current().name === "S9";
},
before() {
return this.modalConfig.playerBefore;
},
after() {
return this.modalConfig.playerAfter;
},
offlineStats() {
return AwayProgressTypes.appearsInAwayModal;
},
headerText() {
const timeDisplay = TimeSpan.fromSeconds(this.modalConfig.seconds).toString();
const timeDisplay = TimeSpan.fromSeconds(this.seconds).toString();
if (this.nothingHappened || !this.somethingHappened) {
return `While you were away for ${timeDisplay}... Nothing happened.`;
}
@ -62,8 +64,8 @@ export default {
v-for="name of offlineStats"
:key="name"
:name="name"
:player-before="before"
:player-after="after"
:player-before="playerBefore"
:player-after="playerAfter"
@something-happened="somethingHappened = true"
/>
</div>

View File

@ -7,19 +7,14 @@ export default {
ModalWrapperChoice
},
props: {
modalConfig: {
type: Object,
scriptID: {
type: [String, Number],
required: true
}
},
computed: {
modal() {
return this.$viewModel.modal.current;
},
},
methods: {
handleYesClick() {
const script = this.modalConfig.scriptID;
const script = this.scriptID;
const runningScriptID = AutomatorBackend.state.topLevelScript;
AutomatorBackend.deleteScript(script);
@ -34,17 +29,6 @@ export default {
// AutomatorBackend.deleteScript will create an empty script if necessary
player.reality.automator.state.editorScript = scriptList[0].id;
}
// Deleting a script leaves a gap in ids, shift all of them down to fill it
let newID = 0;
const shiftedScripts = {};
for (const id of Object.keys(player.reality.automator.scripts)) {
shiftedScripts[newID] = player.reality.automator.scripts[id];
shiftedScripts[newID].id = newID;
newID++;
}
player.reality.automator.scripts = shiftedScripts;
EventHub.dispatch(GAME_EVENT.AUTOMATOR_SAVE_CHANGED);
},
},

View File

@ -62,8 +62,8 @@ export default {
this.canGetHint = this.currentStored >= this.nextHintCost;
this.shownEntries = [];
this.realityHintsLeft = Object.values(EnslavedProgress).length;
for (const prog of Object.values(EnslavedProgress)) {
this.realityHintsLeft = EnslavedProgress.all.length;
for (const prog of EnslavedProgress.all) {
if (prog.hasHint) {
this.shownEntries.push([prog.hasProgress
? prog.config.progress
@ -82,7 +82,7 @@ export default {
},
giveRealityHint(available) {
if (available <= 0 || !Enslaved.spendTimeForHint()) return;
Object.values(EnslavedProgress).filter(prog => !prog.hasHint).randomElement().unlock();
EnslavedProgress.all.filter(prog => !prog.hasHint).randomElement().unlock();
},
giveGlyphHint(available) {
if (available <= 0 || !Enslaved.spendTimeForHint()) return;

View File

@ -9,8 +9,8 @@ export default {
GlyphSetPreview
},
props: {
modalConfig: {
type: Object,
glyphSetId: {
type: Number,
required: true
}
},
@ -21,10 +21,10 @@ export default {
},
methods: {
update() {
this.glyphSet = Glyphs.copyForRecords(player.reality.glyphs.sets[this.modalConfig.glyphSetId].glyphs);
this.glyphSet = Glyphs.copyForRecords(player.reality.glyphs.sets[this.glyphSetId].glyphs);
},
handleYesClick() {
player.reality.glyphs.sets[this.modalConfig.glyphSetId].glyphs = [];
player.reality.glyphs.sets[this.glyphSetId].glyphs = [];
EventHub.dispatch(GAME_EVENT.GLYPH_SET_SAVE_CHANGE);
},
},

View File

@ -11,16 +11,30 @@ export default {
GlyphShowcasePanelEntry,
},
props: {
modalConfig: {
type: Object,
required: true,
name: String,
glyphSet: Array,
closeOn: String,
isGlyphSelection: Boolean,
showSetName: Boolean,
displaySacrifice: Boolean,
}
name: {
type: String,
required: true
},
glyphSet: {
type: Array,
required: true
},
closeOn: {
type: String,
required: true
},
isGlyphSelection: {
type: Boolean,
default: false
},
showSetName: {
type: Boolean,
default: true
},
displaySacrifice: {
type: Boolean,
default: true
},
},
data() {
return {
@ -31,9 +45,6 @@ export default {
};
},
computed: {
isGlyphSelection() {
return this.modalConfig.isGlyphSelection;
},
maxGlyphEffects() {
let maxEffects = 1;
for (const glyph of this.glyphs) {
@ -43,13 +54,13 @@ export default {
},
},
created() {
this.on$(this.modalConfig.closeOn, this.emitClose);
this.on$(this.closeOn, this.emitClose);
},
methods: {
update() {
this.glyphs = this.isGlyphSelection
? GlyphSelection.glyphList(GlyphSelection.choiceCount, gainedGlyphLevel(), { isChoosingGlyph: false })
: this.modalConfig.glyphSet.filter(x => x);
: this.glyphSet.filter(x => x);
this.gainedLevel = gainedGlyphLevel().actualLevel;
// There should only be one reality glyph; this picks one pseudo-randomly if multiple are cheated/glitched in
const realityGlyph = this.glyphs.filter(g => g.type === "reality")[0];
@ -64,13 +75,13 @@ export default {
<template>
<ModalWrapper>
<template #header>
{{ modalConfig.name }}
{{ name }}
</template>
<div v-if="isGlyphSelection">
Projected Glyph Level: {{ formatInt(gainedLevel) }}
</div>
<GlyphSetName
v-if="modalConfig.showSetName"
v-if="showSetName"
:glyph-set="glyphs"
:force-color="true"
/>
@ -84,7 +95,7 @@ export default {
:show-level="!isGlyphSelection"
:reality-glyph-boost="realityGlyphBoost"
:max-glyph-effects="maxGlyphEffects"
:show-sacrifice="modalConfig.displaySacrifice"
:show-sacrifice="displaySacrifice"
/>
</div>
</ModalWrapper>

View File

@ -6,12 +6,6 @@ export default {
components: {
ModalCloseButton,
},
props: {
modalConfig: {
required: true,
type: Object,
}
},
data() {
return {
tabId: 0,
@ -123,4 +117,4 @@ export default {
.s-base--dark .o-h2p-tab-button--first-irrelevant {
border-top-color: white;
}
</style>
</style>

View File

@ -35,6 +35,7 @@ export default {
<component
:is="modal.component"
v-if="modal.isBare && !forceDontShowModal"
v-bind="modal.props"
:modal-config="modal.props"
/>
<div
@ -43,6 +44,7 @@ export default {
>
<component
:is="modal.component"
v-bind="modal.props"
:modal-config="modal.props"
@close="hide"
/>

View File

@ -51,44 +51,58 @@ export default {
</script>
<template>
<ModalWrapper class="c-reality-glyph-creation">
<ModalWrapper>
<template #header>
Reality Glyph Creation
</template>
<div>
Create a level {{ formatInt(realityGlyphLevel) }} Reality Glyph.
Rarity will always be {{ formatPercents(1) }}
and level scales on your current reality resource amount (which is all consumed). All other alchemy resources will
be unaffected. Reality Glyphs have unique effects, some of which are only available with higher level Glyphs.
Reality Glyphs can also be sacrificed to increase the yield from alchemy reactions. Like Effarig Glyphs,
you cannot equip more than one at the same time.
<div class="c-reality-glyph-creation">
<div>
Create a level {{ formatInt(realityGlyphLevel) }} Reality Glyph.
Rarity will always be {{ formatPercents(1) }} and
level scales on your current reality resource amount (which is all consumed). All other alchemy resources will
be unaffected. Reality Glyphs have unique effects, some of which are only available with higher level Glyphs.
Reality Glyphs can also be sacrificed to increase the yield from alchemy reactions. Like Effarig Glyphs,
you cannot equip more than one at the same time.
</div>
<div class="o-available-effects-container">
<div class="o-available-effects">
Available Effects:
</div>
<div
v-for="(effect, index) in possibleEffects"
:key="index"
>
{{ formatGlyphEffect(effect) }}
</div>
</div>
<PrimaryButton
v-if="isDoomed"
:enabled="false"
>
You cannot create Reality Glyphs while in Doomed
</PrimaryButton>
<PrimaryButton
v-else-if="realityGlyphLevel !== 0"
@click="createRealityGlyph"
>
Create a Reality Glyph!
</PrimaryButton>
<PrimaryButton
v-else
:enabled="false"
>
Reality Glyph level must be higher than {{ formatInt(0) }}
</PrimaryButton>
</div>
<div>
Available Effects:
</div>
<div
v-for="(effect, index) in possibleEffects"
:key="index"
>
{{ formatGlyphEffect(effect) }}
</div><br>
<PrimaryButton
v-if="isDoomed"
:enabled="false"
>
You cannot create Reality Glyphs while in Doomed
</PrimaryButton>
<PrimaryButton
v-else-if="realityGlyphLevel !== 0"
@click="createRealityGlyph"
>
Create a Reality Glyph!
</PrimaryButton>
<PrimaryButton
v-else
:enabled="false"
>
Reality Glyph level must be higher than {{ formatInt(0) }}
</PrimaryButton>
</ModalWrapper>
</template>
<style scoped>
.o-available-effects-container {
margin: 1.5rem 0 2rem;
}
.o-available-effects {
font-weight: bold;
}
</style>

View File

@ -7,21 +7,25 @@ export default {
ModalWrapperChoice
},
props: {
modalConfig: {
type: Object,
targetSlot: {
type: Number,
required: true
},
inventoryIndex: {
type: Number,
required: true
}
},
data() {
return {
targetSlot: 0,
target: 0,
idx: 0,
};
},
methods: {
update() {
this.targetSlot = this.modalConfig.targetSlot;
this.idx = this.modalConfig.inventoryIndex;
this.target = this.targetSlot;
this.idx = this.inventoryIndex;
this.glyph = Glyphs.findByInventoryIndex(this.idx);
},
handleYesClick() {

View File

@ -2,17 +2,19 @@
import { sha512_256 } from "js-sha512";
import ModalWrapperChoice from "@/components/modals/ModalWrapperChoice";
import PrimaryButton from "@/components/PrimaryButton";
import StudyStringLine from "@/components/modals/StudyStringLine";
export default {
name: "StudyStringModal",
components: {
ModalWrapperChoice,
StudyStringLine
StudyStringLine,
PrimaryButton
},
props: {
modalConfig: {
type: Object,
id: {
type: Number,
required: true,
}
},
@ -26,7 +28,7 @@ export default {
// This modal is used by both study importing and preset editing but only has a prop actually passed in when
// editing (which is the preset index). Needs to be an undefined check because index can be zero
isImporting() {
return this.modalConfig.id === undefined;
return this.id === undefined;
},
// This represents the state reached from importing into an empty tree
importedTree() {
@ -119,7 +121,7 @@ export default {
},
// Needs to be assigned in created() or else they will end up being undefined when importing
created() {
const preset = player.timestudy.presets[this.modalConfig.id];
const preset = player.timestudy.presets[this.id];
this.input = preset ? preset.studies : "";
this.name = preset ? preset.name : "";
},
@ -131,6 +133,9 @@ export default {
if (this.isImporting) this.importTree();
else this.savePreset();
},
convertInputShorthands() {
this.input = TimeStudyTree.formatStudyList(this.input);
},
importTree() {
if (!this.inputIsValid) return;
if (this.inputIsSecret) SecretAchievement(37).unlock();
@ -141,7 +146,7 @@ export default {
},
savePreset() {
if (this.inputIsValid) {
player.timestudy.presets[this.modalConfig.id].studies = TimeStudyTree.formatStudyList(this.input);
player.timestudy.presets[this.id].studies = this.input;
GameUI.notify.eternity(`Study Tree ${this.name} successfully edited.`);
this.emitClose();
}
@ -216,6 +221,12 @@ export default {
Not a valid tree
</div>
</div>
<div v-if="!isImporting && inputIsValidTree">
<br>
<PrimaryButton @click="convertInputShorthands">
Collapse Study ID list Shorthands
</PrimaryButton>
</div>
<template #confirm-text>
{{ isImporting ? "Import" : "Save" }}
</template>

View File

@ -0,0 +1,73 @@
<script>
import ModalWrapperChoice from "@/components/modals/ModalWrapperChoice";
export default {
name: "SwitchAutomatorEditorModal",
components: {
ModalWrapperChoice
},
props: {
modalConfig: {
type: Object,
required: false,
default: () => ({})
}
},
data() {
return {
isCurrentlyBlocks: false
};
},
computed: {
currentScriptID: {
get() {
return this.$viewModel.tabs.reality.automator.editorScriptID;
},
set(value) {
this.$viewModel.tabs.reality.automator.editorScriptID = value;
}
},
currentScriptContent() {
return player.reality.automator.scripts[this.currentScriptID].content;
},
},
methods: {
update() {
this.isCurrentlyBlocks = player.reality.automator.type === AUTOMATOR_TYPE.BLOCK;
},
toggleAutomatorMode() {
const scriptID = this.currentScriptID;
Tutorial.moveOn(TUTORIAL_STATE.AUTOMATOR);
if (this.isCurrentlyBlocks) {
// This saves the script after converting it.
BlockAutomator.parseTextFromBlocks();
player.reality.automator.type = AUTOMATOR_TYPE.TEXT;
} else if (BlockAutomator.fromText(this.currentScriptContent)) {
AutomatorBackend.saveScript(scriptID, AutomatorTextUI.editor.getDoc().getValue());
player.reality.automator.type = AUTOMATOR_TYPE.BLOCK;
} else {
Modal.message.show("Automator script has errors, cannot convert to blocks.");
}
this.modalConfig.callback?.();
}
}
};
</script>
<template>
<ModalWrapperChoice
option="switchAutomatorMode"
@confirm="toggleAutomatorMode"
>
<template #header>
Change Automator to {{ isCurrentlyBlocks ? "text" : "block" }} editor
</template>
<div class="c-modal-message__text">
Are you sure you want to change to the {{ isCurrentlyBlocks ? "text" : "block" }} editor?
This will stop your current script!
</div>
<template #confirm-text>
Change Modes
</template>
</ModalWrapperChoice>
</template>

View File

@ -6,16 +6,19 @@ export default {
components: {
ModalWrapperChoice
},
props: {
id: {
type: Number,
required: true
}
},
computed: {
challenge() {
return EternityChallenge(this.modal.id);
return EternityChallenge(this.id);
},
challengeIsCompleted() {
return this.challenge.isFullyCompleted;
},
modal() {
return this.$viewModel.modal.current;
},
message() {
return `You will Eternity, if possible, and start a new Eternity within the Challenge, with all the
Challenge-specific restrictions and modifiers active.
@ -25,7 +28,7 @@ export default {
${formatInt(5)} times, with increasing goals and bonuses.`;
},
entranceLabel() {
return `You are about to enter Eternity Challenge ${this.modal.id}`;
return `You are about to enter Eternity Challenge ${this.id}`;
},
reward() {
let rewardDescription = this.challenge._config.reward.description;

View File

@ -6,26 +6,29 @@ export default {
components: {
ModalWrapperChoice
},
props: {
id: {
type: Number,
required: true
}
},
computed: {
challenge() {
return InfinityChallenge(this.modal.id);
return InfinityChallenge(this.id);
},
challengeIsCompleted() {
return this.challenge.isCompleted;
},
modal() {
return this.$viewModel.modal.current;
},
message() {
return `You will Big Crunch, if possible, and start a new Infinity within the Challenge, with all the
Challenge-specific restrictions and modifiers active.
To complete the Challenge${this.challengeIsCompleted ? "" : " and gain its reward"},
you must reach the Challenge goal of
${format(InfinityChallenge(this.modal.id).goal)} Antimatter.
${format(InfinityChallenge(this.id).goal)} Antimatter.
You do not start with any Dimension Boosts or Galaxies, regardless of upgrades.`;
},
entranceLabel() {
return `You are about to enter Infinity Challenge ${this.modal.id}`;
return `You are about to enter Infinity Challenge ${this.id}`;
},
reward() {
let rewardDescription = this.challenge._config.reward.description;

View File

@ -6,16 +6,19 @@ export default {
components: {
ModalWrapperChoice
},
props: {
id: {
type: Number,
required: true
}
},
computed: {
challenge() {
return NormalChallenge(this.modal.id);
return NormalChallenge(this.id);
},
challengeIsCompleted() {
return this.challenge.isCompleted;
},
modal() {
return this.$viewModel.modal.current;
},
message() {
return `You will Big Crunch, if possible, and start a new Infinity within the Challenge, with all the
Challenge-specific restrictions and modifiers active.
@ -24,7 +27,7 @@ export default {
You do not start with any Dimension Boosts or Galaxies, regardless of upgrades.`;
},
entranceLabel() {
return `You are about to enter Challenge ${this.modal.id}`;
return `You are about to enter Challenge ${this.id}`;
},
reward() {
return `The reward for completing this challenge is: ${this.challenge._config.reward}`;

View File

@ -12,9 +12,6 @@ export default {
};
},
computed: {
modal() {
return this.$viewModel.modal.current;
},
message() {
switch (this.messageIndex) {
case 0: return "Are you sure you want to get rid of your Companion Glyph?";

View File

@ -7,8 +7,8 @@ export default {
ModalWrapperChoice
},
props: {
modalConfig: {
type: Object,
idx: {
type: Number,
required: true
}
},
@ -19,12 +19,12 @@ export default {
},
computed: {
glyph() {
return Glyphs.findByInventoryIndex(this.modalConfig.idx);
return Glyphs.findByInventoryIndex(this.idx);
},
},
methods: {
update() {
const newGlyph = Glyphs.findByInventoryIndex(this.modalConfig.idx);
const newGlyph = Glyphs.findByInventoryIndex(this.idx);
if (this.glyph !== newGlyph && this.confirmedDelete) {
// Why is confirmedDelete here: refer to SacrificeGlyphModal.vue

View File

@ -7,8 +7,8 @@ export default {
ModalWrapperChoice
},
props: {
modalConfig: {
type: Object,
harsh: {
type: Boolean,
required: true
}
},
@ -19,9 +19,6 @@ export default {
};
},
computed: {
harsh() {
return this.modalConfig.harsh;
},
threshold() {
return this.harsh ? 1 : 5;
},

View File

@ -7,8 +7,8 @@ export default {
ModalWrapperChoice
},
props: {
modalConfig: {
type: Object,
idx: {
type: Number,
required: true
}
},
@ -24,7 +24,7 @@ export default {
},
computed: {
glyph() {
return Glyphs.findByInventoryIndex(this.modalConfig.idx);
return Glyphs.findByInventoryIndex(this.idx);
},
resource() {
return GlyphSacrificeHandler.glyphAlchemyResource(this.glyph);
@ -43,7 +43,7 @@ export default {
this.after = this.resourceAmount + this.gain;
const newGlyph = Glyphs.findByInventoryIndex(this.modalConfig.idx);
const newGlyph = Glyphs.findByInventoryIndex(this.idx);
if (this.glyph !== newGlyph && !this.confirmedRefine) {
// Why is confirmedRefine here: refer to SacrificeGlyphModal.vue

View File

@ -7,8 +7,8 @@ export default {
ModalWrapperChoice
},
props: {
modalConfig: {
type: Object,
idx: {
type: Number,
required: true
}
},
@ -21,7 +21,7 @@ export default {
},
computed: {
glyph() {
return Glyphs.findByInventoryIndex(this.modalConfig.idx);
return Glyphs.findByInventoryIndex(this.idx);
},
message() {
return `Do you really want to sacrifice this Glyph? Your total power of sacrificed ${this.glyph.type}
@ -34,7 +34,7 @@ export default {
this.currentGlyphSacrifice = player.reality.glyphs.sac[this.glyph.type];
this.gain = GlyphSacrificeHandler.glyphSacrificeGain(this.glyph);
const newGlyph = Glyphs.findByInventoryIndex(this.modalConfig.idx);
const newGlyph = Glyphs.findByInventoryIndex(this.idx);
if (this.glyph !== newGlyph && !this.confirmedSacrifice) {
// ConfirmedSacrifice is here because when you sac a glyph with confirmation it

View File

@ -7,8 +7,8 @@ export default {
ModalWrapperChoice
},
props: {
modalConfig: {
type: Object,
bulk: {
type: Number,
required: true,
}
},
@ -21,7 +21,6 @@ export default {
};
},
computed: {
bulk() { return this.modalConfig.bulk; },
topLabel() {
if (this.bulk) return `You are about to purchase ${quantifyInt("Antimatter Galaxy", this.newGalaxies)}`;
return `You are about to purchase an Antimatter Galaxy`;

View File

@ -7,13 +7,12 @@ export default {
ModalWrapperChoice
},
props: {
modalConfig: {
type: Object,
bulk: {
type: Number,
required: true,
}
},
computed: {
bulk() { return this.modalConfig.bulk; },
topLabel() {
return `You are about to do a Dimension Boost Reset`;
},

View File

@ -9,20 +9,24 @@ export default {
EnterCelestialsRaPet,
},
props: {
modalConfig: {
type: Object,
number: {
type: Number,
required: true,
},
name: {
type: String,
required: true
}
},
computed: {
description() {
return GameDatabase.celestials.descriptions[this.modalConfig.number].description().split("\n");
return GameDatabase.celestials.descriptions[this.number].description().split("\n");
},
topLabel() {
return `${this.modalConfig.name} Reality`;
return `${this.name} Reality`;
},
message() {
return `Perform a Reality reset, and enter ${this.modalConfig.name} Reality, in which`;
return `Perform a Reality reset, and enter ${this.name} Reality, in which`;
},
},
methods: {
@ -37,7 +41,7 @@ export default {
const laitelaFastest = player.celestials.laitela.fastestCompletion;
const laitalaTime = TimeSpan.fromSeconds(laitelaFastest).toStringShort();
switch (this.modalConfig.number) {
switch (this.number) {
case 0: return `Your highest Teresa completetion was for ${format(teresaBestAM, 2, 2)}
antimatter, gaining you a ${formatX(teresaRunMult, 2)} multiplier to Glyph Sacrifice power.`;
case 1: return `${effarigDone
@ -64,7 +68,7 @@ export default {
},
handleYesClick() {
beginProcessReality(getRealityProps(true));
switch (this.modalConfig.number) {
switch (this.number) {
case 0: return Teresa.initializeRun();
case 1: return Effarig.initializeRun();
case 2: return Enslaved.initializeRun();
@ -95,7 +99,7 @@ export default {
<div>
{{ extraLine() }}
</div>
<span v-if="modalConfig.number === 4">
<span v-if="number === 4">
<EnterCelestialsRaPet
v-for="id in 4"
:key="id"

View File

@ -8,9 +8,6 @@ export default {
ModalWrapperChoice
},
computed: {
modal() {
return this.$viewModel.modal.current;
},
message() {
return `Dilating time will start a new Eternity, and all Dimension multiplier's exponents and
tickspeed multiplier's exponent will be reduced to ${formatPow(0.75, 2, 2)}. If you can Eternity while Dilated,

View File

@ -21,6 +21,7 @@ export default {
alchemyCap: 0,
capFactor: 0,
createdRealityGlyph: false,
allReactionsDisabled: false
};
},
computed: {
@ -46,6 +47,9 @@ export default {
"tutorial--glow": !this.createdRealityGlyph
};
},
reactions() {
return AlchemyReactions.all.compact().filter(r => r.product.isUnlocked);
}
},
methods: {
update() {
@ -55,6 +59,7 @@ export default {
this.alchemyCap = Ra.alchemyResourceCap;
this.capFactor = 1 / GlyphSacrificeHandler.glyphRefinementEfficiency;
this.createdRealityGlyph = player.reality.glyphs.createdRealityGlyph;
this.allReactionsDisabled = this.reactions.every(reaction => !reaction.isActive);
},
orbitSize(orbit) {
const maxRadius = this.layout.orbits.map(o => o.radius).max();
@ -151,18 +156,11 @@ export default {
Modal.h2p.show();
},
toggleAllReactions() {
const reactions = AlchemyReactions.all.compact().filter(r => r._product.isUnlocked);
const allReactionsDisabled = reactions.every(reaction => !reaction.isActive);
if (allReactionsDisabled) {
for (const reaction of reactions) {
reaction.isActive = true;
}
} else {
for (const reaction of reactions) {
reaction.isActive = false;
}
const setIsActive = this.allReactionsDisabled;
for (const reaction of this.reactions) {
reaction.isActive = setIsActive;
}
}
},
}
};
</script>
@ -180,7 +178,7 @@ export default {
class="o-primary-btn--subtab-option"
@click="toggleAllReactions"
>
Toggle all reactions
{{ allReactionsDisabled ? "Enable" : "Disable" }} all reactions
</PrimaryButton>
<PrimaryButton
v-if="realityCreationVisible"

View File

@ -13,6 +13,12 @@ export default {
repeatOn: false,
forceRestartOn: false,
followExecution: false,
hasErrors: false,
currentLine: 0,
statusName: "",
editingName: "",
duplicateStatus: false,
duplicateEditing: false,
};
},
computed: {
@ -32,6 +38,18 @@ export default {
"fa-eject": this.isPaused
};
},
statusText() {
// Pad with leading zeroes based on script length to prevent text jitter on fast scripts. This technically fails
// for scripts with more than 99999 lines, but scripts that long will be prevented elsewhere
const digits = Math.clampMin(Math.ceil(Math.log10(AutomatorBackend.currentScriptLength + 1)), 1);
let lineNum = `0000${this.currentLine}`;
lineNum = lineNum.slice(lineNum.length - digits);
if (this.isPaused) return `Paused: "${this.statusName}" (Resumes on Line ${lineNum})`;
if (this.isRunning) return `Running: "${this.statusName}" (Line ${lineNum})`;
if (this.hasErrors) return `Stopped: "${this.statusName}" has errors (Cannot run)`;
return `Stopped: Will start running "${this.statusName}"`;
},
},
methods: {
update() {
@ -40,9 +58,21 @@ export default {
this.repeatOn = AutomatorBackend.state.repeat;
this.forceRestartOn = AutomatorBackend.state.forceRestart;
this.followExecution = AutomatorBackend.state.followExecution;
this.hasErrors = AutomatorData.currentErrors().length !== 0;
this.currentLine = AutomatorBackend.currentLineNumber;
// When the automator isn't running, the script name contains the last run script instead of the
// to-be-run script, which is the currently displayed one in the editor
this.statusName = (this.isPaused || this.isRunning)
? AutomatorBackend.scriptName
: AutomatorBackend.currentEditingScript.name;
this.editingName = AutomatorBackend.currentEditingScript.name;
this.duplicateStatus = AutomatorBackend.hasDuplicateName(this.statusName);
this.duplicateEditing = AutomatorBackend.hasDuplicateName(this.editingName);
},
rewind: () => AutomatorBackend.restart(),
play() {
if (this.hasErrors) return;
if (this.isRunning) {
AutomatorBackend.pause();
return;
@ -64,52 +94,99 @@ export default {
</script>
<template>
<div class="c-automator__controls l-automator__controls l-automator-pane__controls">
<AutomatorButton
v-tooltip="'Rewind Automator to the first command'"
class="fa-fast-backward"
@click="rewind"
/>
<AutomatorButton
v-tooltip="{
content: playTooltip,
hideOnTargetClick: false
}"
:class="playButtonClass"
@click="play"
/>
<AutomatorButton
v-tooltip="'Stop Automator and reset position'"
class="fa-stop"
@click="stop"
/>
<AutomatorButton
v-tooltip="'Step forward one line'"
class="fa-step-forward"
@click="step"
/>
<AutomatorButton
v-tooltip="'Restart script automatically when it completes'"
class="fa-sync-alt"
:class="{ 'c-automator__button--active' : repeatOn }"
@click="repeat"
/>
<AutomatorButton
v-tooltip="'Restart script when finishing or restarting a Reality'"
class="fa-reply"
:class="{ 'c-automator__button--active' : forceRestartOn }"
@click="restart"
/>
<AutomatorButton
v-tooltip="'Scroll Automator to follow current line'"
class="fa-indent"
:class="{ 'c-automator__button--active' : followExecution }"
@click="follow"
/>
<div class="c-automator__controls l-automator__controls">
<div class="l-automator-button-row">
<AutomatorButton
v-tooltip="'Rewind Automator to the first command'"
class="fa-fast-backward"
@click="rewind"
/>
<AutomatorButton
v-tooltip="{
content: playTooltip,
hideOnTargetClick: false
}"
:class="playButtonClass"
@click="play"
/>
<AutomatorButton
v-tooltip="'Stop Automator and reset position'"
class="fa-stop"
@click="stop"
/>
<AutomatorButton
v-tooltip="'Step forward one line'"
class="fa-step-forward"
@click="step"
/>
<AutomatorButton
v-tooltip="'Restart script automatically when it completes'"
class="fa-sync-alt"
:class="{ 'c-automator__button--active' : repeatOn }"
@click="repeat"
/>
<AutomatorButton
v-tooltip="'Restart script when finishing or restarting a Reality'"
class="fa-reply"
:class="{ 'c-automator__button--active' : forceRestartOn }"
@click="restart"
/>
<AutomatorButton
v-tooltip="'Scroll Automator to follow current line'"
class="fa-indent"
:class="{ 'c-automator__button--active' : followExecution }"
@click="follow"
/>
<div class="c-automator__status-text c-automator__status-text--edit">
<span
v-if="duplicateEditing"
v-tooltip="'More than one script has this name!'"
class="fas fa-exclamation-triangle c-automator__status-text--error"
/>
{{ editingName }}
</div>
</div>
<div class="l-automator-button-row">
<span
v-if="duplicateStatus"
v-tooltip="'More than one script has this name!'"
class="fas fa-exclamation-triangle c-automator__status-text c-automator__status-text--error"
/>
<span
v-if="statusName !== editingName"
v-tooltip="'The automator is running a different script than the editor is showing'"
class="fas fa-circle-exclamation c-automator__status-text c-automator__status-text--warning"
/>
<span
class="c-automator__status-text"
:class="{ 'c-automator__status-text--error' : hasErrors && !isRunning }"
>
{{ statusText }}
</span>
</div>
</div>
</template>
<style scoped>
.c-automator__status-text {
font-size: 1.5rem;
color: var(--color-reality);
font-weight: bold;
padding: 0 0.5rem;
}
.c-automator__status-text--edit {
color: var(--color-accent);
}
.c-automator__status-text--warning {
color: var(--color-good-paused);
}
.c-automator__status-text--error {
color: var(--color-bad);
}
.c-automator__button--active {
background-color: var(--color-reality);
border-color: var(--color-reality-light);

View File

@ -5,6 +5,7 @@ import AutomatorDocsCommandList from "./AutomatorDocsCommandList";
import AutomatorDocsTemplateList from "./AutomatorDocsTemplateList";
import AutomatorErrorPage from "./AutomatorErrorPage";
import AutomatorEventLog from "./AutomatorEventLog";
import AutomatorModeSwitch from "./AutomatorModeSwitch";
export default {
name: "AutomatorDocs",
@ -14,7 +15,8 @@ export default {
AutomatorErrorPage,
AutomatorEventLog,
AutomatorBlocks,
AutomatorDocsTemplateList
AutomatorDocsTemplateList,
AutomatorModeSwitch,
},
data() {
return {
@ -128,6 +130,10 @@ export default {
this.currentScriptID = Object.keys(storedScripts)[0];
player.reality.automator.state.editorScript = this.currentScriptID;
}
if (!AutomatorGrammar.blockifyTextAutomator(this.currentScript)) {
player.reality.automator.type = AUTOMATOR_TYPE.TEXT;
Modal.message.show("Automator script has errors, cannot view in blocks.");
}
this.$nextTick(() => BlockAutomator.fromText(this.currentScript));
},
rename() {
@ -178,87 +184,93 @@ export default {
<template>
<div class="l-automator-pane">
<div class="c-automator__controls l-automator__controls l-automator-pane__controls">
<AutomatorButton
v-tooltip="'Scripting Information'"
class="fa-list"
:class="{ 'c-automator__button--active': infoPaneID === 1 }"
@click="infoPaneID = 1"
/>
<AutomatorButton
v-tooltip="blockTooltip"
:class="{
'fa-cubes': isBlock,
'fa-file-code': !isBlock,
'c-automator__button--active': infoPaneID === 2
}"
@click="infoPaneID = 2"
/>
<AutomatorButton
v-tooltip="errorTooltip"
:style="errorStyle"
class="fa-exclamation-triangle"
:class="{ 'c-automator__button--active': infoPaneID === 3 }"
@click="infoPaneID = 3"
/>
<AutomatorButton
v-tooltip="'View recently executed commands'"
class="fa-eye"
:class="{ 'c-automator__button--active': infoPaneID === 4 }"
@click="infoPaneID = 4"
/>
<AutomatorButton
v-tooltip="'Export automator script'"
class="fa-file-export"
@click="exportScript"
/>
<AutomatorButton
v-tooltip="'Import automator script'"
class="fa-file-import"
@click="importScript"
/>
<div class="l-automator__script-names">
<template v-if="!editingName">
<select
class="l-automator__scripts-dropdown"
@input="onScriptDropdown"
>
<option
v-for="script in scripts"
:key="script.id"
v-bind="selectedScriptAttribute(script.id)"
:value="script.id"
>
{{ dropdownLabel(script) }}
</option>
<option value="createNewScript">
Create new...
</option>
</select>
<AutomatorButton
v-tooltip="'Rename script'"
class="far fa-edit"
@click="rename"
/>
</template>
<input
v-else
ref="renameInput"
class="l-automator__rename-input"
@blur="nameEdited"
@keyup.enter="$refs.renameInput.blur()"
>
<div class="c-automator__controls l-automator__controls">
<div class="l-automator-button-row">
<AutomatorButton
v-tooltip="'Scripting Information'"
class="fa-list"
:class="{ 'c-automator__button--active': infoPaneID === 1 }"
@click="infoPaneID = 1"
/>
<AutomatorButton
v-tooltip="blockTooltip"
:class="{
'fa-cubes': isBlock,
'fa-file-code': !isBlock,
'c-automator__button--active': infoPaneID === 2
}"
@click="infoPaneID = 2"
/>
<AutomatorButton
v-tooltip="errorTooltip"
:style="errorStyle"
class="fa-exclamation-triangle"
:class="{ 'c-automator__button--active': infoPaneID === 3 }"
@click="infoPaneID = 3"
/>
<AutomatorButton
v-tooltip="'View recently executed commands'"
class="fa-eye"
:class="{ 'c-automator__button--active': infoPaneID === 4 }"
@click="infoPaneID = 4"
/>
<AutomatorModeSwitch />
<AutomatorButton
v-tooltip="fullScreenTooltip"
:class="fullScreenIconClass"
class="l-automator__expand-corner"
@click="fullScreen = !fullScreen"
/>
</div>
<div class="l-automator-button-row">
<AutomatorButton
v-tooltip="'Export automator script'"
class="fa-file-export"
@click="exportScript"
/>
<AutomatorButton
v-tooltip="'Import automator script'"
class="fa-file-import"
@click="importScript"
/>
<div class="l-automator__script-names">
<template v-if="!editingName">
<select
class="l-automator__scripts-dropdown"
@input="onScriptDropdown"
>
<option
v-for="script in scripts"
:key="script.id"
v-bind="selectedScriptAttribute(script.id)"
:value="script.id"
>
{{ dropdownLabel(script) }}
</option>
<option value="createNewScript">
Create new...
</option>
</select>
<AutomatorButton
v-tooltip="'Rename script'"
class="far fa-edit"
@click="rename"
/>
</template>
<input
v-else
ref="renameInput"
class="l-automator__rename-input"
@blur="nameEdited"
@keyup.enter="$refs.renameInput.blur()"
>
</div>
<AutomatorButton
v-tooltip="'Delete this script'"
class="fas fa-trash"
@click="deleteScript"
/>
</div>
<AutomatorButton
v-tooltip="'Delete this script'"
class="fas fa-trash"
@click="deleteScript"
/>
<AutomatorButton
v-tooltip="fullScreenTooltip"
:class="fullScreenIconClass"
@click="fullScreen = !fullScreen"
/>
</div>
<div class="c-automator-docs l-automator-pane__content">
<AutomatorDocsCommandList v-if="infoPaneID === 1" />
@ -273,6 +285,28 @@ export default {
</template>
<style scoped>
.l-automator__expand-corner {
position: absolute;
right: 0;
}
.l-automator__script-names {
display: flex;
flex-direction: row;
width: 50%;
justify-content: space-evenly;
align-items: center;
}
.l-automator__scripts-dropdown {
width: 90%;
height: 90%;
border-width: 0.1rem;
border-radius: 0;
margin: 0.4rem;
padding: 0.2rem 0 0.3rem;
}
.c-automator__button--active {
background-color: var(--color-reality);
border-color: var(--color-reality-light);

View File

@ -12,13 +12,7 @@ export default {
},
data() {
return {
activeLineRaw: 0,
automatorType: 0,
runningScriptID: 0,
activeLineInfo: {
lineNumber: 0,
scriptID: 0,
}
};
},
computed: {
@ -42,18 +36,6 @@ export default {
isTextAutomator() {
return this.automatorType === AUTOMATOR_TYPE.TEXT;
},
activeLine() {
return AutomatorBackend.state.topLevelScript === this.currentScriptID ? this.activeLineRaw : 0;
},
automatorModeTooltip() {
if (this.automatorType === AUTOMATOR_TYPE.BLOCK) return "Switch to the text editor";
return "Switch to the block editor";
},
tutorialClass() {
return {
"tutorial--glow": ui.view.tutorialState === TUTORIAL_STATE.AUTOMATOR && ui.view.tutorialActive
};
}
},
created() {
this.on$(GAME_EVENT.GAME_LOAD, () => this.onGameLoad());
@ -62,20 +44,8 @@ export default {
},
methods: {
update() {
this.runningScriptID = AutomatorBackend.state.topLevelScript;
this.automatorType = player.reality.automator.type;
if (AutomatorBackend.isOn) {
this.activeLineInfo = {
lineNumber: AutomatorBackend.stack.top.lineNumber,
scriptID: AutomatorBackend.state.topLevelScript,
};
} else {
this.activeLineInfo = {
lineNumber: 0,
scriptID: "0",
};
if (AutomatorTextUI.editor) AutomatorTextUI.editor.performLint();
}
if (!AutomatorBackend.isOn && AutomatorTextUI.editor) AutomatorTextUI.editor.performLint();
},
onGameLoad() {
this.updateCurrentScriptID();
@ -95,44 +65,14 @@ export default {
}
this.$nextTick(() => BlockAutomator.fromText(this.currentScript));
},
toggleAutomatorMode() {
const scriptID = ui.view.tabs.reality.automator.editorScriptID;
Tutorial.moveOn(TUTORIAL_STATE.AUTOMATOR);
if (this.automatorType === AUTOMATOR_TYPE.BLOCK) {
// This saves the script after converting it.
BlockAutomator.parseTextFromBlocks();
player.reality.automator.type = AUTOMATOR_TYPE.TEXT;
} else if (BlockAutomator.fromText(this.currentScriptContent)) {
AutomatorBackend.saveScript(scriptID, AutomatorTextUI.editor.getDoc().getValue());
player.reality.automator.type = AUTOMATOR_TYPE.BLOCK;
} else {
Modal.message.show("Automator script has errors, cannot convert to blocks.");
}
this.$recompute("currentScriptContent");
}
}
};
</script>
<template>
<div class="l-automator-pane">
<div class="c-automator__controls l-automator__controls l-automator-pane__controls">
<div class="c-automator__controls l-automator__controls">
<AutomatorControls />
<button
v-tooltip="{
content: automatorModeTooltip,
hideOnTargetClick: false
}"
:class="{
'c-slider-toggle-button': true,
'c-slider-toggle-button--right': isTextAutomator,
...tutorialClass
}"
@click="toggleAutomatorMode"
>
<i class="fas fa-cubes" />
<i class="fas fa-code" />
</button>
</div>
<AutomatorTextEditor
v-if="isTextAutomator"
@ -141,47 +81,3 @@ export default {
<AutomatorBlockEditor v-if="!isTextAutomator" />
</div>
</template>
<style scoped>
.c-slider-toggle-button {
display: flex;
overflow: hidden;
position: relative;
align-items: center;
color: black;
background-color: #626262;
border: 0.2rem solid #767676;
border-radius: 0.2rem;
margin: 0.4rem;
padding: 0.3rem 0;
cursor: pointer;
}
.c-slider-toggle-button .fas {
width: 3rem;
position: relative;
z-index: 1;
}
.c-slider-toggle-button::before {
content: "";
width: 3rem;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 0;
background-color: white;
border-radius: 0.2rem;
transition: 0.3s ease all;
}
.c-slider-toggle-button--right::before {
left: 3rem;
background-color: white;
}
.tutorial--glow::after {
z-index: 2;
}
</style>

View File

@ -0,0 +1,151 @@
<script>
export default {
name: "AutomatorModeSwitch",
data() {
return {
automatorType: 0,
};
},
computed: {
currentScriptID: {
get() {
return this.$viewModel.tabs.reality.automator.editorScriptID;
},
set(value) {
this.$viewModel.tabs.reality.automator.editorScriptID = value;
}
},
currentScriptContent() {
return player.reality.automator.scripts[this.currentScriptID].content;
},
currentScript() {
return CodeMirror.Doc(this.currentScriptContent, "automato").getValue();
},
isTextAutomator() {
return this.automatorType === AUTOMATOR_TYPE.TEXT;
},
automatorModeTooltip() {
if (this.automatorType === AUTOMATOR_TYPE.BLOCK) return "Switch to the text editor";
return "Switch to the block editor";
},
tutorialClass() {
return {
"tutorial--glow": ui.view.tutorialState === TUTORIAL_STATE.AUTOMATOR && ui.view.tutorialActive
};
}
},
created() {
this.on$(GAME_EVENT.GAME_LOAD, () => this.onGameLoad());
this.on$(GAME_EVENT.AUTOMATOR_SAVE_CHANGED, () => this.onGameLoad());
this.updateCurrentScriptID();
},
methods: {
update() {
this.automatorType = player.reality.automator.type;
},
onGameLoad() {
this.updateCurrentScriptID();
},
updateCurrentScriptID() {
const storedScripts = player.reality.automator.scripts;
this.currentScriptID = player.reality.automator.state.editorScript;
// This shouldn't happen if things are loaded in the right order, but might as well be sure.
if (storedScripts[this.currentScriptID] === undefined) {
this.currentScriptID = Object.keys(storedScripts)[0];
player.reality.automator.state.editorScript = this.currentScriptID;
}
if (AutomatorData.currentErrors().length !== 0 && player.reality.automator.type === AUTOMATOR_TYPE.BLOCK) {
Modal.message.show(`Switched to text editor mode; this script has errors
which cannot be converted to block mode.`);
player.reality.automator.type = AUTOMATOR_TYPE.TEXT;
}
this.$nextTick(() => BlockAutomator.fromText(this.currentScript));
},
toggleAutomatorMode() {
if (AutomatorBackend.state.mode === AUTOMATOR_MODE.PAUSE || !player.options.confirmations.switchAutomatorMode) {
const scriptID = this.currentScriptID;
Tutorial.moveOn(TUTORIAL_STATE.AUTOMATOR);
if (this.automatorType === AUTOMATOR_TYPE.BLOCK) {
// This saves the script after converting it.
BlockAutomator.parseTextFromBlocks();
player.reality.automator.type = AUTOMATOR_TYPE.TEXT;
} else if (BlockAutomator.fromText(this.currentScriptContent)) {
AutomatorBackend.saveScript(scriptID, AutomatorTextUI.editor.getDoc().getValue());
player.reality.automator.type = AUTOMATOR_TYPE.BLOCK;
} else {
Modal.message.show("Automator script has errors, cannot convert to blocks.");
}
this.$recompute("currentScriptContent");
} else {
Modal.switchAutomatorEditorMode.show({
callBack: () => this.$recompute("currentScriptContent")
});
}
}
}
};
</script>
<template>
<div class="c-automator__controls l-automator__controls">
<button
v-tooltip="{
content: automatorModeTooltip,
hideOnTargetClick: false
}"
:class="{
'c-slider-toggle-button': true,
'c-slider-toggle-button--right': isTextAutomator,
...tutorialClass
}"
@click="toggleAutomatorMode"
>
<i class="fas fa-cubes" />
<i class="fas fa-code" />
</button>
</div>
</template>
<style scoped>
.c-slider-toggle-button {
display: flex;
overflow: hidden;
position: relative;
align-items: center;
color: black;
background-color: #626262;
border: 0.2rem solid #767676;
border-radius: 0.2rem;
margin: 0.2rem 0.4rem;
padding: 0.3rem 0;
cursor: pointer;
}
.c-slider-toggle-button .fas {
width: 3rem;
position: relative;
z-index: 1;
}
.c-slider-toggle-button::before {
content: "";
width: 3rem;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 0;
background-color: white;
border-radius: 0.2rem;
transition: 0.3s ease all;
}
.c-slider-toggle-button--right::before {
left: 3rem;
background-color: white;
}
.tutorial--glow::after {
z-index: 2;
}
</style>

View File

@ -179,7 +179,3 @@ export const AutomatorTextUI = {
class="c-automator-editor l-automator-editor l-automator-pane__content"
/>
</template>
<style scoped>
</style>

View File

@ -186,12 +186,12 @@ export default {
background: black;
}
@keyframes roll {
@keyframes a-roll {
100% { transform: rotateY(360deg); }
}
.pelle-icon {
animation: roll infinite 8s linear;
animation: a-roll infinite 8s linear;
}
.o-celestial-quote-history {

View File

@ -130,9 +130,6 @@ export default {
name: "Equipped Glyphs",
glyphSet: this.glyphs,
closeOn: GAME_EVENT.GLYPHS_EQUIPPED_CHANGED,
isGlyphSelection: false,
showSetName: true,
displaySacrifice: true,
});
},
clickGlyph(glyph, idx) {

View File

@ -57,7 +57,6 @@ export default {
closeOn: GAME_EVENT.REALITY_RESET_AFTER,
isGlyphSelection: true,
showSetName: false,
displaySacrifice: true,
});
}
}

View File

@ -82,7 +82,7 @@ export default {
this.ecCount = EternityChallenges.completions;
this.missingAchievements = Achievements.preReality.countWhere(a => !a.isUnlocked);
// Repeatable dilation upgrades don't have isBought, but do have boughtAmount
this.unpurchasedDilationUpgrades = Object.values(DilationUpgrade)
this.unpurchasedDilationUpgrades = DilationUpgrade.all
.countWhere(u => (u.isBought === undefined ? u.boughtAmount === 0 : !u.isBought) && !u.config.pelleOnly);
this.currLog10EP = player.eternityPoints.log10();
this.cheapestLog10TD = Math.min(...TimeDimensions.all.map(x => x.cost.log10()));

View File

@ -35,7 +35,7 @@ export default {
},
save() {
this.hideContextMenu();
this.preset.studies = TimeStudyTree.formatStudyList(GameCache.currentStudyTree.value.exportString);
this.preset.studies = GameCache.currentStudyTree.value.exportString;
const presetName = this.name ? `Study preset "${this.name}"` : "Study preset";
GameUI.notify.eternity(`${presetName} saved in slot ${this.saveslot}`);
},