mirror of
https://github.com/IvarK/AntimatterDimensionsSourceCode.git
synced 2025-02-16 15:40:16 +00:00
Merge branch 'master' into Steam-Webpack
This commit is contained in:
commit
c77f6d85e3
@ -1,3 +1,5 @@
|
||||
import { ProgressChecker } from "../storage/progress-checker";
|
||||
|
||||
import CloudLoadConflictModal from "@/components/modals/cloud/CloudLoadConflictModal";
|
||||
import CloudManualLoginModal from "@/components/modals/cloud/CloudManualLoginModal";
|
||||
import CloudSaveConflictModal from "@/components/modals/cloud/CloudSaveConflictModal";
|
||||
@ -40,6 +42,7 @@ import PurgeGlyphModal from "@/components/modals/glyph-management/PurgeGlyphModa
|
||||
import RefineGlyphModal from "@/components/modals/glyph-management/RefineGlyphModal";
|
||||
import SacrificeGlyphModal from "@/components/modals/glyph-management/SacrificeGlyphModal";
|
||||
|
||||
import AutobuyerEditModal from "@/components/modals/AutobuyerEditModal";
|
||||
import AutomatorScriptTemplate from "@/components/modals/AutomatorScriptTemplate";
|
||||
import AwayProgressModal from "@/components/modals/AwayProgressModal";
|
||||
import BreakInfinityModal from "@/components/modals/BreakInfinityModal";
|
||||
@ -240,6 +243,7 @@ Modal.importScriptData = new Modal(ImportAutomatorDataModal);
|
||||
Modal.automatorScriptDelete = new Modal(DeleteAutomatorScriptModal);
|
||||
Modal.automatorScriptTemplate = new Modal(AutomatorScriptTemplate);
|
||||
Modal.switchAutomatorEditorMode = new Modal(SwitchAutomatorEditorModal);
|
||||
Modal.autobuyerEditModal = new Modal(AutobuyerEditModal);
|
||||
Modal.shop = new Modal(StdStoreModal);
|
||||
Modal.studyString = new Modal(StudyStringModal);
|
||||
Modal.singularityMilestones = new Modal(SingularityMilestonesModal);
|
||||
@ -263,6 +267,7 @@ function getSaveInfo(save) {
|
||||
bestLevel: 0,
|
||||
totalSTD: 0,
|
||||
saveName: "",
|
||||
compositeProgress: 0,
|
||||
};
|
||||
// This code ends up getting run on raw save data before any migrations are applied, so we need to default to props
|
||||
// which only exist on the pre-reality version when applicable. Note that new Decimal(undefined) gives zero.
|
||||
@ -279,6 +284,7 @@ function getSaveInfo(save) {
|
||||
resources.bestLevel = save.records?.bestReality.glyphLevel ?? 0;
|
||||
resources.totalSTD = save?.IAP?.totalSTD ?? 0;
|
||||
resources.saveName = save.options.saveFileName ?? "";
|
||||
resources.compositeProgress = ProgressChecker.getCompositeProgress(save);
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
@ -127,6 +127,7 @@ class AntimatterDimensionAutobuyerState extends UpgradeableAutobuyerState {
|
||||
this.data.isUnlocked = false;
|
||||
this.data.isBought = false;
|
||||
this.data.bulk = 1;
|
||||
TabNotification.newAutobuyer.clearTrigger();
|
||||
}
|
||||
|
||||
static get entryCount() { return 8; }
|
||||
|
@ -64,6 +64,14 @@ export const Autobuyers = (function() {
|
||||
return Autobuyers.all.filter(a => a.isUnlocked || a.isBought);
|
||||
},
|
||||
|
||||
get hasAutobuyersForEditModal() {
|
||||
return [Autobuyer.dimboost,
|
||||
Autobuyer.galaxy,
|
||||
Autobuyer.bigCrunch,
|
||||
Autobuyer.eternity,
|
||||
Autobuyer.reality].some(autobuyer => autobuyer.isUnlocked);
|
||||
},
|
||||
|
||||
toggle() {
|
||||
player.auto.autobuyersOn = !player.auto.autobuyersOn;
|
||||
},
|
||||
|
@ -95,5 +95,6 @@ Autobuyer.tickspeed = new class TickspeedAutobuyerState extends UpgradeableAutob
|
||||
this.data.mode = AUTOBUYER_MODE.BUY_SINGLE;
|
||||
this.data.isUnlocked = false;
|
||||
this.data.isBought = false;
|
||||
TabNotification.newAutobuyer.clearTrigger();
|
||||
}
|
||||
}();
|
||||
|
@ -85,7 +85,7 @@ export const GameCache = {
|
||||
// Cached because it needs to be checked upon any change to antimatter, but that's a hot path and we want to keep
|
||||
// unnecessary repetitive calculations and accessing to a minimum
|
||||
cheapestAntimatterAutobuyer: new Lazy(() => Autobuyer.antimatterDimension.zeroIndexed.concat(Autobuyer.tickspeed)
|
||||
.filter(ab => !ab.isBought)
|
||||
.filter(ab => !(ab.isBought || ab.isUnlocked))
|
||||
.map(ab => ab.antimatterCost.toNumber())
|
||||
.min()
|
||||
),
|
||||
|
@ -202,6 +202,9 @@ Currency.antimatter = new class extends DecimalCurrency {
|
||||
set value(value) {
|
||||
if (InfinityChallenges.nextIC) InfinityChallenges.notifyICUnlock(value);
|
||||
if (GameCache.cheapestAntimatterAutobuyer.value && value.gte(GameCache.cheapestAntimatterAutobuyer.value)) {
|
||||
// Clicking into the automation tab clears the trigger and prevents it from retriggering as long as the player
|
||||
// stays on the tab; leaving the tab with an available autobuyer will immediately force it to trigger again
|
||||
TabNotification.newAutobuyer.clearTrigger();
|
||||
TabNotification.newAutobuyer.tryTrigger();
|
||||
}
|
||||
player.antimatter = value;
|
||||
|
@ -578,7 +578,8 @@ dev.testGlyphs = function(config) {
|
||||
const glyphData = glyphSets[index].map(glyphToShortString).sum();
|
||||
console.log(`${done} ${glyphData} rm=${rm} gl=${gl} ep=${ep} ip=${ip} am=${am} ` +
|
||||
`dimboosts=${dimboosts} galaxies=${galaxies}`);
|
||||
GameStorage.import(save, Date.now());
|
||||
GameStorage.offlineEnabled = false;
|
||||
GameStorage.import(save);
|
||||
if (index < glyphSets.length - 1) {
|
||||
setTimeout(runTrial, 100, index + 1);
|
||||
}
|
||||
@ -605,6 +606,7 @@ dev.forceCloudSave = async function() {
|
||||
const save = await Cloud.load();
|
||||
const root = GameSaveSerializer.deserialize(save);
|
||||
const saveId = GameStorage.currentSlot;
|
||||
if (!root.saves) root.saves = [];
|
||||
root.saves[saveId] = GameStorage.saves[saveId];
|
||||
Cloud.save(saveId);
|
||||
};
|
||||
|
@ -151,7 +151,7 @@ function tachyonGainMultiplier() {
|
||||
}
|
||||
|
||||
export function rewardTP() {
|
||||
Currency.tachyonParticles.bumpTo(getTP(Currency.antimatter.value));
|
||||
Currency.tachyonParticles.bumpTo(getTP(Currency.antimatter.value, true));
|
||||
player.dilation.lastEP = Currency.eternityPoints.value;
|
||||
}
|
||||
|
||||
@ -159,8 +159,8 @@ export function rewardTP() {
|
||||
// applying the reward only once upon unlock promotes min-maxing the upgrade by unlocking dilation with
|
||||
// TP multipliers as large as possible. Applying the reward to a base TP value and letting the multipliers
|
||||
// act dynamically on this fixed base value elsewhere solves that issue
|
||||
export function getBaseTP(antimatter) {
|
||||
if (!Player.canEternity) return DC.D0;
|
||||
export function getBaseTP(antimatter, requireEternity) {
|
||||
if (!Player.canEternity && requireEternity) return DC.D0;
|
||||
const am = (isInCelestialReality() || Pelle.isDoomed)
|
||||
? antimatter
|
||||
: Ra.unlocks.unlockDilationStartingTP.effectOrDefault(antimatter);
|
||||
@ -170,13 +170,14 @@ export function getBaseTP(antimatter) {
|
||||
}
|
||||
|
||||
// Returns the TP that would be gained this run
|
||||
export function getTP(antimatter) {
|
||||
return getBaseTP(antimatter).times(tachyonGainMultiplier());
|
||||
export function getTP(antimatter, requireEternity) {
|
||||
return getBaseTP(antimatter, requireEternity).times(tachyonGainMultiplier());
|
||||
}
|
||||
|
||||
// Returns the amount of TP gained, subtracting out current TP; used only for displaying gained TP
|
||||
export function getTachyonGain() {
|
||||
return getTP(Currency.antimatter.value).minus(Currency.tachyonParticles.value).clampMin(0);
|
||||
// and for "exit dilation" button (saying whether you need more antimatter)
|
||||
export function getTachyonGain(requireEternity) {
|
||||
return getTP(Currency.antimatter.value, requireEternity).minus(Currency.tachyonParticles.value).clampMin(0);
|
||||
}
|
||||
|
||||
// Returns the minimum antimatter needed in order to gain more TP; used only for display purposes
|
||||
|
@ -74,16 +74,19 @@ export function eternity(force, auto, specialConditions = {}) {
|
||||
// Annoyingly, we need to check for studies right here; giveEternityRewards removes studies if we're in an EC,
|
||||
// so doing the check later doesn't give us the initial state of having studies or not.
|
||||
const noStudies = player.timestudy.studies.length === 0;
|
||||
if (force) {
|
||||
player.challenge.eternity.current = 0;
|
||||
} else {
|
||||
if (!force) {
|
||||
if (!Player.canEternity) return false;
|
||||
EventHub.dispatch(GAME_EVENT.ETERNITY_RESET_BEFORE);
|
||||
if (!player.dilation.active) giveEternityRewards(auto);
|
||||
player.requirementChecks.reality.noEternities = false;
|
||||
}
|
||||
|
||||
if (player.dilation.active && (!force || Currency.infinityPoints.gte(Number.MAX_VALUE))) rewardTP();
|
||||
if (player.dilation.active) rewardTP();
|
||||
|
||||
// This needs to be after the dilation check for the "can gain TP" check in rewardTP to be correct.
|
||||
if (force) {
|
||||
player.challenge.eternity.current = 0;
|
||||
}
|
||||
|
||||
initializeChallengeCompletions();
|
||||
initializeResourcesAfterEternity();
|
||||
|
@ -256,7 +256,14 @@ export const shortcuts = [
|
||||
type: "bind",
|
||||
function: () => SecretAchievement(41).unlock(),
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Adjust Autobuyers",
|
||||
keys: ["mod", "alt", "a"],
|
||||
type: "bind",
|
||||
function: () => keyboardEditAutobuyers(),
|
||||
visible: () => Autobuyers.hasAutobuyersForEditModal
|
||||
},
|
||||
];
|
||||
|
||||
for (const hotkey of shortcuts) {
|
||||
@ -411,6 +418,16 @@ function keyboardH2PToggle() {
|
||||
Modal.h2p.show();
|
||||
}
|
||||
|
||||
function keyboardEditAutobuyers() {
|
||||
if (Modal.autobuyerEditModal.isOpen) {
|
||||
EventHub.dispatch(GAME_EVENT.CLOSE_MODAL);
|
||||
return;
|
||||
}
|
||||
if (Modal.isOpen) return;
|
||||
if (!Autobuyers.hasAutobuyersForEditModal) return;
|
||||
Modal.autobuyerEditModal.show();
|
||||
}
|
||||
|
||||
function keyboardVisibleTabsToggle() {
|
||||
if (Modal.hiddenTabs.isOpen) {
|
||||
EventHub.dispatch(GAME_EVENT.CLOSE_MODAL);
|
||||
@ -458,7 +475,12 @@ let konamiStep = 0;
|
||||
|
||||
function testKonami(character) {
|
||||
if (SecretAchievement(17).isUnlocked) return;
|
||||
// This conditional is structured weirdly in order to make sure more than 2 consecutive "up" inputs doesn't
|
||||
// reset the sequence state unnecessarily, and that interrupting the sequence later on with the starting
|
||||
// input will correctly set the state to one step in
|
||||
if (konamiCode[konamiStep] === character) konamiStep++;
|
||||
else if (konamiStep === 2 && character === "up") konamiStep = 2;
|
||||
else if (character === konamiCode[0]) konamiStep = 1;
|
||||
else konamiStep = 0;
|
||||
if (konamiCode.length <= konamiStep) {
|
||||
SecretAchievement(17).unlock();
|
||||
|
@ -55,7 +55,7 @@ export const GameIntervals = (function() {
|
||||
},
|
||||
gameLoop: interval(() => gameLoop(), () => player.options.updateRate),
|
||||
save: interval(() => GameStorage.save(), () =>
|
||||
(player.options.autosaveInterval - Math.clampMin(0, Date.now() - GameStorage.lastSaveTime))
|
||||
player.options.autosaveInterval - Math.clampMin(0, Date.now() - GameStorage.lastSaveTime)
|
||||
),
|
||||
checkCloudSave: interval(() => {
|
||||
if (player.options.cloudEnabled && Cloud.loggedIn) Cloud.saveCheck();
|
||||
|
@ -109,11 +109,11 @@ ShopPurchase.respecRequest = function() {
|
||||
};
|
||||
|
||||
kong.purchaseTimeSkip = function() {
|
||||
simulateTime(3600 * 6);
|
||||
simulateTime(3600 * 6, true);
|
||||
};
|
||||
|
||||
kong.purchaseLongerTimeSkip = function() {
|
||||
simulateTime(3600 * 24);
|
||||
simulateTime(3600 * 24, true);
|
||||
};
|
||||
|
||||
kong.updatePurchases = function() {
|
||||
|
@ -49,6 +49,10 @@ class NormalChallengeState extends GameMechanicState {
|
||||
return player.challenge.normal.current === this.id || (isPartOfIC1 && InfinityChallenge(1).isRunning);
|
||||
}
|
||||
|
||||
get isOnlyActiveChallenge() {
|
||||
return player.challenge.normal.current === this.id;
|
||||
}
|
||||
|
||||
get isUnlocked() {
|
||||
if (PlayerProgress.eternityUnlocked()) return true;
|
||||
if (this.id === 0) return true;
|
||||
@ -75,7 +79,7 @@ class NormalChallengeState extends GameMechanicState {
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.id === 1 || this.isRunning) return;
|
||||
if (this.id === 1 || this.isOnlyActiveChallenge) return;
|
||||
if (!Tab.challenges.isUnlocked) return;
|
||||
player.challenge.normal.current = this.id;
|
||||
player.challenge.infinity.current = 0;
|
||||
|
@ -767,6 +767,7 @@ window.player = {
|
||||
retryCelestial: false,
|
||||
showAllChallenges: false,
|
||||
cloudEnabled: true,
|
||||
syncSaveIntervals: true,
|
||||
hotkeys: true,
|
||||
theme: "Normal",
|
||||
commas: true,
|
||||
|
@ -134,7 +134,7 @@ GameDatabase.achievements.normal = [
|
||||
id: 32,
|
||||
name: "The Gods are pleased",
|
||||
get description() { return `Get over ${formatX(600)} from Dimensional Sacrifice outside of Challenge 8.`; },
|
||||
checkRequirement: () => !NormalChallenge(8).isRunning && Sacrifice.totalBoost.gte(600),
|
||||
checkRequirement: () => !NormalChallenge(8).isOnlyActiveChallenge && Sacrifice.totalBoost.gte(600),
|
||||
checkEvent: GAME_EVENT.SACRIFICE_RESET_AFTER,
|
||||
get reward() {
|
||||
return `Dimensional Sacrifice is stronger.
|
||||
@ -337,7 +337,7 @@ GameDatabase.achievements.normal = [
|
||||
get description() {
|
||||
return `Complete the 2nd Antimatter Dimension Autobuyer Challenge in ${formatInt(3)} minutes or less.`;
|
||||
},
|
||||
checkRequirement: () => NormalChallenge(2).isRunning && Time.thisInfinityRealTime.totalMinutes <= 3,
|
||||
checkRequirement: () => NormalChallenge(2).isOnlyActiveChallenge && Time.thisInfinityRealTime.totalMinutes <= 3,
|
||||
checkEvent: GAME_EVENT.BIG_CRUNCH_BEFORE,
|
||||
get reward() {
|
||||
return `All Antimatter Dimensions are stronger in the first ${formatInt(3)} minutes of Infinities.`;
|
||||
@ -352,7 +352,7 @@ GameDatabase.achievements.normal = [
|
||||
get description() {
|
||||
return `Complete the 8th Antimatter Dimension Autobuyer Challenge in ${formatInt(3)} minutes or less.`;
|
||||
},
|
||||
checkRequirement: () => NormalChallenge(8).isRunning && Time.thisInfinityRealTime.totalMinutes <= 3,
|
||||
checkRequirement: () => NormalChallenge(8).isOnlyActiveChallenge && Time.thisInfinityRealTime.totalMinutes <= 3,
|
||||
checkEvent: GAME_EVENT.BIG_CRUNCH_BEFORE,
|
||||
get reward() {
|
||||
return `Dimensional Sacrifice is stronger.
|
||||
@ -365,7 +365,7 @@ GameDatabase.achievements.normal = [
|
||||
id: 58,
|
||||
name: "This is fine.",
|
||||
get description() { return `Complete the Tickspeed Autobuyer Challenge in ${formatInt(3)} minutes or less.`; },
|
||||
checkRequirement: () => NormalChallenge(9).isRunning && Time.thisInfinityRealTime.totalMinutes <= 3,
|
||||
checkRequirement: () => NormalChallenge(9).isOnlyActiveChallenge && Time.thisInfinityRealTime.totalMinutes <= 3,
|
||||
checkEvent: GAME_EVENT.BIG_CRUNCH_BEFORE,
|
||||
get reward() {
|
||||
return `Increase the multiplier for buying ${formatInt(10)} Antimatter Dimensions by +${formatPercents(0.01)}.`;
|
||||
@ -442,7 +442,7 @@ GameDatabase.achievements.normal = [
|
||||
get description() {
|
||||
return `Complete the 3rd Antimatter Dimension Autobuyer Challenge in ${formatInt(10)} seconds or less.`;
|
||||
},
|
||||
checkRequirement: () => NormalChallenge(3).isRunning && Time.thisInfinityRealTime.totalSeconds <= 10,
|
||||
checkRequirement: () => NormalChallenge(3).isOnlyActiveChallenge && Time.thisInfinityRealTime.totalSeconds <= 10,
|
||||
checkEvent: GAME_EVENT.BIG_CRUNCH_BEFORE,
|
||||
get reward() { return `1st Antimatter Dimensions are ${formatPercents(0.5)} stronger.`; },
|
||||
effect: 1.5
|
||||
@ -454,7 +454,7 @@ GameDatabase.achievements.normal = [
|
||||
`Get to Infinity with only a single 1st Antimatter Dimension without Dimension Boosts
|
||||
or Antimatter Galaxies, while in the 2nd Antimatter Dimension Autobuyer Challenge.`,
|
||||
checkRequirement: () =>
|
||||
NormalChallenge(2).isRunning &&
|
||||
NormalChallenge(2).isOnlyActiveChallenge &&
|
||||
AntimatterDimension(1).amount.eq(1) &&
|
||||
DimBoost.purchasedBoosts === 0 &&
|
||||
player.galaxies === 0,
|
||||
|
@ -18,8 +18,8 @@ function rebuyable(config) {
|
||||
(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)}`;
|
||||
? `Currently: ${formatX(10 - value)} ${afterECText}`
|
||||
: `Currently: ${formatX(10 - value)} | Next: ${formatX(10 - value - 1)}`;
|
||||
}),
|
||||
formatCost: value => format(value, 2, 0),
|
||||
noLabel,
|
||||
|
@ -33,6 +33,14 @@ export const Cloud = {
|
||||
shouldOverwriteCloudSave: true,
|
||||
lastCloudHash: null,
|
||||
|
||||
resetTempState() {
|
||||
this.hasSeenSavingConflict = false;
|
||||
this.shouldOverwriteCloudSave = true;
|
||||
this.lastCloudHash = null;
|
||||
GameStorage.lastCloudSave = Date.now();
|
||||
GameIntervals.checkCloudSave.restart();
|
||||
},
|
||||
|
||||
get loggedIn() {
|
||||
return this.user !== null;
|
||||
},
|
||||
@ -78,12 +86,11 @@ export const Cloud = {
|
||||
older: ProgressChecker.compareSaveTimes(cloud, local),
|
||||
diffSTD: (cloud?.IAP?.totalSTD ?? 0) - (local?.IAP?.totalSTD ?? 0),
|
||||
differentName: cloud?.options.saveFileName !== local?.options.saveFileName,
|
||||
hashMismatch: hash && this.lastCloudHash !== hash,
|
||||
hashMismatch: this.lastCloudHash && this.lastCloudHash !== hash,
|
||||
};
|
||||
},
|
||||
|
||||
async saveCheck() {
|
||||
GameIntervals.checkCloudSave.restart();
|
||||
const save = await this.load();
|
||||
if (save === null) {
|
||||
this.save();
|
||||
@ -91,8 +98,9 @@ export const Cloud = {
|
||||
const root = GameSaveSerializer.deserialize(save);
|
||||
const saveId = GameStorage.currentSlot;
|
||||
const cloudSave = root.saves[saveId];
|
||||
const thisCloudHash = sha512_256(GameSaveSerializer.serialize(cloudSave));
|
||||
const localSave = GameStorage.saves[saveId];
|
||||
const saveComparison = this.compareSaves(cloudSave, localSave, sha512_256(save));
|
||||
const saveComparison = this.compareSaves(cloudSave, localSave, thisCloudHash);
|
||||
|
||||
// eslint-disable-next-line no-loop-func
|
||||
const overwriteAndSendCloudSave = () => {
|
||||
@ -103,11 +111,9 @@ export const Cloud = {
|
||||
// Bring up the modal if cloud saving will overwrite a cloud save which is older or possibly farther
|
||||
const hasBoth = cloudSave && localSave;
|
||||
// NOTE THIS CHECK IS INTENTIONALLY DIFFERENT FROM THE LOAD CHECK
|
||||
// Hash mismatch check should be separate from the others because otherwise it only ever shows up on the first
|
||||
// mismatch; there are situations (eg. two devices actively saving) which can cause this to happen repeatedly.
|
||||
const hasConflict = hasBoth && (saveComparison.older === -1 || saveComparison.farther !== 1 ||
|
||||
saveComparison.diffSTD > 0 || saveComparison.differentName);
|
||||
if ((hasConflict && !this.hasSeenSavingConflict) || saveComparison.hashMismatch) {
|
||||
saveComparison.diffSTD > 0 || saveComparison.differentName || saveComparison.hashMismatch);
|
||||
if (hasConflict && !this.hasSeenSavingConflict) {
|
||||
Modal.addCloudConflict(saveId, saveComparison, cloudSave, localSave, overwriteAndSendCloudSave);
|
||||
Modal.cloudSaveConflict.show();
|
||||
} else if (!hasConflict || (this.hasSeenSavingConflict && this.shouldOverwriteCloudSave)) {
|
||||
@ -119,14 +125,16 @@ export const Cloud = {
|
||||
save(slot) {
|
||||
if (!this.user) return;
|
||||
if (GlyphSelection.active || ui.$viewModel.modal.progressBar !== undefined) return;
|
||||
if (player.options.syncSaveIntervals) GameStorage.save();
|
||||
const root = {
|
||||
current: GameStorage.currentSlot,
|
||||
saves: GameStorage.saves,
|
||||
};
|
||||
|
||||
const toSave = GameSaveSerializer.serialize(root);
|
||||
this.lastCloudHash = sha512_256(toSave);
|
||||
set(ref(this.db, `users/${this.user.id}/web`), toSave);
|
||||
this.lastCloudHash = sha512_256(GameSaveSerializer.serialize(root.saves[slot]));
|
||||
GameStorage.lastCloudSave = Date.now();
|
||||
GameIntervals.checkCloudSave.restart();
|
||||
set(ref(this.db, `users/${this.user.id}/web`), GameSaveSerializer.serialize(root));
|
||||
GameUI.notify.info(`Game saved (slot ${slot + 1}) to cloud`);/* with user ${this.user.displayName}`);*/
|
||||
},
|
||||
|
||||
|
@ -11,6 +11,9 @@ export const GameStorage = {
|
||||
},
|
||||
saved: 0,
|
||||
lastSaveTime: Date.now(),
|
||||
lastCloudSave: Date.now(),
|
||||
offlineEnabled: undefined,
|
||||
offlineTicks: undefined,
|
||||
|
||||
get localStorageKey() {
|
||||
return isDevEnvironment() ? "dimensionTestSave" : "dimensionSave";
|
||||
@ -54,11 +57,12 @@ export const GameStorage = {
|
||||
this.save(true);
|
||||
this.loadPlayerObject(this.saves[slot] ?? Player.defaultStart);
|
||||
Tabs.all.find(t => t.id === player.options.lastOpenTab).show(true);
|
||||
Cloud.resetTempState();
|
||||
GameUI.notify.info("Game loaded");
|
||||
SteamFunctions.BackfillAchievements()
|
||||
},
|
||||
|
||||
import(saveData, overrideLastUpdate = undefined) {
|
||||
import(saveData) {
|
||||
if (tryImportSecret(saveData) || Theme.tryUnlock(saveData)) {
|
||||
return;
|
||||
}
|
||||
@ -70,9 +74,10 @@ export const GameStorage = {
|
||||
Modal.hideAll();
|
||||
Quote.clearAll();
|
||||
AutomatorBackend.clearEditor();
|
||||
this.loadPlayerObject(player, overrideLastUpdate);
|
||||
this.loadPlayerObject(player);
|
||||
if (player.speedrun?.isActive) Speedrun.setSegmented(true);
|
||||
this.save(true);
|
||||
Cloud.resetTempState();
|
||||
|
||||
// This is to fix a very specific exploit: When the game is ending, some tabs get hidden
|
||||
// The options tab is the first one of those, which makes the player redirect to the Pelle tab
|
||||
@ -195,9 +200,10 @@ export const GameStorage = {
|
||||
player.IAP = IAP;
|
||||
this.save(true);
|
||||
Tab.dimensions.antimatter.show();
|
||||
Cloud.resetTempState();
|
||||
},
|
||||
|
||||
loadPlayerObject(playerObject, overrideLastUpdate = undefined) {
|
||||
loadPlayerObject(playerObject) {
|
||||
this.saved = 0;
|
||||
|
||||
const checkString = this.checkPlayerObject(playerObject);
|
||||
@ -246,11 +252,10 @@ export const GameStorage = {
|
||||
AutomatorBackend.initializeFromSave();
|
||||
Lazy.invalidateAll();
|
||||
|
||||
if (overrideLastUpdate) {
|
||||
player.lastUpdate = overrideLastUpdate;
|
||||
}
|
||||
const rawDiff = Date.now() - player.lastUpdate;
|
||||
if (player.options.offlineProgress && !Speedrun.isPausedAtStart()) {
|
||||
// We set offlineEnabled externally on importing; otherwise this is just a local load
|
||||
const simulateOffline = this.offlineEnabled ?? player.options.offlineProgress;
|
||||
if (simulateOffline && !Speedrun.isPausedAtStart()) {
|
||||
let diff = rawDiff;
|
||||
player.speedrun.offlineTimeUsed += diff;
|
||||
if (diff > 5 * 60 * 1000 && player.celestials.enslaved.autoStoreReal) {
|
||||
|
@ -41,7 +41,7 @@ export class DilationTimeStudyState extends TimeStudyState {
|
||||
}
|
||||
if (!Pelle.isDoomed) Currency.tachyonParticles.bumpTo(Perk.startTP.effectOrDefault(0));
|
||||
if (Ra.unlocks.unlockDilationStartingTP.canBeApplied && !isInCelestialReality() && !Pelle.isDoomed) {
|
||||
Currency.tachyonParticles.bumpTo(getTP(Ra.unlocks.unlockDilationStartingTP.effectOrDefault(0)));
|
||||
Currency.tachyonParticles.bumpTo(getTP(Ra.unlocks.unlockDilationStartingTP.effectOrDefault(0), false));
|
||||
}
|
||||
TabNotification.dilationAfterUnlock.tryTrigger();
|
||||
}
|
||||
|
@ -14,8 +14,11 @@ class TabNotificationState {
|
||||
|
||||
tryTrigger() {
|
||||
if (!this.config.condition() || this.triggered) return;
|
||||
const currentTabKey = `${Tabs.current.key}${Tabs.current._currentSubtab.key}`;
|
||||
this.config.tabsToHighLight.map(t => t.parent + t.tab)
|
||||
.forEach(tab => player.tabNotifications.add(tab));
|
||||
.forEach(tab => {
|
||||
if (tab !== currentTabKey) player.tabNotifications.add(tab);
|
||||
});
|
||||
player.triggeredTabNotificationBits |= 1 << this.config.id;
|
||||
|
||||
// Force all tabs and subtabs of this notification to be unhidden
|
||||
|
@ -842,18 +842,19 @@ function afterSimulation(seconds, playerBefore) {
|
||||
}
|
||||
|
||||
export function simulateTime(seconds, real, fast) {
|
||||
// The game is simulated at a base 50ms update rate, with a max of
|
||||
// player.options.offlineTicks ticks. additional ticks are converted
|
||||
// into a higher diff per tick
|
||||
// warning: do not call this function with real unless you know what you're doing
|
||||
// calling it with fast will only simulate it with a max of 50 ticks
|
||||
// The game is simulated at a base 50ms update rate, with a maximum tick count based on the values of real and fast
|
||||
// - Calling with real === true will always simulate at full accuracy with no tick count reduction
|
||||
// - Calling with fast === true will only simulate it with a max of 50 ticks
|
||||
// - Otherwise, tick count will be limited to the offline tick count (which may be set externally during save import)
|
||||
// Tick count is never *increased*, and only ever decreased if needed.
|
||||
let ticks = Math.floor(seconds * 20);
|
||||
GameUI.notify.showBlackHoles = false;
|
||||
|
||||
// Limit the tick count (this also applies if the black hole is unlocked)
|
||||
if (ticks > player.options.offlineTicks && !real && !fast) {
|
||||
ticks = player.options.offlineTicks;
|
||||
} else if (ticks > 50 && fast) {
|
||||
const maxTicks = GameStorage.offlineTicks ?? player.options.offlineTicks;
|
||||
if (ticks > maxTicks && !real && !fast) {
|
||||
ticks = maxTicks;
|
||||
} else if (ticks > 50 && !real && fast) {
|
||||
ticks = 50;
|
||||
}
|
||||
|
||||
|
@ -624,6 +624,34 @@ body.t-s9 {
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.c-autobuyer-box-row__modal {
|
||||
background-color: #111014;
|
||||
border-color: #383232;
|
||||
}
|
||||
|
||||
.t-metro .c-autobuyer-box-row__modal {
|
||||
background-color: var(--color-base);
|
||||
border-color: var(--color-text);
|
||||
}
|
||||
|
||||
.t-inverted .c-autobuyer-box-row__modal,
|
||||
.t-inverted-metro .c-autobuyer-box-row__modal {
|
||||
background-color: var(--color-base);
|
||||
border-color: var(--color-text);
|
||||
}
|
||||
|
||||
.t-s7 .c-autobuyer-box-row__modal {
|
||||
background-color: var(--color-base);
|
||||
}
|
||||
|
||||
.o-autobuyer-toggle-checkbox__label-modal {
|
||||
border-color: #383232;
|
||||
}
|
||||
|
||||
.t-inverted .o-autobuyer-toggle-checkbox__label-modal {
|
||||
border-color: var(--color-text);
|
||||
}
|
||||
|
||||
.o-autobuyer-input,
|
||||
.c-autobuyer-box__mode-select {
|
||||
color: var(--color-accent);
|
||||
@ -653,6 +681,11 @@ body.t-s9 {
|
||||
border: 0.1rem solid black;
|
||||
}
|
||||
|
||||
.t-s4 .o-autobuyer-input,
|
||||
.t-s7 .o-autobuyer-input {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.t-s6 .o-autobuyer-input,
|
||||
.t-s6 .c-autobuyer-box__mode-select,
|
||||
.t-s10 .o-autobuyer-input,
|
||||
|
@ -83,6 +83,21 @@
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.t-s11 .o-autobuyer-input,
|
||||
.t-s11 .c-autobuyer-box__mode-select {
|
||||
color: var(--color-accent);
|
||||
background: var(--color-base);
|
||||
border: 0.1rem solid var(--color-accent);
|
||||
}
|
||||
|
||||
.t-s11 .o-autobuyer-btn {
|
||||
border: 0.1rem solid var(--color-accent);
|
||||
}
|
||||
|
||||
.t-s11 .c-challenge-box--normal {
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.o-tab-btn--secondary {
|
||||
width: 18.5rem;
|
||||
height: 2.5rem;
|
||||
|
@ -61,6 +61,7 @@ html {
|
||||
--color-bad: #b84b5f;
|
||||
--color-gh-purple: #8957e5;
|
||||
--color-notification: red;
|
||||
--color-overlay: rgba(30, 30, 50, 90%);
|
||||
|
||||
--color-antimatter: #2196f3;
|
||||
--color-infinity: #b67f33;
|
||||
@ -120,6 +121,7 @@ html {
|
||||
--color-disabled: #37474f;
|
||||
--color-accent: #1256a3;
|
||||
--color-notification: yellow;
|
||||
--color-overlay: rgba(60, 60, 100, 50%);
|
||||
|
||||
--color-infinity: #ff9800;
|
||||
--color-reality-dark: #0ba00e;
|
||||
@ -141,6 +143,7 @@ html {
|
||||
--color-good-dark: #2e7d32;
|
||||
--color-bad: #e53935;
|
||||
--color-notification: yellow;
|
||||
--color-overlay: rgba(60, 60, 100, 50%);
|
||||
|
||||
--color-infinity: #ff9800;
|
||||
--color-eternity: #673ab7;
|
||||
@ -194,6 +197,7 @@ html {
|
||||
--color-good: #2f9e35;
|
||||
--color-good-dark: #08510b;
|
||||
--color-notification: yellow;
|
||||
--color-overlay: rgba(60, 60, 100, 50%);
|
||||
|
||||
--color-prestige--accent: black;
|
||||
|
||||
@ -209,6 +213,7 @@ html {
|
||||
--color-base: black;
|
||||
--color-accent: #fbc21b;
|
||||
--color-notification: yellow;
|
||||
--color-overlay: rgba(60, 60, 100, 50%);
|
||||
|
||||
--color-prestige--accent: black;
|
||||
|
||||
@ -4146,27 +4151,52 @@ br {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.o-autobuyer-toggle-checkbox__label-modal {
|
||||
border-color: var(--color-text);
|
||||
}
|
||||
|
||||
.s-base--metro .o-autobuyer-toggle-checkbox__label {
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
.s-base--metro .o-autobuyer-toggle-checkbox__label-modal {
|
||||
border-color: var(--color-text);
|
||||
}
|
||||
|
||||
.t-dark .o-autobuyer-toggle-checkbox__label {
|
||||
border-color: var(--color-base);
|
||||
}
|
||||
|
||||
.t-dark .o-autobuyer-toggle-checkbox__label-modal {
|
||||
border-color: var(--color-good-dark);
|
||||
}
|
||||
|
||||
.t-dark-metro .o-autobuyer-toggle-checkbox__label {
|
||||
border-color: var(--color-base);
|
||||
}
|
||||
|
||||
.t-dark-metro .o-autobuyer-toggle-checkbox__label-modal {
|
||||
border-color: var(--color-good-dark);
|
||||
}
|
||||
|
||||
.t-s1 .o-autobuyer-toggle-checkbox__label {
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
.t-s1 .o-autobuyer-toggle-checkbox__label-modal {
|
||||
border-color: var(--color-text);
|
||||
}
|
||||
|
||||
.t-s6 .o-autobuyer-toggle-checkbox__label,
|
||||
.t-s10 .o-autobuyer-toggle-checkbox__label {
|
||||
border-color: #cccccc;
|
||||
}
|
||||
|
||||
.t-s6 .o-autobuyer-toggle-checkbox__label,
|
||||
.t-s10 .o-autobuyer-toggle-checkbox__label {
|
||||
border-color: var(--color-text);
|
||||
}
|
||||
|
||||
.o-autobuyer-toggle-checkbox__label:hover {
|
||||
transform: scale(1.1) translate(-0.1rem, 0.1rem);
|
||||
}
|
||||
@ -4372,6 +4402,14 @@ br {
|
||||
padding: 1rem 2rem;
|
||||
}
|
||||
|
||||
/* For some reason, we need to specifically define the font size here or else it balloons up to a size
|
||||
bigger than that of the autobuyer tab. We also explicitly set the border color in order for it to appear
|
||||
properly on certain themes. */
|
||||
.c-autobuyer-box-row__modal {
|
||||
font-size: 1.1rem;
|
||||
border-color: var(--color-text);
|
||||
}
|
||||
|
||||
.s-base--metro .c-autobuyer-box-row {
|
||||
border-color: black;
|
||||
}
|
||||
@ -4380,15 +4418,41 @@ br {
|
||||
border-color: var(--color-base);
|
||||
}
|
||||
|
||||
.t-dark .c-autobuyer-box-row__modal {
|
||||
background-color: rgb(55, 71, 79);
|
||||
border-color: var(--color-good-dark);
|
||||
}
|
||||
|
||||
.t-dark-metro .c-autobuyer-box-row {
|
||||
border-color: var(--color-base);
|
||||
}
|
||||
|
||||
.t-dark-metro .c-autobuyer-box-row__modal {
|
||||
background-color: rgb(55, 71, 79);
|
||||
border-color: var(--color-good-dark);
|
||||
}
|
||||
|
||||
.t-s1 .c-autobuyer-box-row {
|
||||
background: var(--color-base);
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
.t-s2 .c-autobuyer-box-row__modal {
|
||||
background-color: rgb(230, 230, 255);
|
||||
}
|
||||
|
||||
.t-s3 .c-autobuyer-box-row__modal {
|
||||
background-color: var(--color-base);
|
||||
}
|
||||
|
||||
.t-s4 .c-autobuyer-box-row__modal {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.t-s5 .c-autobuyer-box-row__modal {
|
||||
background-color: var(--color-base);
|
||||
}
|
||||
|
||||
.t-s6 .c-autobuyer-box-row,
|
||||
.t-s10 .c-autobuyer-box-row {
|
||||
background: black;
|
||||
@ -5258,7 +5322,7 @@ br {
|
||||
|
||||
@keyframes a-modal-overlay-fadein {
|
||||
from { background-color: rgba(0, 0, 0, 0%); }
|
||||
to { background-color: rgba(60, 60, 100, 50%); }
|
||||
to { background-color: var(--color-overlay); }
|
||||
}
|
||||
|
||||
.l-modal-overlay {
|
||||
@ -5271,7 +5335,7 @@ br {
|
||||
left: 0;
|
||||
z-index: 6;
|
||||
animation-name: a-modal-overlay-fadein;
|
||||
animation-duration: 2s;
|
||||
animation-duration: 1s;
|
||||
animation-fill-mode: forwards;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
@ -4,19 +4,30 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
currentTime: 0,
|
||||
lastSave: 0,
|
||||
cloudSaveEnabled: false,
|
||||
lastLocalSave: 0,
|
||||
lastCloudSave: 0,
|
||||
showTimeSinceSave: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
time() {
|
||||
return timeDisplayShort(this.currentTime - this.lastSave);
|
||||
}
|
||||
localString() {
|
||||
const desc = this.cloudSaveEnabled
|
||||
? "Time since last local save:"
|
||||
: "Time since last save:";
|
||||
return `${desc} ${timeDisplayShort(this.currentTime - this.lastLocalSave)}`;
|
||||
},
|
||||
cloudString() {
|
||||
if (!this.cloudSaveEnabled) return null;
|
||||
return `Time since last cloud save: ${timeDisplayShort(this.currentTime - this.lastCloudSave)}`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.lastSave = GameStorage.lastSaveTime;
|
||||
this.currentTime = Date.now();
|
||||
this.cloudSaveEnabled = player.options.cloudEnabled && Cloud.loggedIn;
|
||||
this.lastLocalSave = GameStorage.lastSaveTime;
|
||||
this.lastCloudSave = GameStorage.lastCloudSave;
|
||||
this.showTimeSinceSave = player.options.showTimeSinceSave;
|
||||
},
|
||||
save() {
|
||||
@ -32,7 +43,9 @@ export default {
|
||||
class="o-save-timer"
|
||||
@click="save"
|
||||
>
|
||||
Time since last save: {{ time }}
|
||||
{{ localString }}
|
||||
<br>
|
||||
{{ cloudString }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -42,6 +55,7 @@ export default {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
text-align: left;
|
||||
z-index: 5;
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-base);
|
||||
|
86
src/components/modals/AutobuyerEditModal.vue
Normal file
86
src/components/modals/AutobuyerEditModal.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<script>
|
||||
import BigCrunchAutobuyerBox from "@/components/tabs/autobuyers/BigCrunchAutobuyerBox";
|
||||
import DimensionBoostAutobuyerBox from "@/components/tabs/autobuyers/DimensionBoostAutobuyerBox";
|
||||
import EternityAutobuyerBox from "@/components/tabs/autobuyers/EternityAutobuyerBox";
|
||||
import GalaxyAutobuyerBox from "@/components/tabs/autobuyers/GalaxyAutobuyerBox";
|
||||
import ModalWrapper from "@/components/modals/ModalWrapper";
|
||||
import RealityAutobuyerBox from "@/components/tabs/autobuyers/RealityAutobuyerBox";
|
||||
|
||||
export default {
|
||||
name: "AutobuyerEditModal",
|
||||
components: {
|
||||
BigCrunchAutobuyerBox,
|
||||
DimensionBoostAutobuyerBox,
|
||||
EternityAutobuyerBox,
|
||||
GalaxyAutobuyerBox,
|
||||
ModalWrapper,
|
||||
RealityAutobuyerBox,
|
||||
},
|
||||
computed: {
|
||||
header() {
|
||||
return `Edit Autobuyers`;
|
||||
},
|
||||
message() {
|
||||
// We have to have this edge-case due to a weird happening where you could open this modal
|
||||
// during the Reality animation, which would then show an empty modal.
|
||||
return Autobuyers.hasAutobuyersForEditModal
|
||||
? `Using this modal, you can edit various values inside your autobuyers.`
|
||||
: `You currently have no autobuyers which could be shown here.`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModalWrapper>
|
||||
<template #header>
|
||||
{{ header }}
|
||||
</template>
|
||||
<div class="c-modal-message__text-fit">
|
||||
<span>
|
||||
{{ message }}
|
||||
</span>
|
||||
</div>
|
||||
<!--
|
||||
We only include these autobuyers as these are (probably) the ones that users will want to change
|
||||
most often.
|
||||
-->
|
||||
<RealityAutobuyerBox
|
||||
class="c-reality-pos"
|
||||
is-modal
|
||||
/>
|
||||
<EternityAutobuyerBox
|
||||
class="c-eternity-pos"
|
||||
is-modal
|
||||
/>
|
||||
<BigCrunchAutobuyerBox
|
||||
class="c-infinity-pos"
|
||||
is-modal
|
||||
/>
|
||||
<GalaxyAutobuyerBox is-modal />
|
||||
<DimensionBoostAutobuyerBox is-modal />
|
||||
</ModalWrapper>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* From AutobuyersTab.vue */
|
||||
/* This is necessary for the ExpandingControlBox within these components to render in the right stacking order
|
||||
when they're open. It looks slightly hacky but actually can't be done any other way; each AutobuyerBox creates
|
||||
its own stacking context, which means that all z-indices specified within are essentially scoped and the
|
||||
AutobuyerBox components will always render in page order regardless of internal z-indices without these. */
|
||||
.c-reality-pos {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.c-eternity-pos {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.c-infinity-pos {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.c-modal-message__text-fit {
|
||||
width: auto;
|
||||
}
|
||||
</style>
|
@ -2,6 +2,12 @@
|
||||
import ModalWrapperChoice from "@/components/modals/ModalWrapperChoice";
|
||||
import PrimaryButton from "@/components/PrimaryButton";
|
||||
|
||||
const OFFLINE_PROGRESS_TYPE = {
|
||||
IMPORTED: 0,
|
||||
LOCAL: 1,
|
||||
IGNORED: 2,
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "ImportSaveModal",
|
||||
components: {
|
||||
@ -12,6 +18,7 @@ export default {
|
||||
return {
|
||||
input: "",
|
||||
importCounter: 0,
|
||||
offlineImport: OFFLINE_PROGRESS_TYPE.IMPORTED,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -56,12 +63,66 @@ export default {
|
||||
},
|
||||
clicksLeft() {
|
||||
return 5 - this.importCounter;
|
||||
},
|
||||
timeSinceSave() {
|
||||
return TimeSpan.fromMilliseconds(Date.now() - this.player.lastUpdate).toString();
|
||||
},
|
||||
offlineType() {
|
||||
// We update here in the computed method instead of elsewhere because otherwise it initializes the text
|
||||
// to a wrong or undefined setting
|
||||
this.updateOfflineSettings();
|
||||
|
||||
switch (this.offlineImport) {
|
||||
case OFFLINE_PROGRESS_TYPE.IMPORTED:
|
||||
return "Using imported save settings";
|
||||
case OFFLINE_PROGRESS_TYPE.LOCAL:
|
||||
return "Using existing save settings";
|
||||
case OFFLINE_PROGRESS_TYPE.IGNORED:
|
||||
return "Will not simulate offline time";
|
||||
default:
|
||||
throw new Error("Unrecognized offline progress setting for importing");
|
||||
}
|
||||
},
|
||||
offlineDetails() {
|
||||
if (this.offlineImport === OFFLINE_PROGRESS_TYPE.IGNORED) {
|
||||
return `Save will be imported without offline progress.`;
|
||||
}
|
||||
const ticks = GameStorage.offlineTicks;
|
||||
return GameStorage.offlineEnabled
|
||||
? `After importing, will simulate ${formatInt(ticks)} ticks of duration
|
||||
${TimeSpan.fromMilliseconds((Date.now() - this.player.lastUpdate) / ticks).toStringShort()} each.`
|
||||
: "This setting will not apply any offline progress after importing.";
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.input.select();
|
||||
},
|
||||
destroyed() {
|
||||
// Explicitly setting this to undefined after closing forces the game to fall-back to the stored settings within
|
||||
// the player object if this modal is closed - ie. it makes sure actions in the modal don't persist
|
||||
GameStorage.offlineEnabled = undefined;
|
||||
GameStorage.offlineTicks = undefined;
|
||||
},
|
||||
methods: {
|
||||
changeOfflineSetting() {
|
||||
this.offlineImport = (this.offlineImport + 1) % 3;
|
||||
},
|
||||
updateOfflineSettings() {
|
||||
switch (this.offlineImport) {
|
||||
case OFFLINE_PROGRESS_TYPE.IMPORTED:
|
||||
// These are default values from a new save, used if importing from pre-reality where these props don't exist
|
||||
GameStorage.offlineEnabled = this.player.options.offlineProgress ?? true;
|
||||
GameStorage.offlineTicks = this.player.options.offlineTicks ?? 1000;
|
||||
break;
|
||||
case OFFLINE_PROGRESS_TYPE.LOCAL:
|
||||
GameStorage.offlineEnabled = player.options.offlineProgress;
|
||||
GameStorage.offlineTicks = player.options.offlineTicks;
|
||||
break;
|
||||
case OFFLINE_PROGRESS_TYPE.IGNORED:
|
||||
GameStorage.offlineEnabled = false;
|
||||
break;
|
||||
}
|
||||
},
|
||||
importSave() {
|
||||
this.importCounter++;
|
||||
if (this.hasLessSTDs && this.clicksLeft > 0) return;
|
||||
@ -108,7 +169,18 @@ export default {
|
||||
Realities: {{ formatPostBreak(player.realities, 2) }}
|
||||
</div>
|
||||
<div class="c-modal-import__warning">
|
||||
(your current save file will be overwritten!)
|
||||
(Your current save file will be overwritten!)
|
||||
</div>
|
||||
<br>
|
||||
<div>
|
||||
This save was last opened {{ timeSinceSave }} ago.
|
||||
<div
|
||||
class="o-primary-btn"
|
||||
@click="changeOfflineSetting"
|
||||
>
|
||||
Offline Progress: {{ offlineType }}
|
||||
</div>
|
||||
<span v-html="offlineDetails" />
|
||||
</div>
|
||||
<div
|
||||
v-if="hasLessSTDs"
|
||||
|
@ -48,6 +48,11 @@ export default {
|
||||
icon="fa-brands fa-google-play"
|
||||
link="https://play.google.com/store/apps/details?id=kajfosz.antimatterdimensions"
|
||||
/>
|
||||
<InformationModalButton
|
||||
name="Antimatter Dimensions on Steam"
|
||||
icon="fa-brands fa-steam"
|
||||
link="https://store.steampowered.com/app/1399720/Antimatter_Dimensions/"
|
||||
/>
|
||||
<InformationModalButton
|
||||
name="Credits"
|
||||
icon="fa-solid fa-users"
|
||||
|
@ -20,47 +20,50 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
name() {
|
||||
return this.unlockedQuotes[0].quote._celestial;
|
||||
},
|
||||
focusedQuote() {
|
||||
return this.unlockedQuotes[this.focusedQuoteId];
|
||||
},
|
||||
currentQuoteLine() {
|
||||
return this.focusedQuote.currentLine;
|
||||
},
|
||||
commonButtonClass() {
|
||||
const lightBG = this.name === "laitela" && !Theme.current().isDark();
|
||||
return {
|
||||
"fas c-modal-celestial-quote-history__arrow": true,
|
||||
"o-dark-button": lightBG,
|
||||
"o-light-button": !lightBG,
|
||||
};
|
||||
},
|
||||
upClass() {
|
||||
return {
|
||||
"c-modal-celestial-quote-history__arrow": true,
|
||||
"c-modal-celestial-quote-history__arrow-up": true,
|
||||
...this.commonButtonClass,
|
||||
"c-modal-celestial-quote-history__arrow-up fa-chevron-circle-up": true,
|
||||
"c-modal-celestial-quote-history__arrow--disabled": this.focusedQuoteId <= 0,
|
||||
"fas": true,
|
||||
"fa-chevron-circle-up": true,
|
||||
};
|
||||
},
|
||||
downClass() {
|
||||
return {
|
||||
"c-modal-celestial-quote-history__arrow": true,
|
||||
"c-modal-celestial-quote-history__arrow-down": true,
|
||||
...this.commonButtonClass,
|
||||
"c-modal-celestial-quote-history__arrow-down fa-chevron-circle-down": true,
|
||||
"c-modal-celestial-quote-history__arrow--disabled": this.focusedQuoteId >= this.unlockedQuotes.length - 1,
|
||||
"fas": true,
|
||||
"fa-chevron-circle-down": true,
|
||||
};
|
||||
},
|
||||
leftClass() {
|
||||
return {
|
||||
"c-modal-celestial-quote-history__arrow": true,
|
||||
"c-modal-celestial-quote-history__arrow-left": true,
|
||||
...this.commonButtonClass,
|
||||
"c-modal-celestial-quote-history__arrow-left fa-chevron-circle-left": true,
|
||||
"c-modal-celestial-quote-history__arrow--disabled": this.currentQuoteLine <= 0,
|
||||
"fas": true,
|
||||
"fa-chevron-circle-left": true,
|
||||
};
|
||||
},
|
||||
rightClass() {
|
||||
return {
|
||||
"c-modal-celestial-quote-history__arrow": true,
|
||||
"c-modal-celestial-quote-history__arrow-right": true,
|
||||
...this.commonButtonClass,
|
||||
"c-modal-celestial-quote-history__arrow-right fa-chevron-circle-right": true,
|
||||
"c-modal-celestial-quote-history__arrow--disabled":
|
||||
this.currentQuoteLine >= this.focusedQuote.quote.totalLines - 1,
|
||||
"fas": true,
|
||||
"fa-chevron-circle-right": true,
|
||||
};
|
||||
},
|
||||
},
|
||||
@ -140,7 +143,7 @@ function easeOut(x) {
|
||||
<template>
|
||||
<div class="l-modal-overlay c-modal-overlay">
|
||||
<i
|
||||
class="c-modal-celestial-quote-history__close fas fa-circle-xmark"
|
||||
class="c-modal-celestial-quote-history__close fas fa-circle-xmark o-light-button"
|
||||
@click="close"
|
||||
/>
|
||||
<div
|
||||
@ -210,10 +213,17 @@ function easeOut(x) {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
font-size: 2.5rem;
|
||||
color: var(--color-text);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.o-light-button {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.o-dark-button {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.c-modal-celestial-quote-history__arrow--disabled {
|
||||
opacity: 0.4;
|
||||
cursor: default;
|
||||
|
@ -31,6 +31,29 @@ export default {
|
||||
},
|
||||
clicksLeft() {
|
||||
return 5 - this.overwriteCounter;
|
||||
},
|
||||
suggestionText() {
|
||||
const goodStyle = `style="color: var(--color-good)"`;
|
||||
const badStyle = `style="color: var(--color-bad)"`;
|
||||
|
||||
const suggestions = ["Loading this Cloud save "];
|
||||
const cloudProg = this.conflict.cloud.compositeProgress, localProg = this.conflict.local.compositeProgress;
|
||||
const warnOverwrite = this.farther && Math.abs(cloudProg - localProg) > 0.15;
|
||||
suggestions.push(warnOverwrite
|
||||
? `<b ${badStyle}>would cause your local save to lose significant progress</b>`
|
||||
: `<b ${goodStyle}>is probably safe</b>`);
|
||||
suggestions.push(this.hasLessSTDs
|
||||
? ` ${warnOverwrite ? "and" : "but"} <b ${badStyle}>will cause you to lose STDs on your local save</b>.`
|
||||
: "."
|
||||
);
|
||||
if (this.hasDifferentName) {
|
||||
suggestions.push(`<br>${warnOverwrite ? "Additionally" : "However"}, the Cloud save
|
||||
<b ${badStyle}>may be a save from a different device</b>.`);
|
||||
}
|
||||
if (warnOverwrite || this.hasDifferentName) {
|
||||
suggestions.push(`<br><b ${badStyle}>Are you sure you wish to overwrite your local save?</b>`);
|
||||
}
|
||||
return suggestions.join("");
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -54,21 +77,19 @@ export default {
|
||||
<template #header>
|
||||
Load Game from Cloud
|
||||
</template>
|
||||
<b>
|
||||
<span v-if="hasDifferentName">
|
||||
Your Local and Cloud Saves have different names.
|
||||
</span>
|
||||
<span v-else-if="older">
|
||||
Your Local Save appears to be older than your Cloud Save.
|
||||
</span>
|
||||
<span v-else-if="farther">
|
||||
Your Local Save appears to be farther than your Cloud Save.
|
||||
</span>
|
||||
<span v-else>
|
||||
Your Local Save and Cloud Save appear to have similar amounts of progress.
|
||||
</span>
|
||||
Please select the save you want to load.
|
||||
</b>
|
||||
<span v-if="hasDifferentName">
|
||||
Your Local and Cloud Saves have <b>different names</b>.
|
||||
</span>
|
||||
<span v-else-if="older">
|
||||
Loading from the Cloud would <b>load a save with less playtime</b>.
|
||||
</span>
|
||||
<span v-else-if="farther">
|
||||
Loading from the Cloud would <b>cause you to lose progress</b>.
|
||||
</span>
|
||||
<span v-else>
|
||||
Your Local Save and Cloud Save <b>appear to have similar amounts of progress</b>.
|
||||
</span>
|
||||
Please select the save you want to load.
|
||||
<br>
|
||||
<SaveInfoEntry
|
||||
:save-data="conflict.local"
|
||||
@ -84,6 +105,7 @@ export default {
|
||||
:show-name="hasDifferentName"
|
||||
save-type="Cloud Save"
|
||||
/>
|
||||
<span v-html="suggestionText" />
|
||||
<div
|
||||
v-if="hasLessSTDs"
|
||||
class="c-modal-IAP__warning"
|
||||
|
@ -34,6 +34,29 @@ export default {
|
||||
},
|
||||
clicksLeft() {
|
||||
return 5 - this.overwriteCounter;
|
||||
},
|
||||
suggestionText() {
|
||||
const goodStyle = `style="color: var(--color-good)"`;
|
||||
const badStyle = `style="color: var(--color-bad)"`;
|
||||
|
||||
const suggestions = ["Saving to the Cloud "];
|
||||
const cloudProg = this.conflict.cloud.compositeProgress, localProg = this.conflict.local.compositeProgress;
|
||||
const warnOverwrite = this.farther && Math.abs(cloudProg - localProg) > 0.15;
|
||||
suggestions.push(warnOverwrite
|
||||
? `<b ${badStyle}>would overwrite a save with significantly more progress</b>`
|
||||
: `<b ${goodStyle}>is probably safe</b>`);
|
||||
suggestions.push(this.hasLessSTDs
|
||||
? ` ${warnOverwrite ? "and" : "but"} <b ${badStyle}>will cause your Cloud save to lose STDs</b>.`
|
||||
: "."
|
||||
);
|
||||
if (this.hasDifferentName || this.wrongHash) {
|
||||
suggestions.push(` ${warnOverwrite ? "Additionally" : "However"}, you may be overwriting a
|
||||
<b ${badStyle}>save from a different device</b>.`);
|
||||
}
|
||||
if (warnOverwrite || this.hasDifferentName || this.wrongHash) {
|
||||
suggestions.push(`<br><b ${badStyle}>Are you sure you wish to overwrite the Cloud save?</b>`);
|
||||
}
|
||||
return suggestions.join("");
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -43,6 +66,7 @@ export default {
|
||||
if (accepted) {
|
||||
this.conflict.onAccept?.();
|
||||
}
|
||||
EventHub.dispatch(GAME_EVENT.CLOSE_MODAL);
|
||||
},
|
||||
cancel() {
|
||||
this.overwriteCounter++;
|
||||
@ -67,23 +91,21 @@ export default {
|
||||
<template #header>
|
||||
Save Game to Cloud
|
||||
</template>
|
||||
<b>
|
||||
<span v-if="wrongHash">
|
||||
Your Cloud Save has been changed by someone else since you last saved to the Cloud this session.
|
||||
</span>
|
||||
<span v-else-if="hasDifferentName">
|
||||
Your Local and Cloud Saves have different names.
|
||||
</span>
|
||||
<span v-else-if="older">
|
||||
Your Cloud Save appears to be older than your Local Save.
|
||||
</span>
|
||||
<span v-else-if="farther">
|
||||
Your Cloud Save appears to be farther than your Local Save.
|
||||
</span>
|
||||
<span v-else>
|
||||
Your Local Save and Cloud Save appear to have similar amounts of progress.
|
||||
</span>
|
||||
</b>
|
||||
<span v-if="wrongHash">
|
||||
Your Cloud Save has been <b>changed by a different device</b> since you last saved to the Cloud this session.
|
||||
</span>
|
||||
<span v-else-if="hasDifferentName">
|
||||
Your Local and Cloud Saves have <b>different names</b>.
|
||||
</span>
|
||||
<span v-else-if="older">
|
||||
Saving to the Cloud would <b>overwrite an older save</b>.
|
||||
</span>
|
||||
<span v-else-if="farther">
|
||||
Saving to the Cloud would <b>overwrite a save with more progress</b>.
|
||||
</span>
|
||||
<span v-else>
|
||||
Your Local Save and Cloud Save <b>appear to have similar amounts of progress</b>.
|
||||
</span>
|
||||
<br>
|
||||
<SaveInfoEntry
|
||||
:save-data="conflict.local"
|
||||
@ -99,8 +121,7 @@ export default {
|
||||
:show-name="hasDifferentName"
|
||||
save-type="Cloud Save"
|
||||
/>
|
||||
Would you like to overwrite the Cloud Save? Your choice here will apply for every
|
||||
time the game automatically attempts to Cloud Save, until the page is reloaded.
|
||||
<span v-html="suggestionText" />
|
||||
<div
|
||||
v-if="hasLessSTDs"
|
||||
class="c-modal-IAP__warning"
|
||||
@ -108,6 +129,9 @@ export default {
|
||||
LOCAL SAVE HAS LESS STDs BOUGHT, YOU WILL LOSE THEM IF YOU OVERWRITE.
|
||||
<br>CLICK THE BUTTON 5 TIMES TO CONFIRM.
|
||||
</div>
|
||||
<br>
|
||||
Choosing to overwrite will force a save to the Cloud every time, while choosing to not
|
||||
overwrite will effectively disable Cloud saving. This lasts until you reload the page.
|
||||
<template #cancel-text>
|
||||
Overwrite Cloud Save <span v-if="hasLessSTDs">({{ clicksLeft }})</span>
|
||||
</template>
|
||||
@ -115,4 +139,4 @@ export default {
|
||||
Do not overwrite
|
||||
</template>
|
||||
</ModalWrapperChoice>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -22,7 +22,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.tachyonGain.copyFrom(getTachyonGain());
|
||||
this.tachyonGain.copyFrom(getTachyonGain(true));
|
||||
this.isDoomed = Pelle.isDoomed;
|
||||
},
|
||||
handleYesClick() {
|
||||
|
@ -21,6 +21,11 @@ export default {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
isModal: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@ -44,6 +49,12 @@ export default {
|
||||
"o-primary-btn--disabled": !this.isUnlockable
|
||||
};
|
||||
},
|
||||
autobuyerBoxRowClass() {
|
||||
return {
|
||||
"c-autobuyer-box-row": true,
|
||||
"c-autobuyer-box-row__modal": this.isModal
|
||||
};
|
||||
},
|
||||
autobuyerToggleClass() {
|
||||
if (!this.globalToggle) {
|
||||
return this.isActive ? "fas fa-pause" : "fas fa-times";
|
||||
@ -54,6 +65,7 @@ export default {
|
||||
if (!this.globalToggle) {
|
||||
return {
|
||||
"o-autobuyer-toggle-checkbox__label": true,
|
||||
"o-autobuyer-toggle-checkbox__label-modal": this.isModal,
|
||||
"o-autobuyer-toggle-checkbox__label--active-paused": this.isActive,
|
||||
"o-autobuyer-toggle-checkbox__label--deactive-paused": !this.isActive,
|
||||
"o-autobuyer-toggle-checkbox__label--disabled": !this.globalToggle
|
||||
@ -61,6 +73,7 @@ export default {
|
||||
}
|
||||
return {
|
||||
"o-autobuyer-toggle-checkbox__label": true,
|
||||
"o-autobuyer-toggle-checkbox__label-modal": this.isModal,
|
||||
"o-autobuyer-toggle-checkbox__label--active": this.isActive,
|
||||
"o-autobuyer-toggle-checkbox__label--disabled": !this.globalToggle
|
||||
};
|
||||
@ -104,7 +117,7 @@ export default {
|
||||
<template>
|
||||
<div
|
||||
v-if="isUnlocked || isBought"
|
||||
class="c-autobuyer-box-row"
|
||||
:class="autobuyerBoxRowClass"
|
||||
>
|
||||
<div class="l-autobuyer-box__header">
|
||||
{{ name }}
|
||||
|
@ -14,6 +14,13 @@ export default {
|
||||
ExpandingControlBox,
|
||||
AutobuyerDropdownEntry
|
||||
},
|
||||
props: {
|
||||
isModal: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isDoomed: false,
|
||||
@ -84,6 +91,7 @@ export default {
|
||||
<AutobuyerBox
|
||||
:autobuyer="autobuyer"
|
||||
:show-interval="!postBreak"
|
||||
:is-modal="isModal"
|
||||
name="Automatic Big Crunch"
|
||||
>
|
||||
<template
|
||||
|
@ -10,6 +10,13 @@ export default {
|
||||
AutobuyerIntervalButton,
|
||||
AutobuyerInput
|
||||
},
|
||||
props: {
|
||||
isModal: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasMaxedInterval: false,
|
||||
@ -44,6 +51,7 @@ export default {
|
||||
<template>
|
||||
<AutobuyerBox
|
||||
:autobuyer="autobuyer"
|
||||
:is-modal="isModal"
|
||||
:show-interval="!isBuyMaxUnlocked"
|
||||
name="Automatic Dimension Boosts"
|
||||
>
|
||||
|
@ -12,6 +12,13 @@ export default {
|
||||
ExpandingControlBox,
|
||||
AutobuyerDropdownEntry
|
||||
},
|
||||
props: {
|
||||
isModal: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isDoomed: false,
|
||||
@ -77,6 +84,7 @@ export default {
|
||||
<template>
|
||||
<AutobuyerBox
|
||||
:autobuyer="autobuyer"
|
||||
:is-modal="isModal"
|
||||
name="Automatic Eternity"
|
||||
>
|
||||
<template #intervalSlot>
|
||||
|
@ -10,6 +10,13 @@ export default {
|
||||
AutobuyerIntervalButton,
|
||||
AutobuyerInput
|
||||
},
|
||||
props: {
|
||||
isModal: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasMaxedInterval: false,
|
||||
@ -42,6 +49,7 @@ export default {
|
||||
<template>
|
||||
<AutobuyerBox
|
||||
:autobuyer="autobuyer"
|
||||
:is-modal="isModal"
|
||||
name="Automatic Antimatter Galaxies"
|
||||
:show-interval="!isBuyMaxUnlocked"
|
||||
>
|
||||
|
@ -12,6 +12,13 @@ export default {
|
||||
ExpandingControlBox,
|
||||
AutobuyerDropdownEntry
|
||||
},
|
||||
props: {
|
||||
isModal: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mode: AUTO_REALITY_MODE.RM,
|
||||
@ -50,6 +57,7 @@ export default {
|
||||
<template>
|
||||
<AutobuyerBox
|
||||
:autobuyer="autobuyer"
|
||||
:is-modal="isModal"
|
||||
name="Automatic Reality"
|
||||
>
|
||||
<template #intervalSlot>
|
||||
|
@ -45,7 +45,8 @@ export default {
|
||||
update() {
|
||||
this.isDisabled = this.challenge.isDisabled;
|
||||
this.isUnlocked = this.challenge.isUnlocked;
|
||||
this.isRunning = this.challenge.isRunning;
|
||||
// This stops normal challenges from appearing like they're running during IC1
|
||||
this.isRunning = this.challenge.isOnlyActiveChallenge;
|
||||
this.lockedAt = this.challenge.config.lockedAt;
|
||||
this.isBroken = Enslaved.isRunning && Enslaved.BROKEN_CHALLENGES.includes(this.challengeId);
|
||||
this.isCompleted = this.challenge.isCompleted && !this.isBroken;
|
||||
|
@ -6,29 +6,43 @@ export default {
|
||||
components: {
|
||||
SliderComponent
|
||||
},
|
||||
props: {
|
||||
min: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
interval: {
|
||||
type: Number,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
autosaveInterval: 10
|
||||
sliderInterval: 10
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
sliderProps() {
|
||||
return {
|
||||
min: 10,
|
||||
max: 60,
|
||||
interval: 1,
|
||||
min: this.min,
|
||||
max: this.max,
|
||||
interval: this.interval,
|
||||
width: "100%",
|
||||
tooltip: false
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.autosaveInterval = player.options.autosaveInterval / 1000;
|
||||
this.sliderInterval = player.options.autosaveInterval / 1000;
|
||||
},
|
||||
adjustSliderValue(value) {
|
||||
this.autosaveInterval = value;
|
||||
player.options.autosaveInterval = this.autosaveInterval * 1000;
|
||||
this.sliderInterval = value;
|
||||
player.options.autosaveInterval = this.sliderInterval * 1000;
|
||||
GameOptions.refreshAutosaveInterval();
|
||||
}
|
||||
}
|
||||
@ -37,11 +51,11 @@ export default {
|
||||
|
||||
<template>
|
||||
<div class="o-primary-btn o-primary-btn--option o-primary-btn--slider l-options-grid__button">
|
||||
<b>Autosave interval: {{ formatInt(autosaveInterval) }}s</b>
|
||||
<b>Autosave interval: {{ formatInt(sliderInterval) }}s</b>
|
||||
<SliderComponent
|
||||
class="o-primary-btn--slider__slider"
|
||||
v-bind="sliderProps"
|
||||
:value="autosaveInterval"
|
||||
:value="sliderInterval"
|
||||
@input="adjustSliderValue($event)"
|
||||
/>
|
||||
</div>
|
||||
|
@ -17,17 +17,22 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
cloudEnabled: false,
|
||||
syncSaveIntervals: false,
|
||||
showTimeSinceSave: false,
|
||||
loggedIn: false,
|
||||
userName: "",
|
||||
canSpeedrun: false,
|
||||
creditsClosed: false
|
||||
creditsClosed: false,
|
||||
isCloudSaving: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
cloudEnabled(newValue) {
|
||||
player.options.cloudEnabled = newValue;
|
||||
},
|
||||
syncSaveIntervals(newValue) {
|
||||
player.options.syncSaveIntervals = newValue;
|
||||
},
|
||||
showTimeSinceSave(newValue) {
|
||||
player.options.showTimeSinceSave = newValue;
|
||||
}
|
||||
@ -36,12 +41,14 @@ export default {
|
||||
update() {
|
||||
const options = player.options;
|
||||
this.cloudEnabled = options.cloudEnabled;
|
||||
this.syncSaveIntervals = options.syncSaveIntervals;
|
||||
this.showTimeSinceSave = options.showTimeSinceSave;
|
||||
this.loggedIn = Cloud.loggedIn;
|
||||
this.canSpeedrun = player.speedrun.isUnlocked;
|
||||
this.creditsClosed = GameEnd.creditsEverClosed;
|
||||
if (!this.loggedIn) return;
|
||||
this.userName = Cloud.user.displayName;
|
||||
this.isCloudSaving = Cloud.shouldOverwriteCloudSave;
|
||||
},
|
||||
importAsFile(event) {
|
||||
// This happens if the file dialog is canceled instead of a file being selected
|
||||
@ -52,6 +59,15 @@ export default {
|
||||
const contents = reader.result;
|
||||
const toImport = GameSaveSerializer.deserialize(contents);
|
||||
const showWarning = (toImport?.IAP?.totalSTD ?? 0) < player.IAP.totalSTD;
|
||||
|
||||
// File importing behavior should use the behavior on the existing and to-be-overwritten save instead of the
|
||||
// settings in the to-be-imported save. This is largely because the former is more easily edited by the player,
|
||||
// and in contrast with the import-as-string case which allows the player to choose.
|
||||
// Note: Do not move this into GameStorage.import, as this would cause the offline progress choice in the text
|
||||
// import modal (the only other place GameStorage.import is called) to always be overridden
|
||||
GameStorage.offlineEnabled = player.options.offlineProgress;
|
||||
GameStorage.offlineTicks = player.options.offlineTicks;
|
||||
|
||||
if (showWarning) {
|
||||
Modal.addImportConflict(toImport, GameStorage.saves[GameStorage.currentSlot]);
|
||||
Modal.importWarning.show({
|
||||
@ -110,7 +126,11 @@ export default {
|
||||
>
|
||||
Choose save
|
||||
</OptionsButton>
|
||||
<AutosaveIntervalSlider />
|
||||
<AutosaveIntervalSlider
|
||||
:min="10"
|
||||
:max="60"
|
||||
:interval="1"
|
||||
/>
|
||||
</div>
|
||||
<div class="l-options-grid__row">
|
||||
<OptionsButton
|
||||
@ -155,31 +175,28 @@ export default {
|
||||
<span v-if="loggedIn">Logged in as {{ userName }}</span>
|
||||
<span v-else>Not logged in</span>
|
||||
</h2>
|
||||
<div v-if="loggedIn">
|
||||
<span v-if="isCloudSaving">Cloud Saving will occur automatically every 5 minutes.</span>
|
||||
<span v-else>Cloud Saving has been disabled until you refresh the page or switch saves.</span>
|
||||
</div>
|
||||
<div class="l-options-grid">
|
||||
<div
|
||||
v-if="loggedIn"
|
||||
class="l-options-grid__row"
|
||||
>
|
||||
<OptionsButton
|
||||
v-if="loggedIn"
|
||||
onclick="GameOptions.cloudSave()"
|
||||
:class="{ 'o-pelle-disabled-pointer': creditsClosed }"
|
||||
>
|
||||
Cloud save
|
||||
</OptionsButton>
|
||||
<OptionsButton
|
||||
v-if="loggedIn"
|
||||
onclick="GameOptions.cloudLoad()"
|
||||
:class="{ 'o-pelle-disabled-pointer': creditsClosed }"
|
||||
>
|
||||
Cloud load
|
||||
</OptionsButton>
|
||||
<PrimaryToggleButton
|
||||
v-model="cloudEnabled"
|
||||
class="o-primary-btn--option l-options-grid__button"
|
||||
:class="{ 'o-pelle-disabled-pointer': creditsClosed }"
|
||||
label="Automatic cloud saving/loading:"
|
||||
/>
|
||||
</div>
|
||||
<div class="l-options-grid__row">
|
||||
<OptionsButton
|
||||
v-if="loggedIn"
|
||||
onclick="GameOptions.logout()"
|
||||
@ -194,6 +211,23 @@ export default {
|
||||
Login with Google to enable Cloud Saving
|
||||
</OptionsButton>
|
||||
</div>
|
||||
<div
|
||||
v-if="loggedIn"
|
||||
class="l-options-grid__row"
|
||||
>
|
||||
<PrimaryToggleButton
|
||||
v-model="cloudEnabled"
|
||||
class="o-primary-btn--option l-options-grid__button"
|
||||
:class="{ 'o-pelle-disabled-pointer': creditsClosed }"
|
||||
label="Automatic cloud saving/loading:"
|
||||
/>
|
||||
<PrimaryToggleButton
|
||||
v-model="syncSaveIntervals"
|
||||
class="o-primary-btn--option l-options-grid__button"
|
||||
:class="{ 'o-pelle-disabled-pointer': creditsClosed }"
|
||||
label="Force local save before cloud saving:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -25,7 +25,6 @@ export default {
|
||||
theme: "",
|
||||
notation: "",
|
||||
commas: false,
|
||||
autosaveInterval: 3000,
|
||||
headerTextColored: true,
|
||||
};
|
||||
},
|
||||
|
@ -29,9 +29,10 @@ export default {
|
||||
this.showRequirement = Pelle.isDoomed && !Pelle.canDilateInPelle;
|
||||
if (!this.isRunning) return;
|
||||
this.canEternity = Player.canEternity;
|
||||
this.hasGain = getTachyonGain().gt(0);
|
||||
// This lets this.hasGain be true even before eternity.
|
||||
this.hasGain = getTachyonGain(false).gt(0);
|
||||
if (this.canEternity && this.hasGain) {
|
||||
this.tachyonGain.copyFrom(getTachyonGain());
|
||||
this.tachyonGain.copyFrom(getTachyonGain(true));
|
||||
} else if (this.hasGain) {
|
||||
this.eternityGoal.copyFrom(Player.eternityGoal);
|
||||
} else {
|
||||
|
@ -142,15 +142,13 @@ export default {
|
||||
this.gainedEP.copyFrom(gainedEP);
|
||||
const hasNewContent = !PlayerProgress.realityUnlocked() &&
|
||||
Currency.eternityPoints.exponent >= 4000 &&
|
||||
Currency.timeTheorems.gte(5e9) &&
|
||||
player.records.thisReality.maxReplicanti.exponent > 20000;
|
||||
|
||||
!TimeStudy.reality.isBought;
|
||||
if (player.dilation.active) {
|
||||
this.type = hasNewContent
|
||||
? EP_BUTTON_DISPLAY_TYPE.DILATION_EXPLORE_NEW_CONTENT
|
||||
: EP_BUTTON_DISPLAY_TYPE.DILATION;
|
||||
this.currentTachyons.copyFrom(Currency.tachyonParticles);
|
||||
this.gainedTachyons.copyFrom(getTachyonGain());
|
||||
this.gainedTachyons.copyFrom(getTachyonGain(true));
|
||||
return;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user