Merge branch 'master' into Fix-Pelle-Stuff

This commit is contained in:
Phoenix51505 2023-02-08 18:10:57 -05:00 committed by GitHub
commit df01ce1483
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
134 changed files with 2484 additions and 406 deletions

View File

@ -142,12 +142,6 @@ export const Achievements = {
return;
}
if (Achievements.preReality.every(a => a.isUnlocked)) return;
if (Perk.achievementGroup5.isBought) {
for (const achievement of Achievements.preReality) {
achievement.unlock(true);
}
return;
}
player.reality.achTimer += diff;
if (player.reality.achTimer < this.period) return;

View File

@ -72,6 +72,8 @@ import SwitchAutomatorEditorModal from "@/components/modals/SwitchAutomatorEdito
import UiChoiceModal from "@/components/modals/UiChoiceModal";
import UndoGlyphModal from "@/components/modals/UndoGlyphModal";
import S12GamesModal from "@/components/modals/secret-themes/S12GamesModal";
let nextModalID = 0;
export class Modal {
constructor(component, priority = 0, closeEvent) {
@ -255,6 +257,8 @@ Modal.sacrifice = new Modal(SacrificeModal, 1, GAME_EVENT.DIMBOOST_AFTER);
Modal.breakInfinity = new Modal(BreakInfinityModal, 1, GAME_EVENT.ETERNITY_RESET_AFTER);
Modal.respecIAP = new Modal(RespecIAPModal);
Modal.s12Games = new Modal(S12GamesModal);
function getSaveInfo(save) {
const resources = {
realTimePlayed: 0,

View File

@ -4,7 +4,7 @@ export const Theme = function Theme(name, config) {
this.name = name;
this.isDark = function() {
return this.isDefault()
return (this.isDefault() || name === "S12")
? player.options.newUI
: config.isDark;
};
@ -88,6 +88,7 @@ Theme.secretThemeIndex = function(name) {
"dba8336cd3224649d07952b00045a6ec3c8df277aa8a0a0e3e7c2aaa77f1fbb9",
"73de8a7f9efa1cbffc80a8effc9891a799127cd204b3a8b023bea8f513ed4753",
"f3a71114261b4af6517a53f89bf0c6b56bb81b6f0e931d0e0d71249eb196628c",
"1248689171faaa0abb68279199a8d2eb232dba10d2dacb79a705f680b6862c0e",
];
const sha = sha512_256(name.toUpperCase());
return secretThemes.indexOf(sha);
@ -153,6 +154,7 @@ export const Themes = {
Theme.create("S9", { secret: true, }),
Theme.create("S10", { dark: true, metro: true, animated: true, secret: true, }),
Theme.create("S11", { dark: true, animated: true, secret: true, }),
Theme.create("S12", { secret: true, }),
/* eslint-enable no-multi-spaces */
],

View File

@ -40,6 +40,11 @@ Autobuyer.epMult = new class EPMultAutobuyerState extends AutobuyerState {
}
tick() {
// While the active check is normally automatically handled with the global autobuyer ticking method, we also
// call this from the TD autobuyers in order to make sure this is executed before TDs are purchased. Simply
// reordering the autobuyer call order is undesirable because much of the codebase relies on autobuyers being
// grouped as they are, and many other autobuyers in the 5xEP group must execute *after* dimensions
if (!this.isActive) return;
applyEU2();
EternityUpgrade.epMult.buyMax();
}

View File

@ -41,12 +41,30 @@ Autobuyer.reality = new class RealityAutobuyerState extends AutobuyerState {
this.data.glyph = value;
}
get time() {
return this.data.time;
}
set time(value) {
this.data.time = value;
}
get shard() {
return this.data.shard;
}
set shard(value) {
this.data.shard = value;
}
toggleMode() {
this.mode = [
AUTO_REALITY_MODE.RM,
AUTO_REALITY_MODE.GLYPH,
AUTO_REALITY_MODE.EITHER,
AUTO_REALITY_MODE.BOTH
AUTO_REALITY_MODE.BOTH,
AUTO_REALITY_MODE.TIME,
AUTO_REALITY_MODE.RELIC_SHARD
]
.nextSibling(this.mode);
}
@ -74,6 +92,12 @@ Autobuyer.reality = new class RealityAutobuyerState extends AutobuyerState {
case AUTO_REALITY_MODE.BOTH:
proc = rmProc && glyphProc;
break;
case AUTO_REALITY_MODE.TIME:
proc = player.records.thisReality.realTime / 1000 > this.time;
break;
case AUTO_REALITY_MODE.RELIC_SHARD:
proc = Effarig.shardsGained > this.shard;
break;
}
if (proc) autoReality();
}

View File

@ -35,6 +35,7 @@ class TimeDimensionAutobuyerState extends IntervaledAutobuyerState {
tick() {
applyEU2();
Autobuyer.epMult.tick();
const tier = this.tier;
if (!TimeDimension(tier).isAvailableForPurchase) return;
super.tick();

View File

@ -856,6 +856,8 @@ export const AutomatorBackend = {
},
start(scriptID = this.state.topLevelScript, initialMode = AUTOMATOR_MODE.RUN, compile = true) {
// Automator execution behaves oddly across new games, so we explicitly stop it from running if not unlocked
if (!Player.automatorUnlocked) return;
this.hasJustCompleted = false;
this.state.topLevelScript = scriptID;
const scriptObject = this.findScript(scriptID);

View File

@ -57,15 +57,15 @@ export const AutomatorCommands = ((() => {
let addedECs, gainedEP;
switch (layer) {
case "INFINITY":
return `${format(player.records.lastTenInfinities[0][1], 2)} IP`;
return `${format(player.records.recentInfinities[0][1], 2)} IP`;
case "ETERNITY":
addedECs = AutomatorData.lastECCompletionCount;
gainedEP = `${format(player.records.lastTenEternities[0][1], 2)} EP`;
gainedEP = `${format(player.records.recentEternities[0][1], 2)} EP`;
return addedECs === 0
? `${gainedEP}`
: `${gainedEP}, ${addedECs} completions`;
case "REALITY":
return `${format(player.records.lastTenRealities[0][1], 2)} RM`;
return `${format(player.records.recentRealities[0][1], 2)} RM`;
default:
throw Error(`Unrecognized prestige ${layer} in Automator event log`);
}

View File

@ -3,6 +3,7 @@ import { GameDatabase } from "./secret-formula/game-database";
class AwayProgress {
constructor(config) {
this.name = config.name;
this.forcedName = config.forcedName;
this.isUnlocked = config.isUnlocked;
this.awayOption = config.awayOption ?? this.name;
this.showOption = config.showOption ?? true;
@ -32,6 +33,7 @@ class AwayProgress {
}
get formatName() {
if (this.forcedName) return this.forcedName;
// Format the camelCase name to Title Case, with spaces added before the capital letters
return this.name
.replace(/[A-Z]/gu, match => ` ${match}`)

View File

@ -27,7 +27,9 @@ function handleChallengeCompletion() {
export function manualBigCrunchResetRequest() {
if (!Player.canCrunch) return;
if (GameEnd.creditsEverClosed) return;
if (player.options.confirmations.bigCrunch && player.break) {
// We show the modal under two conditions - on the first ever infinity (to explain the mechanic) and
// post-break (to show total IP and infinities gained)
if (player.options.confirmations.bigCrunch && (!PlayerProgress.infinityUnlocked() || player.break)) {
Modal.bigCrunch.show();
} else {
bigCrunchResetRequest();
@ -177,7 +179,7 @@ export function preProductionGenerateIP(diff) {
genCount = Math.floor(player.partInfinityPoint);
player.partInfinityPoint -= genCount;
}
let gainedPerGen = InfinityUpgrade.ipGen.effectValue;
let gainedPerGen = player.records.bestInfinity.time >= 999999999999 ? DC.D0 : InfinityUpgrade.ipGen.effectValue;
if (Laitela.isRunning) gainedPerGen = dilatedValueOf(gainedPerGen);
const gainedThisTick = new Decimal(genCount).times(gainedPerGen);
Currency.infinityPoints.add(gainedThisTick);

View File

@ -48,14 +48,14 @@ export const GameCache = {
worstChallengeTime: new Lazy(() => player.challenge.normal.bestTimes.max()),
bestRunIPPM: new Lazy(() =>
player.records.lastTenInfinities
.map(run => ratePerMinute(run[1], run[0]))
player.records.recentInfinities
.map(run => ratePerMinute(run[2], run[0]))
.reduce(Decimal.maxReducer)
),
averageRealTimePerEternity: new Lazy(() => player.records.lastTenEternities
.map(run => run[3])
.reduce(Number.sumReducer) / (1000 * player.records.lastTenEternities.length)),
averageRealTimePerEternity: new Lazy(() => player.records.recentEternities
.map(run => run[1])
.reduce(Number.sumReducer) / (1000 * player.records.recentEternities.length)),
tickSpeedMultDecrease: new Lazy(() => 10 - Effects.sum(
BreakInfinityUpgrade.tickspeedCostMult,
@ -76,8 +76,7 @@ export const GameCache = {
Perk.achievementGroup1,
Perk.achievementGroup2,
Perk.achievementGroup3,
Perk.achievementGroup4,
Perk.achievementGroup5
Perk.achievementGroup4
)).totalMilliseconds),
buyablePerks: new Lazy(() => Perks.all.filter(p => p.canBeBought)),

View File

@ -82,7 +82,8 @@ class VRunUnlockState extends GameMechanicState {
Decimal.gte(playerData.runRecords[this.id], this.conditionValue)) {
if (!V.isFlipped && this.config.isHard) continue;
this.completions++;
GameUI.notify.success(`You have unlocked V-Achievement '${this.config.name}' tier ${this.completions}`);
GameUI.notify.success(`You have unlocked V-Achievement
'${this.config.name}' tier ${formatInt(this.completions)}`);
V.updateTotalRunUnlocks();

View File

@ -248,7 +248,7 @@ export const Pelle = {
case undefined:
return "No Glyph equipped!";
default:
return "";
return "You cannot equip this Glyph while Doomed!";
}
},

View File

@ -67,7 +67,7 @@ class AlchemyResourceState extends GameMechanicState {
}
get lockText() {
return `${this.unlockedWith.name} Level ${this.unlockedAt}`;
return `${this.unlockedWith.name} Level ${formatInt(this.unlockedAt)}`;
}
get isCustomEffect() {

View File

@ -215,7 +215,9 @@ window.AUTO_REALITY_MODE = {
RM: 0,
GLYPH: 1,
EITHER: 2,
BOTH: 3
BOTH: 3,
TIME: 4,
RELIC_SHARD: 5,
};
// Free tickspeed multiplier with TS171. Shared here because formatting glyph effects depends on it

View File

@ -9,11 +9,11 @@ export function animateAndDilate() {
}
// eslint-disable-next-line no-empty-function
export function animateAndUndilate(callback = () => {}) {
export function animateAndUndilate(callback) {
FullScreenAnimationHandler.display("a-undilate", 2);
setTimeout(() => {
eternity(false, false, { switchingDilation: true });
callback();
if (callback) callback();
}, 1000);
}
@ -176,8 +176,8 @@ 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
// and for "exit dilation" button (saying whether you need more antimatter)
// Returns the amount of TP gained, subtracting out current TP; used for displaying gained TP, text on the
// "exit dilation" button (saying whether you need more antimatter), and in last 10 eternities
export function getTachyonGain(requireEternity) {
return getTP(Currency.antimatter.value, requireEternity).minus(Currency.tachyonParticles.value).clampMin(0);
}

View File

@ -77,7 +77,7 @@ export function eternity(force, auto, specialConditions = {}) {
if (!force) {
if (!Player.canEternity) return false;
EventHub.dispatch(GAME_EVENT.ETERNITY_RESET_BEFORE);
if (!player.dilation.active) giveEternityRewards(auto);
giveEternityRewards(auto);
player.requirementChecks.reality.noEternities = false;
}
@ -138,7 +138,7 @@ export function eternity(force, auto, specialConditions = {}) {
}
// eslint-disable-next-line no-empty-function
export function animateAndEternity(callback = () => {}) {
export function animateAndEternity(callback) {
if (!Player.canEternity) return false;
const hasAnimation = !FullScreenAnimationHandler.isDisplaying &&
((player.dilation.active && player.options.animations.dilation) ||
@ -151,12 +151,12 @@ export function animateAndEternity(callback = () => {}) {
eternityAnimation();
setTimeout(() => {
eternity();
callback();
if (callback) callback();
}, 2250);
}
} else {
eternity();
callback();
if (callback) callback();
}
return hasAnimation;
}

View File

@ -188,10 +188,11 @@ export class EternityChallengeState extends GameMechanicState {
// If dilation is active, the { enteringEC: true } parameter will cause
// dilation to not be disabled. We still don't force-eternity, though;
// this causes TP to still be gained.
const enteringGamespeed = getGameSpeedupFactor();
if (Player.canEternity) eternity(false, auto, { enteringEC: true });
player.challenge.eternity.current = this.id;
if (this.id === 12) {
if (player.requirementChecks.reality.slowestBH < 1) {
if (enteringGamespeed < 0.001) {
SecretAchievement(42).unlock();
}
player.requirementChecks.reality.slowestBH = 1;

View File

@ -449,13 +449,13 @@ export const Glyphs = {
if (player.reality.autoCollapse) this.collapseEmptySlots();
},
sortByLevel() {
this.sort((a, b) => -a.level + b.level);
this.sort((a, b) => b.level - a.level);
},
sortByPower() {
this.sort((a, b) => -a.level * a.strength + b.level * b.strength);
this.sort((a, b) => b.level * b.strength - a.level * a.strength);
},
sortByScore() {
this.sort((a, b) => -AutoGlyphProcessor.filterValue(a) + AutoGlyphProcessor.filterValue(b));
this.sort((a, b) => AutoGlyphProcessor.filterValue(b) - AutoGlyphProcessor.filterValue(a));
},
sortByEffect() {
function reverseBitstring(eff) {
@ -463,7 +463,7 @@ export const Glyphs = {
}
// The bitwise reversal is so that the effects with the LOWER id are valued higher in the sorting.
// This primarily meant for effarig glyph effect sorting, which makes it prioritize timespeed pow highest.
this.sort((a, b) => -reverseBitstring(a.effects) + reverseBitstring(b.effects));
this.sort((a, b) => reverseBitstring(b.effects) - reverseBitstring(a.effects));
},
// If there are enough glyphs that are better than the specified glyph, in every way, then
// the glyph is objectively a useless piece of garbage.

View File

@ -18,17 +18,22 @@ export const NG = {
const automatorConstants = JSON.stringify(player.reality.automator.constants);
const automatorScripts = JSON.stringify(player.reality.automator.scripts);
const fullCompletions = player.records.fullGameCompletions;
const fullTimePlayed = player.records.previousRunRealTime + player.records.realTimePlayed;
GlyphAppearanceHandler.unlockSet();
const glyphCosmetics = JSON.stringify(player.reality.glyphs.cosmetics);
Modal.hideAll();
Quote.clearAll();
GameStorage.hardReset();
player.options = JSON.parse(backUpOptions);
// We need to force this one to be true because otherwise the player will be unable to select their glyphs
// until they can auto-reality
player.options.confirmations.glyphSelection = true;
player.secretUnlocks = secretUnlocks;
player.secretAchievementBits = JSON.parse(secretAchievements);
player.reality.automator.constants = JSON.parse(automatorConstants);
player.reality.automator.scripts = JSON.parse(automatorScripts);
player.records.fullGameCompletions = fullCompletions + 1;
player.records.previousRunRealTime = fullTimePlayed;
ui.view.newUI = player.options.newUI;
ui.view.news = player.options.news.enabled;
player.reality.glyphs.cosmetics = JSON.parse(glyphCosmetics);

View File

@ -23,6 +23,7 @@ export const NewsHandler = {
// we pad the array with zeroes until we can fit the new ID in before actually adding it.
while (this.BITS_PER_MASK * player.news.seen[type].length <= number) player.news.seen[type].push(0);
player.news.seen[type][Math.floor(number / this.BITS_PER_MASK)] |= 1 << (number % this.BITS_PER_MASK);
player.news.totalSeen++;
},
hasSeenNews(id) {

View File

@ -48,6 +48,12 @@ class PerkState extends SetPurchasableMechanicState {
onPurchased() {
if (this.config.bumpCurrency !== undefined) this.config.bumpCurrency();
if (this.label === "EU1" && Currency.eternities.gt(0)) applyEU1();
if (this.label === "ACHNR") {
if (Achievements.preReality.some(a => !a.isUnlocked)) player.reality.gainedAutoAchievements = true;
for (const achievement of Achievements.preReality) {
achievement.unlock(true);
}
}
GameCache.achievementPeriod.invalidate();
GameCache.buyablePerks.invalidate();
EventHub.dispatch(GAME_EVENT.PERK_BOUGHT);

View File

@ -62,6 +62,8 @@ window.player = {
mode: 0,
rm: DC.D1,
glyph: 0,
time: 0,
shard: 0,
isActive: false
},
eternity: {
@ -271,19 +273,21 @@ window.player = {
realTimePlayed: 0,
realTimeDoomed: 0,
fullGameCompletions: 0,
previousRunRealTime: 0,
totalAntimatter: DC.E1,
lastTenInfinities: Array.range(0, 10).map(() =>
[Number.MAX_VALUE, DC.D1, DC.D1, Number.MAX_VALUE]),
lastTenEternities: Array.range(0, 10).map(() =>
[Number.MAX_VALUE, DC.D1, DC.D1, Number.MAX_VALUE]),
lastTenRealities: Array.range(0, 10).map(() =>
[Number.MAX_VALUE, DC.D1, 1, Number.MAX_VALUE, 0]),
recentInfinities: Array.range(0, 10).map(() =>
[Number.MAX_VALUE, Number.MAX_VALUE, DC.D1, DC.D1, ""]),
recentEternities: Array.range(0, 10).map(() =>
[Number.MAX_VALUE, Number.MAX_VALUE, DC.D1, DC.D1, "", DC.D0]),
recentRealities: Array.range(0, 10).map(() =>
[Number.MAX_VALUE, Number.MAX_VALUE, DC.D1, 1, "", 0, 0]),
thisInfinity: {
time: 0,
realTime: 0,
lastBuyTime: 0,
maxAM: DC.D0,
bestIPmin: DC.D0,
bestIPminVal: DC.D0,
},
bestInfinity: {
time: Number.MAX_VALUE,
@ -298,6 +302,7 @@ window.player = {
maxIP: DC.D0,
bestIPMsWithoutMaxAll: DC.D0,
bestEPmin: DC.D0,
bestEPminVal: DC.D0,
bestInfinitiesPerMs: DC.D0,
},
bestEternity: {
@ -314,6 +319,8 @@ window.player = {
bestEternitiesPerMs: DC.D0,
maxReplicanti: DC.D0,
maxDT: DC.D0,
bestRSmin: 0,
bestRSminVal: 0,
},
bestReality: {
time: Number.MAX_VALUE,
@ -521,7 +528,7 @@ window.player = {
},
constants: {},
execTimer: 0,
type: AUTOMATOR_TYPE.BLOCK,
type: AUTOMATOR_TYPE.TEXT,
forceUnlock: false,
currentInfoPane: AutomatorPanels.INTRO_PAGE,
},
@ -791,8 +798,8 @@ window.player = {
offlineProgress: true,
automaticTabSwitching: true,
respecIntoProtected: false,
offlineTicks: 1000,
showLastTenResourceGain: true,
offlineTicks: 1e5,
showRecentRate: true,
autosaveInterval: 30000,
showTimeSinceSave: true,
saveFileName: "",
@ -888,7 +895,8 @@ window.player = {
maxEntries: 200,
clearOnReality: true,
clearOnRestart: true,
}
},
invertTTgenDisplay: false,
},
IAP: {
enabled: false,

View File

@ -340,6 +340,30 @@ export function beginProcessReality(realityProps) {
// Do this before processing glyphs so that we don't try to reality again while async is running.
finishProcessReality(realityProps);
// If we have less than a certain amount of simulated realities, then we just shortcut the heavier async and
// sampling code in order to just directly give all the glyphs. The later code is a fixed amount of overhead
// which is large enough that quick realities can cause it to softlock the game due to lag on slower devices
// Note: This is mostly a copy-paste of a code block in processManualReality() with slight modifications
if (glyphsToProcess < 100) {
for (let glyphNum = 0; glyphNum < glyphsToProcess; glyphNum++) {
if (EffarigUnlock.glyphFilter.isUnlocked) {
const glyphChoices = GlyphSelection.glyphList(GlyphSelection.choiceCount,
realityProps.gainedGlyphLevel, { rng });
const newGlyph = AutoGlyphProcessor.pick(glyphChoices);
if (!AutoGlyphProcessor.wouldKeep(newGlyph) || GameCache.glyphInventorySpace.value === 0) {
AutoGlyphProcessor.getRidOfGlyph(newGlyph);
} else {
Glyphs.addToInventory(newGlyph);
}
} else {
GlyphSelection.select(Math.floor(Math.random() * GlyphSelection.choiceCount), false);
}
}
rng.finalize();
Glyphs.processSortingAfterReality();
return;
}
// We need these variables in this scope in order to modify the behavior of the Async loop while it's running
const progress = {};
let fastToggle = false;
@ -409,7 +433,7 @@ export function beginProcessReality(realityProps) {
if (VUnlocks.autoAutoClean.canBeApplied && player.reality.autoAutoClean) Glyphs.autoClean();
}
};
const glyphsToSample = 10000;
const glyphsToSample = Math.min(glyphsToProcess, 10000);
Async.run(glyphFunction,
glyphsToProcess,
{

View File

@ -765,8 +765,8 @@ GameDatabase.achievements.normal = [
${format(Decimal.NUMBER_MAX_VALUE, 1, 0)} times higher Infinity Points than the previous one.`;
},
checkRequirement: () => {
if (player.records.lastTenInfinities.some(i => i[0] === Number.MAX_VALUE)) return false;
const infinities = player.records.lastTenInfinities.map(run => run[1]);
if (player.records.recentInfinities.some(i => i[0] === Number.MAX_VALUE)) return false;
const infinities = player.records.recentInfinities.map(run => run[2]);
for (let i = 0; i < infinities.length - 1; i++) {
if (infinities[i].lt(infinities[i + 1].times(Decimal.NUMBER_MAX_VALUE))) return false;
}
@ -933,8 +933,8 @@ GameDatabase.achievements.normal = [
id: 132,
name: "Unique snowflakes",
get description() {
return `Have ${formatInt(569)} Antimatter Galaxies without getting any
Replicanti Galaxies in your current Eternity.`;
return `Have ${formatInt(569)} Antimatter Galaxies without gaining any
Replicanti Galaxies in your current Eternity.`;
},
checkRequirement: () => player.galaxies >= 569 && player.requirementChecks.eternity.noRG,
checkEvent: GAME_EVENT.GALAXY_RESET_AFTER,
@ -1041,8 +1041,8 @@ GameDatabase.achievements.normal = [
${format(Decimal.NUMBER_MAX_VALUE, 1, 0)} times higher Eternity Points than the previous one.`;
},
checkRequirement: () => {
if (player.records.lastTenEternities.some(i => i[0] === Number.MAX_VALUE)) return false;
const eternities = player.records.lastTenEternities.map(run => run[1]);
if (player.records.recentEternities.some(i => i[0] === Number.MAX_VALUE)) return false;
const eternities = player.records.recentEternities.map(run => run[2]);
for (let i = 0; i < eternities.length - 1; i++) {
if (eternities[i].lt(eternities[i + 1].times(Decimal.NUMBER_MAX_VALUE))) return false;
}

View File

@ -115,7 +115,7 @@ GameDatabase.achievements.secret = [
checkRequirement: () =>
Time.bestInfinity.totalMilliseconds <= 1 ||
Time.bestEternity.totalMilliseconds <= 1,
checkEvent: [GAME_EVENT.BIG_CRUNCH_BEFORE, GAME_EVENT.ETERNITY_RESET_BEFORE]
checkEvent: [GAME_EVENT.BIG_CRUNCH_AFTER, GAME_EVENT.ETERNITY_RESET_AFTER]
},
{
id: 33,

View File

@ -97,6 +97,7 @@ GameDatabase.awayProgressTypes = [
showOption: false,
}, {
name: "enslavedMemories",
forcedName: "Nameless Memories",
awayOption: "celestialMemories",
reference: ["celestials", "ra", "pets", "enslaved", "memories"],
isUnlocked: () => Ra.pets.enslaved.isUnlocked && !Ra.pets.enslaved.isCapped,

View File

@ -140,7 +140,7 @@ function pelleRiftFill(name, index, textAngle, fillType) {
visibleCheck = () => riftFillStage(name) === FILL_STATE.FILL;
progressFn = () => Math.clamp(0.1 + PelleRifts[name.toLowerCase()].realPercentage / 0.9, 1e-6, 1);
legendFn = () => false;
percentFn = x => (x - 0.1) / 0.9;
percentFn = () => PelleRifts[name.toLowerCase()].realPercentage;
incompleteClass = "c-celestial-nav__test-incomplete";
nodeFill = "crimson";
connectorFill = "crimson";
@ -153,7 +153,7 @@ function pelleRiftFill(name, index, textAngle, fillType) {
visibleCheck = () => riftFillStage(name) >= FILL_STATE.DRAIN;
progressFn = () => Math.clamp(Math.sqrt(PelleRifts[name.toLowerCase()].reducedTo), 1e-6, 1);
legendFn = () => riftFillStage(name) === FILL_STATE.DRAIN && PelleRifts[name.toLowerCase()].reducedTo < 1;
percentFn = x => x;
percentFn = () => PelleRifts[name.toLowerCase()].reducedTo;
incompleteClass = "c-celestial-nav__drained-rift";
nodeFill = "crimson";
connectorFill = "#550919";
@ -161,7 +161,7 @@ function pelleRiftFill(name, index, textAngle, fillType) {
case FILL_STATE.OVERFILL:
visibleCheck = () => riftFillStage(name) === FILL_STATE.OVERFILL;
progressFn = () => Math.clamp(PelleRifts[name.toLowerCase()].percentage - 1, 1e-6, 1);
percentFn = x => x + 1;
percentFn = () => PelleRifts[name.toLowerCase()].percentage;
legendFn = () => true;
incompleteClass = undefined;
nodeFill = "#ff7700";
@ -182,8 +182,8 @@ function pelleRiftFill(name, index, textAngle, fillType) {
},
forceLegend: () => legendFn(),
legend: {
text: complete => [
`${formatPercents(percentFn(complete), 1)} ${wordShift.wordCycle(PelleRifts[name.toLowerCase()].name)}`
text: () => [
`${formatPercents(percentFn(), 1)} ${wordShift.wordCycle(PelleRifts[name.toLowerCase()].name)}`
],
angle: textAngle,
diagonal: 30,
@ -586,7 +586,7 @@ GameDatabase.celestials.navigation = {
},
legend: {
text: complete => {
if (complete >= 1) return "Broken the chain with Glyph level";
if (complete >= 1) return "Glyph level chain has been broken";
const goal = 5000;
return [
"Break a chain",
@ -631,7 +631,7 @@ GameDatabase.celestials.navigation = {
},
legend: {
text: complete => {
if (complete >= 1) return "Broken the chain with Glyph rarity";
if (complete >= 1) return "Glyph rarity chain has been broken";
const goal = 100;
return [
"Break a chain",
@ -1527,8 +1527,8 @@ GameDatabase.celestials.navigation = {
if (upgrade.isAvailableForPurchase) return [
dmdText,
`Imaginary Machines
${format(Math.min(upgrade.currency.value, upgrade.cost), upgrade.canBeBought ? 0 : 2)}
/ ${format(upgrade.cost)}`
${format(Math.min(upgrade.currency.value, upgrade.cost), upgrade.canBeBought ? 1 : 2)}
/ ${format(upgrade.cost, 1)}`
];
if (player.celestials.laitela.fastestCompletion > 30 && Laitela.difficultyTier < 0) return [

View File

@ -174,7 +174,7 @@ GameDatabase.celestials.pelle.rifts = {
{
resource: "recursion",
requirement: 1,
description: "Unlock the Galaxy Generator",
description: "Permanently unlock the Galaxy Generator",
},
],
galaxyGeneratorText: "Creating more Galaxies is unsustainable, you must focus the $value to allow more"

View File

@ -37,7 +37,7 @@ GameDatabase.celestials.pelle.strikes = {
id: 5,
requirementDescription: "Dilate Time",
penaltyDescription: "Time Dilation is permanently active",
rewardDescription: () => `Keep access to Time Dilation upgrades across Armageddon and unlock
rewardDescription: () => `Keep the Time Dilation study across Armageddon, boost Remnant gain, and unlock
${wordShift.wordCycle(PelleRifts.paradox.name)}`,
rift: () => PelleRifts.paradox
}

View File

@ -230,7 +230,7 @@ GameDatabase.celestials.v = {
},
autoAutoClean: {
id: 4,
reward: "Unlock the ability to Automatically Purge on Reality.",
reward: "Unlock the ability to Automatically Purge Glyphs on Reality.",
description: () => `Have ${formatInt(16)} V-Achievements`,
requirement: () => V.spaceTheorems >= 16
},

View File

@ -63,8 +63,8 @@ GameDatabase.challenges.infinity = [
{
id: 5,
description:
`buying Antimatter Dimensions 1-4 causes all smaller Antimatter Dimension costs to increase.
Buying Antimatter Dimensions 5-8 causes all larger Antimatter Dimension costs to increase.`,
`buying Antimatter Dimensions 1-4 causes all cheaper AD costs to increase.
Buying Antimatter Dimensions 5-8 causes all more expensive AD costs to increase.`,
goal: DC.E16500,
isQuickResettable: true,
reward: {
@ -104,7 +104,7 @@ GameDatabase.challenges.infinity = [
TimeStudy(81)
);
return `you cannot buy Antimatter Galaxies. Base Dimension Boost multiplier is increased to a maximum
of ${formatX(10)}. (Current base multiplier: ${formatX(mult)})`;
of ${formatX(10)}. (Current base multiplier: ${formatX(mult, 2, 1)})`;
},
goal: DC.E10000,
isQuickResettable: false,

View File

@ -128,8 +128,8 @@ GameDatabase.challenges.normal = [
legacyId: 7,
isQuickResettable: false,
description: () => `each Antimatter Dimension produces the Dimension ${formatInt(2)} tiers below it
instead of ${formatInt(1)}. The 1st Dimension still produces antimatter, and the 2nd, 4th, and 6th
Dimensions are made stronger to compensate.`,
instead of ${formatInt(1)}. Both 1st and 2nd Dimensions produce antimatter.
The 2nd, 4th, and 6th Dimensions are made stronger to compensate.`,
name: "Automated Big Crunches",
reward: "Big Crunches Autobuyer",
lockedAt: DC.D16,

View File

@ -229,6 +229,9 @@ GameDatabase.credits = {
}, {
name: "Anthios",
roles: 13
}, {
name: "Aubrey",
roles: 13
}, {
name: "Auti",
name2: "Lucia Tolle",
@ -321,9 +324,6 @@ GameDatabase.credits = {
}, {
name: "Pavlxiiv",
roles: 13
}, {
name: "Porygon-Z",
roles: 13
}, {
name: "PotatoTIAB",
roles: 13

View File

@ -59,7 +59,7 @@ GameDatabase.eternity.upgrades = {
? "Time Dimensions are multiplied by days played in this Armageddon"
: "Time Dimensions are multiplied by days played"
),
effect: () => (Pelle.isDoomed ? 1 + Time.thisReality.totalDays : Time.totalTimePlayed.totalDays),
effect: () => (Pelle.isDoomed ? 1 + Time.thisReality.totalDays : Math.max(Time.totalTimePlayed.totalDays, 1)),
formatEffect: value => formatX(value, 2, 1)
}
};

View File

@ -55,8 +55,16 @@ GameDatabase.eternity.timeStudies.normal = [
requirement: [11],
reqType: TS_REQUIREMENT_TYPE.AT_LEAST_ONE,
description: () => `Improve Replicanti multiplier formula to
(log2(x)${formatPow(2)})+x${formatPow(0.032, 3, 3)}`,
effect: () => Replicanti.amount.pow(0.032)
(log2(x)${formatPow(2)})+x${formatPow(0.032, 3, 3)}`,
effect: () => Replicanti.amount.pow(0.032),
// This is a special case because the study itself is *added* to the existing formula, but it makes more sense
// to display a multiplicative increase just like every other study. We need to do the calculation in here in order
// to properly show only the effect of this study and nothing else
formatEffect: value => {
const oldVal = Decimal.pow(Decimal.log2(Replicanti.amount.clampMin(1)), 2);
const newVal = oldVal.plus(value);
return formatX(newVal.div(oldVal).clampMin(1), 2, 2);
}
},
{
id: 22,
@ -81,7 +89,7 @@ GameDatabase.eternity.timeStudies.normal = [
reqType: TS_REQUIREMENT_TYPE.AT_LEAST_ONE,
description: `You gain more Infinities based on Dimension Boosts`,
effect: () => Math.max(DimBoost.totalBoosts, 1),
formatEffect: value => formatX(value)
formatEffect: value => formatX(value, 2)
},
{
id: 33,

View File

@ -223,8 +223,8 @@ ${Laitela.isUnlocked ? "- <b>DE</b>: Dark Energy<br>" : ""}
}, {
name: "Antimatter Dimensions",
info: () => `
Antimatter is a resource that is throughout the entire game for purchasing various things as you progress. You start
with ${formatInt(10)} antimatter when you first open the game. And you can
Antimatter is a resource that is used throughout the entire game for purchasing various things as you progress. You
start with ${formatInt(10)} antimatter when you first open the game, and you can
spend it to buy the 1st Antimatter Dimension to start the game.
<br>
<br>
@ -337,7 +337,7 @@ available, but will increase the effect of your Tickspeed Upgrades by +${format(
Galaxies. As you get more Galaxies, the multiplier will continue becoming stronger and stronger.
<br>
<br>
Though it will have very little impact for the first few purchases,
Though it will have very little impact for the first few Tickspeed purchases,
the increase is multiplicative and won't take long to be visible.
<br>
<br>
@ -1142,6 +1142,10 @@ Unlocking or defeating a Celestial has different conditions depending on the Cel
<br>
All Celestials have their own Celestial Reality, but how the Reality is relevant to each Celestial and the rest of
the game will depend on the Celestial.
<br>
<br>
Celestials are timeless entities. Unless otherwise stated, any new mechanics introduced by Celestials are not affected
by game speed multipliers and instead refer specifically to real time instead of game time.
`,
isUnlocked: () => Teresa.isUnlocked,
tags: ["reality", "challenges", "endgame", "lategame"],

View File

@ -165,11 +165,8 @@ GameDatabase.infinity.upgrades = {
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}`;
if (player.records.bestInfinity.time >= 999999999999) return "Too slow to generate";
return `${format(value, 2)} every ${Time.bestInfinity.times(10).toStringShort()}`;
},
charged: {
description: () =>

View File

@ -223,7 +223,9 @@ GameDatabase.news = [
},
{
id: "a49",
text: "Can we get 1e169 likes on this video??? Smash that like button!!"
get text() {
return `Can we get ${format(1e169)} likes on this video??? Smash that like button!!`;
}
},
{
id: "a50",
@ -317,7 +319,7 @@ GameDatabase.news = [
},
{
id: "a70",
text: "If you can't read this you disabled the news."
text: "If you can't read this, you disabled the news."
},
{
id: "a71",
@ -511,7 +513,8 @@ GameDatabase.news = [
id: "a103",
text:
`Antimatter... antimatter never changes... until you get to quantum physics of antimatter,
but we don't have enough tachyon particles for that.`
but we don't have enough tachyon particles for that.`,
get unlocked() { return PlayerProgress.realityUnlocked() || PlayerProgress.dilationUnlocked(); }
},
{
id: "a104",
@ -601,7 +604,8 @@ GameDatabase.news = [
Sacrifice' is moving away. You have to give up a lot of the things you had that made you happy, but there is
new opportunity in where you move to. And that new opportunity gives you more happiness than you ever had.
'Tickspeed' is how easy it is to make you happy, and 'Time Dimensions' make it even easier to be happy.
Antimatter Dimensions is a metaphor for a depressed man's successful battle against his illness.`
Antimatter Dimensions is a metaphor for a depressed man's successful battle against his illness.`,
get unlocked() { return PlayerProgress.eternityUnlocked(); }
},
{
id: "a114",
@ -719,7 +723,8 @@ GameDatabase.news = [
},
{
id: "a134",
text: "Because of this game I can now use the word \"infinity\" as a verb."
text: "Because of this game I can now use the word \"infinity\" as a verb.",
get unlocked() { return PlayerProgress.infinityUnlocked(); }
},
{
id: "a135",
@ -845,7 +850,8 @@ GameDatabase.news = [
id: "a159",
text:
`What does it mean when you "bank" Infinities? Is there a bank somewhere that you just deposit these
infinities? Does having a lot of banked Infinities improve your credit score? Do you get a credit card?`
infinities? Does having a lot of banked Infinities improve your credit score? Do you get a credit card?`,
get unlocked() { return PlayerProgress.eternityUnlocked(); }
},
{
id: "a160",
@ -1281,7 +1287,8 @@ GameDatabase.news = [
},
{
id: "a223",
text: "If you find your infinity lasting longer than 5 hours please contact a medical professional."
text: "If you find your infinity lasting longer than 5 hours please contact a medical professional.",
get unlocked() { return PlayerProgress.infinityUnlocked(); }
},
{
id: "a224",
@ -1436,6 +1443,9 @@ GameDatabase.news = [
${BLOB} are just blobbling and bouncing around, occasionally merging and dividing. Only ${BLOB} know where
they are from or where they are going to go. Still, ${BLOB} are there, always with me.
You love ${BLOB}, so ${BLOB} loves you too.`,
S12:
`it makes you feel warm and comfortable, as if you were right at home. However, it is highly recommended
to update your theme to the newest theme for the best user experience.`,
};
const reason = reasons[Theme.current().name.replace(/\s/gu, "")];
return `Ah, a fellow ${theme} theme user. I see that you have impeccable taste.
@ -1511,6 +1521,7 @@ GameDatabase.news = [
get text() {
return `<span style='animation: a-text-stretch ${newsAnimSpd(35)}s 1 forwards'>This message is dilated.</span>`;
},
get unlocked() { return PlayerProgress.realityUnlocked() || PlayerProgress.dilationUnlocked(); }
},
{
id: "a253",
@ -1574,7 +1585,8 @@ GameDatabase.news = [
id: "a260",
text:
`It seems that the Replicanti have a very divide-and-conquer method of doing things.
Well, everything at this rate.`
Well, everything at this rate.`,
get unlocked() { return PlayerProgress.eternityUnlocked() || PlayerProgress.replicantiUnlocked(); }
},
{
id: "a261",
@ -2283,8 +2295,8 @@ GameDatabase.news = [
}
};
}()),
// Blob from the blob font
{
// Blob from the blob font
id: "a354",
text:
`<span style='color: #FBC21B; text-shadow: 0px 1px 0px black, 1px 0px 0px black, 1px 1px 0px black,
@ -2320,13 +2332,13 @@ GameDatabase.news = [
id: "a360",
text: `Press "Choose save" to explore the other 2 parallel universes.`
},
// Discord contest winner #1
{
// Discord contest winner #1
id: "a361",
text: "We're having a sale of top quality waterproof towels! Be sure to get some on your way out!"
},
// Discord contest winner #2
{
// Discord contest winner #2
id: "a362",
text:
`Hevipelle Incorporated is proud to present a new brand of cereal: The Big Crunch! This nutritious breakfast
@ -2334,7 +2346,8 @@ GameDatabase.news = [
Replicanti, and Eternity-flavored Marshmallows. Now you can experience Antimatter Dimensions inside of your
stomach! Warning: Side effects may include spontaneous combustion, nausea, vomiting, diarrhea,
dematerialization, vaporization, heart failure, the end of the world, or death. If you are not made out of
antimatter, consult an educated professional on Antimatter Consumption before eating 'The Big Crunch'.`
antimatter, consult an educated professional on Antimatter Consumption before eating 'The Big Crunch'.`,
get unlocked() { return PlayerProgress.eternityUnlocked(); }
},
{
id: "a363",
@ -2372,7 +2385,8 @@ GameDatabase.news = [
},
{
id: "a365",
text: "I don't like Replicanti. They're coarse and rough and irritating and they replicate everywhere."
text: "I don't like Replicanti. They're coarse and rough and irritating and they replicate everywhere.",
get unlocked() { return PlayerProgress.eternityUnlocked() || PlayerProgress.replicantiUnlocked(); }
},
{
id: "a366",
@ -2457,8 +2471,8 @@ GameDatabase.news = [
{
id: "a372",
text:
`If youre ever lost in a forest, look at the trees around you. Its said that moss grows north, so by the
time youve finished looking at a tree, a roaming guitarist will run up to you and ask if you want to hear
`If you're ever lost in a forest, look at the trees around you. It's said that moss grows north, so by the
time you've finished looking at a tree, a roaming guitarist will run up to you and ask if you want to hear
wonderwall`
},
{
@ -2500,7 +2514,7 @@ GameDatabase.news = [
has been revealed. The first codename, as it currently stands, is antimatter. This conveniently works well
with the predicted generation of phones that will use Android 20 - these phones will be the most explosive
ever due to their annihilation-based power source. Sources tell us that a billion dollar research unit is
working on a name for android 21, by tradition to start with B, that doesnt sound too bad when you think
working on a name for android 21, by tradition to start with B, that doesn't sound too bad when you think
about it. `
},
{

View File

@ -146,6 +146,7 @@ GameDatabase.reality.imaginaryUpgrades = [
name: "Recollection of Intrusion",
id: 14,
cost: 3.5e8,
formatCost: x => format(x, 1),
requirement: () => `Reach a tickspeed of ${format("1e75000000000")} / sec within Eternity Challenge 5`,
hasFailed: () => false,
checkRequirement: () => EternityChallenge(5).isRunning && Tickspeed.perSecond.exponent >= 7.5e10,

View File

@ -143,14 +143,14 @@ GameDatabase.reality.perks = {
},
autounlockDilation1: {
id: 42,
label: "UD1",
label: "DU1",
family: PERK_FAMILY.DILATION,
description: "After unlocking Dilation, automatically unlock the second row of Dilation Upgrades for free.",
defaultPosition: new Vector(165, 565)
},
autounlockDilation2: {
id: 43,
label: "UD2",
label: "DU2",
family: PERK_FAMILY.DILATION,
description: "After unlocking Dilation, automatically unlock the third row of Dilation Upgrades for free.",
defaultPosition: new Vector(310, 605)
@ -482,8 +482,10 @@ GameDatabase.reality.perks = {
id: 205,
label: "ACHNR",
family: PERK_FAMILY.ACHIEVEMENT,
description: "Reality no longer resets your Achievements.",
effect: 2,
get description() {
return `Immediately unlock the first ${formatInt(13)} rows of Achievements
and Reality no longer resets them.`;
},
automatorPoints: 10,
shortDescription: () => "Keep Achievements on Reality",
defaultPosition: new Vector(-195, -630)

View File

@ -311,7 +311,8 @@ GameDatabase.reality.upgrades = [
name: "Replicative Rapidity",
id: 23,
cost: 100000,
requirement: () => `Reality in under ${formatInt(15)} minutes (Best: ${Time.bestReality.toStringShort()})`,
requirement: () => `Reality in under ${formatInt(15)} minutes of game time
(Fastest: ${Time.bestReality.toStringShort()})`,
hasFailed: () => Time.thisReality.totalMinutes >= 15,
checkRequirement: () => Time.thisReality.totalMinutes < 15,
checkEvent: GAME_EVENT.REALITY_RESET_BEFORE,

View File

@ -6,7 +6,8 @@ GameDatabase.shopPurchases = {
key: "dimPurchases",
cost: 30,
description: "Double all your Antimatter Dimension multipliers. Forever.",
multiplier: purchases => Math.pow(2, purchases)
multiplier: purchases => Math.pow(2, purchases),
formatEffect: x => `×${Notation.scientific.formatDecimal(new Decimal(x))}`,
},
allDimPurchases: {
key: "allDimPurchases",
@ -18,12 +19,14 @@ GameDatabase.shopPurchases = {
return `Double ALL Dimension multipliers (${makeEnumeration(dims)}; multiplicative until 32x). Forever.`;
},
multiplier: purchases => (purchases > 4 ? 32 + (purchases - 5) * 2 : Math.pow(2, purchases)),
formatEffect: x => `×${x.toFixed(0)}`,
},
IPPurchases: {
key: "IPPurchases",
cost: 40,
description: "Double your Infinity Point gain from all sources. (additive)",
multiplier: purchases => (purchases === 0 ? 1 : 2 * purchases),
formatEffect: x => `×${x.toFixed(0)}`,
isUnlocked: () => PlayerProgress.infinityUnlocked(),
lockText: "Infinity",
},
@ -32,7 +35,7 @@ GameDatabase.shopPurchases = {
cost: 60,
description: "Increase your Replicanti gain by 50%. (additive)",
multiplier: purchases => (purchases === 0 ? 1 : 1 + 0.5 * purchases),
formatEffect: x => formatX(x, 2, 1),
formatEffect: x => `×${x.toFixed(1)}`,
isUnlocked: () => Replicanti.areUnlocked || PlayerProgress.eternityUnlocked(),
lockText: "Replicanti",
},
@ -41,6 +44,7 @@ GameDatabase.shopPurchases = {
cost: 50,
description: "Triple your Eternity Point gain from all sources. (additive)",
multiplier: purchases => (purchases === 0 ? 1 : 3 * purchases),
formatEffect: x => `×${x.toFixed(0)}`,
isUnlocked: () => PlayerProgress.eternityUnlocked(),
lockText: "Eternity",
},
@ -49,7 +53,7 @@ GameDatabase.shopPurchases = {
cost: 40,
description: "Increase your Dilated Time gain by 50%. (additive)",
multiplier: purchases => (purchases === 0 ? 1 : 1 + 0.5 * purchases),
formatEffect: x => formatX(x, 2, 1),
formatEffect: x => `×${x.toFixed(1)}`,
isUnlocked: () => PlayerProgress.dilationUnlocked() || PlayerProgress.realityUnlocked(),
lockText: "Dilation",
},
@ -58,7 +62,7 @@ GameDatabase.shopPurchases = {
cost: 60,
description: "Increase your Reality Machine gain by 100%. (additive)",
multiplier: purchases => purchases + 1,
formatEffect: x => formatX(x, 2),
formatEffect: x => `×${x.toFixed(0)}`,
isUnlocked: () => PlayerProgress.realityUnlocked(),
lockText: "Reality",
},

View File

@ -124,11 +124,14 @@ class ShopPurchaseState extends RebuyableMechanicState {
return typeof cost === "function" ? cost() : cost;
}
// ShopPurchaseData for any particular key is undefined in between page load and STD load,
// so we need to guard against that causing NaNs to propagate through the save
get purchases() {
return ShopPurchaseData[this.config.key];
return ShopPurchaseData[this.config.key] ?? 0;
}
set purchases(value) {
if (!Number.isFinite(value)) return;
ShopPurchaseData[this.config.key] = value;
}

View File

@ -160,11 +160,69 @@ GameStorage.migrations = {
},
14: player => {
GameStorage.migrations.reworkBHPulsing(player);
// Added glyph auto-sort by level; in order to keep the button state cycling consistent with the sort buttons' UI
// order, AUTO_SORT_MODE had to be changed to insert LEVEL mode at the top and shift the others down. This
// makes sure that older saves maintain the same settings after this shift
if (player.reality.autoSort !== 0) player.reality.autoSort++;
},
15: player => {
// Added glyph auto-sort by level; in order to keep the button state cycling consistent with the sort buttons' UI
// order, AUTO_SORT_MODE had to be changed to insert LEVEL mode at the top and shift the others down
if (player.reality.autoSort !== 0) player.reality.autoSort++;
// Added additional resource tracking in last 10 prestige records and adjusted data format to be more consistent
// by reordering to be [game time, real time, prestige currency, prestige count, challenge, ...(other resources)]
// Also fixes a migration bug where values could be undefined or null by assigning defaults when necessary
for (let i = 0; i < 10; i++) {
if (player.records.lastTenInfinities) {
const infRec = player.records.lastTenInfinities[i];
player.records.recentInfinities[i] = [
infRec[0] ?? Number.MAX_VALUE,
Number(infRec[3] ?? Number.MAX_VALUE),
new Decimal(infRec[1] ?? 1),
new Decimal(infRec[2] ?? 1),
""
];
}
if (player.records.lastTenEternities) {
const eterRec = player.records.lastTenEternities[i];
player.records.recentEternities[i] = [
eterRec[0] ?? Number.MAX_VALUE,
Number(eterRec[3] ?? Number.MAX_VALUE),
new Decimal(eterRec[1] ?? 1),
new Decimal(eterRec[2] ?? 1),
"",
new Decimal(0)
];
}
if (player.records.lastTenRealities) {
const realRec = player.records.lastTenRealities[i];
player.records.recentRealities[i] = [
realRec[0] ?? Number.MAX_VALUE,
Number(realRec[3] ?? Number.MAX_VALUE),
new Decimal(realRec[1] ?? 1),
realRec[2] ?? 1,
"",
0,
0
];
}
}
delete player.records.lastTenInfinities;
delete player.records.lastTenEternities;
delete player.records.lastTenRealities;
delete player.options.showLastTenResourceGain;
// Fixes a desync which occasionally causes unique > total seen due to total not being updated properly
if (player.news.seen) {
let unique = 0;
for (const bitmaskArray of Object.values(player.news.seen)) {
for (const bitmask of bitmaskArray) {
unique += countValuesFromBitmask(bitmask);
}
}
player.news.totalSeen = Math.max(player.news.totalSeen, unique);
}
}
},

View File

@ -71,6 +71,16 @@ function findLastOpenSubtab(tabId, subtabs) {
return subtabs.find(s => s.id === player.options.lastOpenSubtab[tabId]) ?? subtabs[0];
}
function cycleThroughSubtabs(subtabs, currentSubtab) {
const availableTabs = subtabs.filter(tab => tab.isAvailable);
const currentIndex = availableTabs.indexOf(currentSubtab);
const direction = ui.view.shiftDown ? -1 : 1;
let newIndex = currentIndex + direction;
newIndex = newIndex < 0 ? availableTabs.length - 1 : newIndex;
newIndex = newIndex > availableTabs.length - 1 ? 0 : newIndex;
return availableTabs[newIndex];
}
class TabState {
constructor(config) {
this.config = config;
@ -129,17 +139,19 @@ class TabState {
show(manual, subtab = undefined) {
if (!manual && !player.options.automaticTabSwitching || Quote.isOpen) return;
ui.view.tab = this.key;
if (subtab === undefined) {
this._currentSubtab = findLastOpenSubtab(this.id, this.subtabs);
} else {
if (subtab !== undefined) {
if (!Enslaved.isRunning) subtab.unhideTab();
this._currentSubtab = subtab;
} else if (ui.view.tab === this.key && ui.view.initialized) {
this._currentSubtab = cycleThroughSubtabs(this.subtabs, this._currentSubtab);
} else {
this._currentSubtab = findLastOpenSubtab(this.id, this.subtabs);
}
if (!this._currentSubtab.isUnlocked) this.resetToUnlocked();
if (!this._currentSubtab.isAvailable) this.resetToAvailable();
ui.view.tab = this.key;
ui.view.subtab = this._currentSubtab.key;
const tabNotificationKey = this.key + this._currentSubtab.key;
if (player.tabNotifications.has(tabNotificationKey)) player.tabNotifications.delete(tabNotificationKey);

View File

@ -179,42 +179,20 @@ export function ratePerMinute(amount, time) {
return Decimal.divide(amount, time / (60 * 1000));
}
export function averageRun(allRuns, name) {
// Filter out all runs which have the default infinite value for time, but if we're left with no valid runs then we
// take just one entry so that the averages also have the same value and we don't get division by zero.
let runs = allRuns.filter(run => run[0] !== Number.MAX_VALUE);
if (runs.length === 0) runs = [allRuns[0]];
const totalTime = runs.map(run => run[0]).sum();
const totalAmount = runs
.map(run => run[1])
.reduce(Decimal.sumReducer);
const totalPrestigeGain = runs
.map(run => run[2])
.reduce(name === "Reality" ? Number.sumReducer : Decimal.sumReducer);
const realTime = runs.map(run => run[3]).sum();
const average = [
totalTime / runs.length,
totalAmount.dividedBy(runs.length),
(name === "Reality") ? totalPrestigeGain / runs.length : totalPrestigeGain.dividedBy(runs.length),
realTime / runs.length
];
if (name === "Reality") {
average.push(runs.map(x => x[4]).sum() / runs.length);
}
return average;
}
// eslint-disable-next-line max-params
export function addInfinityTime(time, realTime, ip, infinities) {
player.records.lastTenInfinities.pop();
player.records.lastTenInfinities.unshift([time, ip, infinities, realTime]);
let challenge = "";
if (player.challenge.normal.current) challenge = `Normal Challenge ${player.challenge.normal.current}`;
if (player.challenge.infinity.current) challenge = `Infinity Challenge ${player.challenge.infinity.current}`;
player.records.recentInfinities.pop();
player.records.recentInfinities.unshift([time, realTime, ip, infinities, challenge]);
GameCache.bestRunIPPM.invalidate();
}
export function resetInfinityRuns() {
player.records.lastTenInfinities = Array.from(
player.records.recentInfinities = Array.from(
{ length: 10 },
() => [Number.MAX_VALUE, DC.D1, DC.D1, Number.MAX_VALUE]
() => [Number.MAX_VALUE, Number.MAX_VALUE, DC.D1, DC.D1, ""]
);
GameCache.bestRunIPPM.invalidate();
}
@ -229,15 +207,24 @@ export function getInfinitiedMilestoneReward(ms, considerMilestoneReached) {
// eslint-disable-next-line max-params
export function addEternityTime(time, realTime, ep, eternities) {
player.records.lastTenEternities.pop();
player.records.lastTenEternities.unshift([time, ep, eternities, realTime]);
let challenge = "";
if (player.challenge.eternity.current) {
const currEC = player.challenge.eternity.current;
const ec = EternityChallenge(currEC);
const challText = player.dilation.active ? "Dilated EC" : "Eternity Challenge";
challenge = `${challText} ${currEC} (${formatInt(ec.completions)}/${formatInt(ec.maxCompletions)})`;
} else if (player.dilation.active) challenge = "Time Dilation";
// If we call this function outside of dilation, it uses the existing AM and produces an erroneous number
const gainedTP = player.dilation.active ? getTachyonGain() : DC.D0;
player.records.recentEternities.pop();
player.records.recentEternities.unshift([time, realTime, ep, eternities, challenge, gainedTP]);
GameCache.averageRealTimePerEternity.invalidate();
}
export function resetEternityRuns() {
player.records.lastTenEternities = Array.from(
player.records.recentEternities = Array.from(
{ length: 10 },
() => [Number.MAX_VALUE, DC.D1, DC.D1, Number.MAX_VALUE]
() => [Number.MAX_VALUE, Number.MAX_VALUE, DC.D1, DC.D1, "", DC.D0]
);
GameCache.averageRealTimePerEternity.invalidate();
}
@ -262,8 +249,14 @@ export function getOfflineEPGain(ms) {
// eslint-disable-next-line max-params
export function addRealityTime(time, realTime, rm, level, realities) {
player.records.lastTenRealities.pop();
player.records.lastTenRealities.unshift([time, rm, realities, realTime, level]);
let reality = "";
const celestials = [Teresa, Effarig, Enslaved, V, Ra, Laitela];
for (const cel of celestials) {
if (cel.isRunning) reality = cel.displayName;
}
const shards = Effarig.shardsGained;
player.records.recentRealities.pop();
player.records.recentRealities.unshift([time, realTime, rm, realities, reality, level, shards]);
}
export function gainedInfinities() {
@ -547,21 +540,13 @@ export function gameLoop(passDiff, options = {}) {
const gain = Math.clampMin(FreeTickspeed.fromShards(Currency.timeShards.value).newAmount - player.totalTickGained, 0);
player.totalTickGained += gain;
const currentIPmin = gainedInfinityPoints().dividedBy(Math.clampMin(0.0005, Time.thisInfinityRealTime.totalMinutes));
if (currentIPmin.gt(player.records.thisInfinity.bestIPmin) && Player.canCrunch)
player.records.thisInfinity.bestIPmin = currentIPmin;
updatePrestigeRates();
tryCompleteInfinityChallenges();
EternityChallenges.autoComplete.tick();
replicantiLoop(diff);
const currentEPmin = gainedEternityPoints().dividedBy(Math.clampMin(0.0005, Time.thisEternityRealTime.totalMinutes));
if (currentEPmin.gt(player.records.thisEternity.bestEPmin) && Player.canEternity)
player.records.thisEternity.bestEPmin = currentEPmin;
if (PlayerProgress.dilationUnlocked()) {
Currency.dilatedTime.add(getDilationGainPerSecond().times(diff / 1000));
}
@ -631,6 +616,26 @@ export function gameLoop(passDiff, options = {}) {
PerformanceStats.end("Game Update");
}
function updatePrestigeRates() {
const currentIPmin = gainedInfinityPoints().dividedBy(Math.clampMin(0.0005, Time.thisInfinityRealTime.totalMinutes));
if (currentIPmin.gt(player.records.thisInfinity.bestIPmin) && Player.canCrunch) {
player.records.thisInfinity.bestIPmin = currentIPmin;
player.records.thisInfinity.bestIPminVal = gainedInfinityPoints();
}
const currentEPmin = gainedEternityPoints().dividedBy(Math.clampMin(0.0005, Time.thisEternityRealTime.totalMinutes));
if (currentEPmin.gt(player.records.thisEternity.bestEPmin) && Player.canEternity) {
player.records.thisEternity.bestEPmin = currentEPmin;
player.records.thisEternity.bestEPminVal = gainedEternityPoints();
}
const currentRSmin = Effarig.shardsGained / Math.clampMin(0.0005, Time.thisRealityRealTime.totalMinutes);
if (currentRSmin > player.records.thisReality.bestRSmin && isRealityAvailable()) {
player.records.thisReality.bestRSmin = currentRSmin;
player.records.thisReality.bestRSminVal = Effarig.shardsGained;
}
}
function passivePrestigeGen() {
let eternitiedGain = 0;
if (RealityUpgrade(14).isBought) {

Binary file not shown.

BIN
public/images/s12-bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 465.39 513.15"><defs><style>.cls-1{fill:#bd1818;}.cls-2{fill:#e52320;}.cls-3{fill:#dc9f12;}.cls-4{fill:#f4df61;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><polygon class="cls-1" points="20.21 115.95 32.02 124.19 32.02 135.2 20.21 139.25 20.21 115.95"/><polygon class="cls-2" points="349.47 473.5 319.37 451.96 319.37 120.21 349.47 106.41 349.47 473.5"/><polygon class="cls-1" points="64.88 101.04 76.69 109.47 76.69 119.87 64.88 123.92 64.88 101.04"/><polygon class="cls-2" points="349.47 84.33 319.37 105.56 319.37 120.21 349.47 120.05 349.47 84.33"/><polygon class="cls-2" points="445.18 115.95 433.38 123.92 433.38 135.2 445.18 139.25 445.18 115.95"/><polygon class="cls-2" points="400.51 101.04 388.7 109.19 388.7 119.87 400.51 123.92 400.51 101.04"/><polygon class="cls-2" points="349.47 148.97 319.44 148.97 232.73 209.23 232.73 233.27 349.47 148.97"/><polygon class="cls-1" points="146.02 148.97 145.87 148.98 145.87 120.21 145.87 106.17 115.91 84.33 115.91 106.41 115.91 120.05 115.91 473.5 145.87 452.03 145.87 171.27 232.73 233.27 232.73 209.23 146.02 148.97"/><polygon class="cls-2" points="232.73 233.27 115.92 149.89 115.92 120.05 115.92 120.05 115.92 84.33 85.82 93.64 85.82 116.74 64.88 123.92 64.88 101.04 41.37 108.9 41.37 131.99 20.21 139.25 20.21 115.95 0 122.66 0 146.19 0 146.19 0 205.18 26.54 224.19 26.54 458.69 115.92 473.5 115.92 310.95 232.73 399.41 232.73 233.27"/><polygon class="cls-1" points="445.18 115.95 445.18 139.25 424.02 131.99 424.02 108.89 400.51 101.04 400.51 123.92 379.57 116.74 379.57 93.64 349.47 84.33 349.47 106.41 349.47 120.05 349.47 148.97 232.73 233.27 232.73 399.41 349.47 309.54 349.47 473.5 438.17 462.82 438.17 224.19 465.39 205.16 465.39 148.97 465.39 146.19 465.39 122.66 445.18 115.95"/><path class="cls-3" d="M232.7,416.27h0v96.89l.8-1.1,31.12-44.37c-4.5-8.09-6.84-40.89-8.06-70.72Z"/><path class="cls-3" d="M241.18,23.83l5.26,60,40.82,0,14.06,14.64-16.44,15.93-10.69-11.06h-8.71c-4.14,4.34-7.3,9.8-7.53,16.46v54.11L232.7,193.84h0V0a12.73,12.73,0,0,1,11.65,12.66Z"/><path class="cls-4" d="M232.68,416.27h0v96.89l-.81-1.1-31.11-44.37c4.49-8.09,6.84-40.89,8-70.72Z"/><path class="cls-4" d="M224,23.83l-5.07,60-40.82,0L164.07,98.48l16.44,15.93,10.69-11.06h8.71c4.14,4.34,7.3,9.8,7.53,16.46v54.11l25.25,19.92h0V0a12.73,12.73,0,0,0-11.64,12.66Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
public/images/s12/shop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
public/images/s12/xmark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

View File

@ -14,8 +14,13 @@
--color-eternity--bg: #b341e04d;
}
:root .t-s12 {
--sidebar-width: 0;
}
:root .t-normal,
:root .t-s9 {
:root .t-s9,
:root .t-s12 {
--color-text: #ffffff;
--color-text-inverted: black;
--color-base: #1d1b22;
@ -41,7 +46,8 @@
}
body.t-normal,
body.t-s9 {
body.t-s9,
body.t-s12 {
color: white;
background-color: #111014;
}
@ -549,7 +555,8 @@ body.t-s9 {
background-color: var(--color-infinity);
}
.t-normal .c-game-header__tesseract-available {
.t-normal .c-game-header__tesseract-available,
.t-s12 .c-game-header__tesseract-available {
background: #eeeeee;
animation: a-tesseract-shift-dark 5s infinite;
}
@ -570,12 +577,14 @@ body.t-s9 {
margin: 0.6rem 0.4rem;
}
.t-normal .o-achievement__tooltip {
.t-normal .o-achievement__tooltip,
.t-s12 .o-achievement__tooltip {
background: var(--color-base);
border: 0.1rem solid var(--color-accent);
}
.t-normal .o-achievement__tooltip::after {
.t-normal .o-achievement__tooltip::after,
.t-s12 .o-achievement__tooltip::after {
border-top-color: var(--color-accent);
}
@ -891,11 +900,13 @@ body.t-s9 {
color: var(--color-eternity);
}
.t-normal .c-game-header__antimatter {
.t-normal .c-game-header__antimatter,
.t-s12 .c-game-header__antimatter {
color: var(--color-accent);
}
.t-normal .c-credits-header {
.t-normal .c-credits-header,
.t-s12 .c-credits-header {
color: var(--color-accent);
}
@ -924,17 +935,20 @@ body.t-s9 {
justify-content: flex-end;
}
.t-normal .c-sacrificed-glyphs--dragover {
.t-normal .c-sacrificed-glyphs--dragover,
.t-s12 .c-sacrificed-glyphs--dragover {
border-color: rgb(255, 255, 255);
box-shadow: 0 0 0.1rem 0.1rem rgb(255, 255, 255);
}
.t-normal .c-glyph-choice-icon {
.t-normal .c-glyph-choice-icon,
.t-s12 .c-glyph-choice-icon {
background-color: rgba(0, 0, 0, 30%);
border: var(--var-border-width, 0.2rem) solid rgba(0, 0, 0, 40%);
}
.t-normal .c-glyph-choice-effect-list {
.t-normal .c-glyph-choice-effect-list,
.t-s12 .c-glyph-choice-effect-list {
background-color: rgba(0, 0, 0, 30%);
border: var(--var-border-width, 0.2rem) solid rgba(0, 0, 0, 40%);
}

View File

@ -1,3 +1,8 @@
@font-face {
font-family: Typewriter;
src: url("MonospaceTypewriter.ttf");
}
#ui {
scrollbar-gutter: stable both-edges;
}

View File

@ -280,7 +280,7 @@ body {
@font-face {
font-family: Typewriter;
src: url("MonospaceTypewriter.ttf");
src: url("BlobEmoji-Bold.ttf"), url("MonospaceTypewriter.ttf");
}
@font-face {
@ -304,11 +304,6 @@ body {
src: url("fa-solid-900.ttf");
}
@font-face {
font-family: Typewriter;
src: url("BlobEmoji-Bold.ttf"), url("MonospaceTypewriter.ttf");
}
/* Background for s6 and s10 is not displayed by default */
#stars {
display: none;
@ -2754,8 +2749,10 @@ br {
overflow: hidden;
background-color: var(--color-base);
border: 0.1rem var(--color-good);
border-style: none solid solid;
border-style: solid;
border-radius: var(--var-border-radius, 0.4rem);
/* May be removed if it makes things to blurry */
transform: translateY(-0.1rem);
}
/* We need scrollbar-color in this rule as well as identical color specifications in the following two; some
@ -5361,7 +5358,7 @@ properly on certain themes. */
border: var(--var-border-width, 0.3rem) solid black;
border-radius: var(--var-border-radius, 0.6rem);
padding: 1rem;
transition-duration: 0.2s;
transition: all 0.2s, left 0s, top 0s, transform 0s;
}
.c-modal--short {
@ -7496,6 +7493,10 @@ kbd {
cursor: pointer;
}
.c-ra-pet-remembrance-button:hover {
box-shadow: 0 0 1rem inset var(--color-ra--base);
}
.s-base--metro .c-ra-pet-remembrance-button {
border-color: black;
}
@ -8075,7 +8076,7 @@ kbd {
}
.o-laitela-run-button {
width: 22rem;
width: 24rem;
height: 84rem;
font-family: Typewriter;
font-size: 1.1rem;
@ -8276,7 +8277,7 @@ kbd {
.c-laitela-singularity-container {
display: flex;
width: 96rem;
width: 98rem;
justify-content: space-around;
align-items: center;
color: var(--color-laitela--accent);
@ -8877,39 +8878,40 @@ kbd {
}
.c-reality-upgrade-btn--possible {
color: black;
/* Text color gets inherited from other pseudo-classes; so we use !important here in order to ensure good contrast
specifically on reality and imaginary upgrades, the only upgrades which use this and the related --locked below */
color: black !important;
background:
repeating-linear-gradient(
-45deg,
#979729,
#979729 3rem,
#777722 3rem,
#777722 6rem
#A2A229,
#A2A229 3rem,
#919122 3rem,
#919122 6rem
);
cursor: default;
}
.c-reality-upgrade-btn--possible:hover {
color: black;
background-color: #8b8529;
/* This is actually a solid color, but it flickers on hover if we don't make it a linear-gradient */
background: linear-gradient(0deg, #919122, #919122);
}
.c-reality-upgrade-btn--locked {
color: black;
background: #954040;
color: white !important;
background: #952020;
background-image:
linear-gradient(45deg, #a55252 25%, transparent 25%),
linear-gradient(135deg, #a55252 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #a55252 75%),
linear-gradient(135deg, transparent 75%, #a55252 75%);
linear-gradient(45deg, #802222 25%, transparent 25%),
linear-gradient(135deg, #802222 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #802222 75%),
linear-gradient(135deg, transparent 75%, #802222 75%);
background-position: 0 0, 2rem 0, 2rem -2rem, 0 2rem;
background-size: 4rem 4rem;
cursor: default;
}
.c-reality-upgrade-btn--locked:hover {
color: var(--color-reality-light);
background-color: #a53939;
background-color: #802222;
}
.c-reality-upgrade-btn--black-hole-unlock {
@ -8922,11 +8924,6 @@ kbd {
background-color: #37474f;
}
.t-dark .c-reality-upgrade-btn--locked {
color: var(--color-reality-light);
background-color: var(--color-bad);
}
.t-s6.c-reality-upgrade-btn:hover,
.t-s10.c-reality-upgrade-btn:hover {
background-color: var(--color-reality-light);
@ -9257,6 +9254,11 @@ input.o-automator-block-input {
padding: 0.5rem;
}
.t-s12 .l-h2p-body {
font-size: 1.3rem;
margin-left: 0;
}
.l-h2p-body::-webkit-scrollbar {
width: 1rem;
}
@ -9318,6 +9320,10 @@ input.o-automator-block-input {
border-bottom: 0.1rem solid white;
}
.t-s12 .o-h2p-tab-button {
border-bottom: 0.1rem solid black;
}
.l-help-me {
width: 2rem;
height: 2rem;

View File

@ -1,8 +1,3 @@
@font-face {
font-family: Typewriter;
src: url("BlobEmoji-Bold.ttf"), url("MonospaceTypewriter.ttf");
}
body.t-s11 {
color: #999999;
background: black;

View File

@ -0,0 +1,326 @@
body.t-s12 {
--s12-taskbar-height: 4.5rem;
--s12-border-color: #27221e;
--s12-background-gradient:
repeating-linear-gradient(
50deg,
rgba(170, 170, 170, 10%),
rgba(170, 170, 170, 10%) 2rem,
rgba(255, 255, 255, 10%) 4rem,
rgba(255, 255, 255, 10%) 5rem,
rgba(170, 170, 170, 10%) 6rem,
rgba(170, 170, 170, 10%) 8rem
),
linear-gradient(
-50deg,
rgba(60, 60, 60, 30%),
transparent 20%,
transparent 80%,
rgba(60, 60, 60, 30%)
);
height: 100%;
background: url("../images/s12-bg.jpg") no-repeat;
background-attachment: fixed;
background-color: #1bb9ee;
/* Center and scale the image nicely */
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.t-s12 .container {
color: black;
}
.t-s12 #ui {
justify-content: flex-start;
/* stylelint-disable-next-line unit-allowed-list */
perspective: 200vh;
scrollbar-gutter: auto;
}
.t-s12 .ui-wrapper {
flex-direction: column;
height: 100%;
}
.c-s12-close-button,
.t-s12 .c-modal .c-modal__close-btn {
display: flex;
width: 5rem;
height: 1.8rem;
position: absolute;
top: 0;
right: 1rem;
justify-content: center;
align-items: center;
font-size: 0;
background-image:
url("../images/s12/xmark.png"),
linear-gradient(to bottom, rgba(255, 255, 255, 40%) 40%, transparent 60%),
radial-gradient(#b43721, #844740);
background-position: center;
background-repeat: no-repeat;
border: 0.15rem solid var(--s12-border-color);
border-top: none;
border-radius: 0 0 0.5rem 0.5rem;
box-shadow: inset 0 0 0.2rem 0.1rem rgba(255, 255, 255, 80%);
cursor: pointer;
}
.c-modal__close-btn--disabled {
filter: grayscale(1);
cursor: default;
}
.c-s12-close-button::before,
.t-s12 .c-modal .c-modal__close-btn:not(.c-modal__close-btn--disabled)::before {
content: "";
width: 100%;
height: 100%;
opacity: 0;
background-image:
url("../images/s12/xmark.png"),
linear-gradient(to bottom, transparent 50%, rgba(224, 178, 64, 60%));
background-position: center;
background-repeat: no-repeat;
border-radius: inherit;
box-shadow: 0 0 1rem 0.3rem #d35532;
transition: opacity 0.4s;
}
.c-s12-close-button:hover::before,
.c-modal__close-btn:hover::before {
opacity: 1;
}
.t-s12 .c-modal {
--color-text: black;
--color-text-inverted: white;
max-width: calc(100% - 10rem);
font-family: "Segoe UI", Typewriter;
font-weight: normal;
background-color: rgba(187, 216, 242, 75%);
background-image: var(--s12-background-gradient);
border: 0.1rem solid var(--s12-border-color);
padding: 2.4rem 1rem 1rem;
-webkit-backdrop-filter: blur(1rem);
backdrop-filter: blur(1rem);
}
.t-s12 .c-modal__inner:not(.c-credits-modal),
.t-s12 .c-modal-message,
.t-s12 .l-h2p-modal,
.t-s12 .c-information-modal,
.t-s12 .l-changelog-modal,
.t-s12 .c-modal-away-progress {
align-items: flex-start;
text-align: left;
font-size: 1.3rem;
color: black;
background-color: #f0f0f0;
border: 0.1rem solid var(--s12-border-color);
margin: 0;
padding: 1rem;
}
.t-s12 .modal-progress-bar,
.t-s12 .c-credits-modal {
color: black;
background-color: #f0f0f0;
border: 0.1rem solid var(--s12-border-color);
box-sizing: border-box;
padding: 1rem;
}
.t-s12 .c-modal-options__large {
width: 53rem;
}
.t-s12 .l-singularity-milestone-modal-container-inner .c-laitela-milestone {
text-align: center;
font-family: Typewriter;
font-size: 1.4rem;
}
.t-s12 .c-modal__title,
.t-s12 .l-h2p-header,
.t-s12 .l-changelog-header {
display: flex;
width: auto;
height: 2.2rem;
position: absolute;
top: 0.2rem;
left: 0;
align-items: center;
font-size: 1.3rem;
font-weight: normal;
text-shadow: 0 0 0.7rem white;
padding-left: 1rem;
}
.c-credits-modal .c-modal__title {
display: inline;
position: static;
}
.c-credits-modal .c-game-header__antimatter {
color: black;
}
.t-s12 .c-h2p-title,
.t-s12 .c-changelog-title {
font-size: 1.3rem;
font-weight: normal;
}
.t-s12 .c-modal__confirmation-toggle {
margin-top: 1.5rem;
}
.t-s12 .c-modal__confirmation-toggle__checkbox {
width: 1.6rem;
height: 1.6rem;
color: #4b6192;
background: linear-gradient(-45deg, #ffffffff, #aeb2b5);
border: 0.2rem solid white;
border-radius: 0;
box-shadow: 0 0 0.1rem 0.1rem var(--s12-border-color), inset 0 0 0.1rem 0.1rem #a0a0a0;
}
.t-s12 .c-modal__confirmation-toggle:hover .c-modal__confirmation-toggle__checkbox {
transform: none;
}
.t-s12 .c-modal .o-primary-btn:not(.c-modal__close-btn, .c-autobuyer-box__mode-select),
.t-s12 .c-new-game-button {
position: relative;
z-index: 0;
align-self: flex-end;
text-align: center;
font-family: "Segoe UI", Typewriter;
font-weight: normal;
color: black;
background-image: linear-gradient(to bottom, white 45%, #d7d7d7 55%);
border: 0.16rem solid #747474;
box-shadow: inset 0 0 0.2rem 0.1rem white;
padding-top: 0;
padding-bottom: 0;
transition: box-shadow 0.3s;
}
.t-s12 .c-new-game-button {
padding: 1rem;
}
.t-s12 .c-modal .o-primary-btn.c-select-notation__item,
.t-s12 .c-modal .o-primary-btn.c-select-theme__item {
background-color: white;
background-image: none;
border: none;
box-shadow: none;
}
.t-s12 .c-modal .o-primary-btn.c-select-notation__item::before,
.t-s12 .c-modal .o-primary-btn.c-select-theme__item::before {
display: none;
}
.t-s12 .c-modal .o-primary-btn.c-dropdown-btn {
z-index: 1;
align-self: center;
}
.t-s12 .c-modal .l-select-notation,
.t-s12 .c-modal .l-select-theme {
scrollbar-color: #747474 white;
border-color: #747474;
}
.l-select-notation__inner::-webkit-scrollbar,
.l-select-theme__inner::-webkit-scrollbar {
background-color: white;
}
.t-s12 .c-modal .l-select-notation__inner::-webkit-scrollbar-thumb,
.t-s12 .c-modal .l-select-theme__inner::-webkit-scrollbar-thumb {
background-color: #747474;
}
.t-s12 .c-modal .o-primary-btn--disabled {
opacity: 0.5;
}
.t-s12 .c-modal .o-primary-btn:not(.c-modal__close-btn, .c-autobuyer-box__mode-select)::after,
.t-s12 .c-new-game-button::after {
content: "";
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: -1;
background-color: transparent;
transition: background-color 0.3s;
}
.t-s12 .c-modal .o-primary-btn:not(.c-modal__close-btn):hover,
.t-s12 .c-new-game-button:hover {
box-shadow: inset 0 0 0.2rem 0.1rem #52d9fb;
}
.t-s12 .c-modal .o-primary-btn:not(.c-modal__close-btn):hover::after,
.t-s12 .c-new-game-button:hover::after {
background-color: rgba(46, 210, 255, 30%);
}
.t-s12 .c-modal .o-primary-btn.o-primary-btn.c-select-notation__item:hover,
.t-s12 .c-modal .o-primary-btn.o-primary-btn.c-select-theme__item:hover {
color: white;
background-color: #2a90ff;
box-shadow: none;
}
.t-s12 .l-modal-buttons {
align-self: flex-end;
font-size: 1.2rem;
}
.t-s12 .c-modal__confirmation-toggle__tooltip {
display: none;
}
.t-s12 .l-modal-options__save-record {
align-self: center;
}
.t-s12 .modal-progress-bar__bg {
overflow: hidden;
position: relative;
background-image: linear-gradient(to right, #cbcbcb 90%, #c0c0c0);
border: 0.1rem solid var(--s12-border-color);
border-radius: 0.2rem;
box-shadow: inset 0 0 0.2rem 0.1rem white;
}
.t-s12 .modal-progress-bar__bg::before {
content: "";
width: 100%;
height: 100%;
position: absolute;
inset: 0;
background-image: linear-gradient(rgba(255, 255, 255, 70%) 30%, transparent 40%);
}
.t-s12 .modal-progress-bar__fg {
background: linear-gradient(to right, #0cb826, #20da3e 20%, #20da3e 80%, #0cb826);
}
.t-s12 .c-modal .c-autobuyer-box-row {
text-align: center;
background-color: transparent;
}

View File

@ -11,6 +11,7 @@ export default {
computed: {
people() { return GameDatabase.credits.people; },
roles() { return GameDatabase.credits.roles; },
isS12EndDisplay() { return this.$viewModel.theme === "S12" && !this.isModal; },
},
methods: {
relevantPeople(role) {
@ -23,7 +24,7 @@ export default {
</script>
<template>
<div>
<div :class="{ 'c-credits-s12-end': isS12EndDisplay }">
<h1
v-if="!isModal"
class="c-credits-header"
@ -60,6 +61,11 @@ export default {
</template>
<style scoped>
.c-credits-s12-end {
--color-text: white;
color: white;
}
.c-credits-header {
color: black;
}
@ -70,6 +76,10 @@ export default {
animation: a-credits-header--glow 25s infinite;
}
.t-s12 .c-credits-header {
color: var(--color-antimatter);
}
@keyframes a-credits-header--glow {
0% { color: #2196f3; }
33% { color: #673ab7; }

View File

@ -5,6 +5,10 @@ import GameUiComponentFixed from "@/components/GameUiComponentFixed";
import ModernUi from "@/components/ui-modes/modern/ModernUi";
import TabComponents from "@/components/tabs";
import S12DesktopIcons from "@/components/ui-modes/s12/DesktopIcons";
import S12Ui from "@/components/ui-modes/s12/S12Ui";
import S12UiFixed from "@/components/ui-modes/s12/S12UiFixed";
export default {
name: "GameUIComponent",
components: {
@ -13,12 +17,19 @@ export default {
ModernUi,
GameUiComponentFixed,
BackgroundAnimations,
S12Ui,
S12UiFixed,
S12DesktopIcons,
},
computed: {
view() {
return this.$viewModel;
},
isThemeS12() {
return this.view.theme === "S12";
},
uiLayout() {
if (this.isThemeS12) return "S12Ui";
return this.view.newUI ? "ModernUi" : "ClassicUi";
},
containerClass() {
@ -52,6 +63,7 @@ export default {
class="c-game-tab"
/>
</component>
<S12DesktopIcons v-if="isThemeS12" />
<link
v-if="view.theme !== 'Normal'"
type="text/css"
@ -59,8 +71,9 @@ export default {
:href="themeCss"
>
</div>
<GameUiComponentFixed />
<BackgroundAnimations />
<GameUiComponentFixed v-if="!isThemeS12" />
<BackgroundAnimations v-if="!isThemeS12" />
<S12UiFixed v-if="isThemeS12" />
</div>
</template>

View File

@ -73,29 +73,31 @@ export default {
class="l-time-studies-tab__tt-shop"
/>
<ModernSidebar
v-if="view.newUI"
v-if="view.newUI && view.theme !== 'S12'"
:style="hideIfMatoFullscreen"
/>
<SaveTimer :style="hideIfMatoFullscreen" />
<SpeedrunStatus :style="hideIfMatoFullscreen" />
<ModalProgressBar v-if="view.modal.progressBar" />
<CelestialQuoteModal
v-else-if="view.quotes.current"
:quote="view.quotes.current"
/>
<CelestialQuoteHistoryDisplay
v-else-if="view.quotes.history"
:quotes="view.quotes.history"
/>
<PopupModal
v-else-if="view.modal.current"
:modal="view.modal.current"
/>
<ModalProgressBar v-if="view.modal.progressBar" />
<FadeAway v-if="ending" />
<CreditsContainer v-if="ending" />
<NewGame v-if="ending" />
<SpectateGame />
<template v-if="view.theme !== 'S12'">
<ModalProgressBar v-if="view.modal.progressBar" />
<CelestialQuoteModal
v-else-if="view.quotes.current"
:quote="view.quotes.current"
/>
<CelestialQuoteHistoryDisplay
v-else-if="view.quotes.history"
:quotes="view.quotes.history"
/>
<PopupModal
v-else-if="view.modal.current"
:modal="view.modal.current"
/>
<ModalProgressBar v-if="view.modal.progressBar" />
<FadeAway v-if="ending" />
<CreditsContainer v-if="ending" />
<NewGame v-if="ending" />
<SpectateGame />
</template>
</div>
</template>
@ -111,4 +113,8 @@ export default {
justify-content: center;
pointer-events: none;
}
.t-s12 .c-game-ui--fixed {
position: absolute;
}
</style>

View File

@ -30,7 +30,7 @@ export default {
this.saveDisabled = GameEnd.endState >= END_STATE_MARKERS.INTERACTIVITY_DISABLED;
},
save() {
GameStorage.save(false);
GameStorage.save(false, true);
}
}
};
@ -53,8 +53,8 @@ export default {
position: absolute;
bottom: 0;
left: 0;
text-align: left;
z-index: 5;
text-align: left;
color: var(--color-text);
background-color: var(--color-base);
border-top: 0.1rem solid var(--color-accent);

View File

@ -127,6 +127,11 @@ export default {
padding: 0.5rem;
}
.t-s12 .l-changelog-body {
font-size: 1.3rem;
margin-left: 0;
}
.l-changelog-body::-webkit-scrollbar {
width: 1rem;
}
@ -187,6 +192,10 @@ export default {
.s-base--dark .o-changelog-tab-button {
border-bottom: 0.1rem solid white;
}
.t-s12 .o-changelog-tab-button {
border-bottom: 0.1rem solid black;
}
</style>
<style>

View File

@ -117,4 +117,8 @@ export default {
.s-base--dark .o-h2p-tab-button--first-irrelevant {
border-top-color: white;
}
.t-s12 .o-h2p-tab-button--first-irrelevant {
border-top-color: black;
}
</style>

View File

@ -89,7 +89,7 @@ export default {
},
willLoseCosmetics() {
const currSets = player.reality.glyphs.cosmetics.unlockedFromNG;
const importedSets = this.player.reality?.glyphs.cosmetics.unlockedFromNG ?? [];
const importedSets = this.player.reality?.glyphs.cosmetics?.unlockedFromNG ?? [];
return currSets.filter(set => !importedSets.includes(set)).length > 0;
},
willLoseSpeedrun() {

View File

@ -87,6 +87,11 @@ export default {
padding: 0.5rem;
}
.t-s12 .c-info-body {
font-size: 1.3rem;
margin: 0;
}
.c-socials {
font-size: 7.5rem;
}
@ -96,4 +101,9 @@ export default {
justify-content: space-evenly;
align-items: center;
}
.t-s12 .l-socials {
width: 100%;
align-self: center;
}
</style>

View File

@ -17,6 +17,9 @@ export default {
modal() {
return this.$viewModel.modal.current;
},
isThemeS12() {
return this.$viewModel.theme === "S12";
}
},
created() {
this.on$(GAME_EVENT.ENTER_PRESSED, this.handleClick);
@ -41,9 +44,13 @@ export default {
<div class="c-modal-message l-modal-content--centered">
<ModalCloseButton
v-if="modal.closeButton"
class="c-modal__close-btn--tiny"
:class="isThemeS12 ? 'c-modal__close-btn' : 'c-modal__close-btn--tiny'"
@click="emitClose"
/>
<ModalCloseButton
v-else-if="isThemeS12"
class="c-modal__close-btn c-modal__close-btn--disabled"
/>
<div
class="c-modal-message__text"
v-html="message"
@ -54,5 +61,11 @@ export default {
>
Okay
</PrimaryButton>
<div
v-if="isThemeS12"
class="c-modal__title"
>
Message
</div>
</div>
</template>

View File

@ -31,36 +31,38 @@ export default {
<div
class="l-modal-overlay c-modal-overlay progress-bar-modal"
>
<div class="modal-progress-bar c-modal">
<div class="modal-progress-bar__label">
{{ progress.label }}
</div>
<div>
{{ progress.info() }}
</div>
<div class="modal-progress-bar__margin">
<div>
{{ progress.progressName }}: {{ formatInt(progress.current) }}/{{ formatInt(progress.max) }}
<div class="c-modal">
<div class="modal-progress-bar">
<div class="modal-progress-bar__label">
{{ progress.label }}
</div>
<div>
Remaining: {{ remainingTime }}
{{ progress.info() }}
</div>
<div class="modal-progress-bar__hbox">
<div class="modal-progress-bar__bg">
<div
class="modal-progress-bar__fg"
:style="foregroundStyle"
/>
<div class="modal-progress-bar__margin">
<div>
{{ progress.progressName }}: {{ formatInt(progress.current) }}/{{ formatInt(progress.max) }}
</div>
<div>
Remaining: {{ remainingTime }}
</div>
<div class="modal-progress-bar__hbox">
<div class="modal-progress-bar__bg">
<div
class="modal-progress-bar__fg"
:style="foregroundStyle"
/>
</div>
</div>
</div>
</div>
<div class="modal-progress-bar__buttons">
<OfflineSpeedupButton
v-for="(button, id) in buttons"
:key="id"
:button="button"
:progress="progress"
/>
<div class="modal-progress-bar__buttons">
<OfflineSpeedupButton
v-for="(button, id) in buttons"
:key="id"
:button="button"
:progress="progress"
/>
</div>
</div>
</div>
</div>
@ -71,19 +73,22 @@ export default {
z-index: 8;
}
.modal-progress-bar {
display: flex;
flex-direction: column;
width: 40rem;
.c-modal {
position: fixed;
/* stylelint-disable-next-line unit-allowed-list */
top: 50vh;
/* stylelint-disable-next-line unit-allowed-list */
left: 50vw;
transform: translate(-50%, -50%);
}
.modal-progress-bar {
display: flex;
flex-direction: column;
width: 40rem;
z-index: 3;
justify-content: space-between;
align-items: center;
transform: translate(-50%, -50%);
}
.modal-progress-bar__hbox {

View File

@ -15,7 +15,7 @@ export default {
</script>
<template>
<div>
<div class="c-modal__inner">
<div class="c-modal__header">
<ModalCloseButton @click="closeModal" />
<span

View File

@ -9,21 +9,43 @@ export default {
},
data() {
return {
showModal: false
showModal: false,
positionStyle: {},
};
},
created() {
this.on$(GAME_EVENT.CLOSE_MODAL, this.hide);
},
mounted() {
this.updatePositionStyles();
},
destroyed() {
document.activeElement.blur();
},
methods: {
update() {
const oldShowModal = this.showModal;
// 2.5 is the cutoff point where the screen starts fading (interactivity disabled). However, we specifically
// want to allow glyph customization to appear at the very end (and nothing else)
this.showModal = GameEnd.endState <= END_STATE_MARKERS.INTERACTIVITY_DISABLED ||
this.modal.component.name === "CosmeticSetChoiceModal";
if (this.showModal !== oldShowModal) this.$nextTick(() => this.updatePositionStyles());
this.updatePositionStyles();
},
updatePositionStyles() {
if (!this.$refs.modal) return;
if (!this.showModal || this.$viewModel.theme !== "S12") {
this.positionStyle = {};
return;
}
const w = this.$refs.modal.offsetWidth, h = this.$refs.modal.offsetHeight;
// We need to set position style specifically for S12 because using a transform messes things up and
// makes everything really blurry
this.positionStyle = {
left: `${Math.round(innerWidth / 2 - w / 2)}px`,
top: `${Math.round(innerHeight / 2 - h / 2)}px`,
transform: "none",
};
},
hide() {
if (!this.modal.isOpen) return;
@ -37,7 +59,9 @@ export default {
<template>
<div
v-if="showModal"
ref="modal"
class="c-modal l-modal"
:style="positionStyle"
>
<component
:is="modal.component"

View File

@ -262,13 +262,13 @@ export default {
/>
</template>
<StudyStringPreview
v-if="!deleting"
v-if="!deleting && inputIsValidTree"
:show-preview="inputIsValidTree"
:new-studies="!isImporting || (canEternity && respecAndLoad) ? importedTree.newStudiesArray
: combinedTree.newStudiesArray"
:disregard-current-studies="!isImporting || (canEternity && respecAndLoad)"
/>
<div v-else-if="hasInput">
<div v-else-if="!deleting && hasInput">
Not a valid tree
</div>
</div>
@ -276,7 +276,7 @@ export default {
<br>
<PrimaryButton
v-if="!deleting"
ach-tooltip="This will format the study preset text, for example, changing 'a,b,c|d' to 'a, b, c | d'."
v-tooltip="'This will format the study preset text, for example, changing \'a,b,c|d\' to \'a, b, c | d\'.'"
@click="convertInputShorthands"
>
Format Preset Text

View File

@ -81,7 +81,7 @@ export default {
text-align: left;
border: 0.1rem solid var(--color-text);
border-radius: var(--var-border-radius, 0.4rem);
margin: 1rem;
margin: 1rem 0;
padding: 1.5rem;
}

View File

@ -130,8 +130,13 @@ export default {
.c-center {
display: flex;
flex-direction: column;
align-items: center;
width: 38rem;
align-items: center;
}
.t-s12 .c-center {
width: 50rem;
text-align: center;
}
.c-dropdown-btn {
@ -141,8 +146,8 @@ export default {
}
.c-dropdown-header {
padding: 0.5rem;
height: 5rem;
padding: 0.5rem;
user-select: none;
}

View File

@ -63,4 +63,8 @@ export default {
.l-wrapper {
width: 62rem;
}
.t-s12 .l-wrapper {
width: 65rem;
}
</style>

View File

@ -25,7 +25,8 @@ export default {
simRealities: 0,
realityMachines: new Decimal(),
shardsGained: 0,
effarigUnlocked: false
effarigUnlocked: false,
willAutoPurge: false,
};
},
computed: {
@ -89,6 +90,7 @@ export default {
const simRMGained = MachineHandler.gainedRealityMachines.times(this.simRealities);
this.realityMachines.copyFrom(simRMGained.clampMax(MachineHandler.distanceToRMCap));
this.shardsGained = Effarig.shardsGained * (simulatedRealityCount(false) + 1);
this.willAutoPurge = player.reality.autoAutoClean;
if (this.firstReality) return;
for (let i = 0; i < this.glyphs.length; ++i) {
const currentGlyph = this.glyphs[i];
@ -172,6 +174,12 @@ export default {
automatically choosing another {{ quantifyInt("Glyph", simRealities - 1) }}
based on your Glyph filter settings.
</div>
<div v-if="willAutoPurge">
<br>
Auto-purge is currently enabled; your selected Glyph
<br>
may not appear in your inventory after it triggers.
</div>
<div
v-if="!hasSpace"
class="o-warning"

View File

@ -0,0 +1,146 @@
<script>
import S12Games from "./s12-games";
let isSelectingGame = false;
export default {
name: "S12Games",
data() {
return {
S12Games
};
},
mounted() {
document.body.addEventListener("click", this.clearSelected);
},
beforeDestroy() {
document.body.removeEventListener("click", this.clearSelected);
this.clearSelected();
},
methods: {
clearSelected() {
if (isSelectingGame) return;
S12Games.selected = -1;
},
handleClick(idx) {
// This makes what everything is doing clearer
// eslint-disable-next-line no-negated-condition
if (S12Games.selected !== idx) {
S12Games.selected = idx;
isSelectingGame = true;
setTimeout(() => isSelectingGame = false, 0);
} else {
window.open(S12Games.entries[idx].link);
}
}
}
};
</script>
<template>
<div class="c-s12-games-container">
<div
v-for="(game, idx) in S12Games.entries"
:key="game.name"
class="c-s12-game"
:class="{ 'c-s12-game--selected': S12Games.selected === idx, }"
@click="handleClick(idx)"
>
<div class="c-s12-game__inner">
<img
:src="`images/s12/${game.image}`"
class="c-s12-game__img"
>
<div class="c-s12-game__text">
{{ game.name }}
</div>
</div>
</div>
</div>
</template>
<style scoped>
.c-s12-games-container {
--icon-font-size: 1.1rem;
--icon-line-height: 1.1;
--icon-size: 8rem;
--icon-margin: 0.4rem;
--icon-inner-padding: 0.5rem;
--total-icon-height: calc(
var(--icon-size) + var(--icon-margin) * 2 +
var(--icon-font-size) * var(--icon-line-height) * 2 +
var(--icon-inner-padding) * 2
);
--total-game-width: 10rem;
--game-margin: 0.2rem;
display: flex;
overflow-y: auto;
flex: 1 0 auto;
flex-wrap: wrap;
width: calc(4 * (var(--total-game-width) + var(--game-margin) * 2));
height: 40rem;
user-select: none;
}
.c-s12-game {
overflow: hidden;
width: var(--total-game-width);
height: var(--total-icon-height);
position: relative;
z-index: 0;
margin: var(--game-margin);
}
.c-s12-game__inner {
display: flex;
overflow: hidden;
flex-direction: column;
width: 100%;
position: relative;
align-items: center;
padding: var(--icon-inner-padding);
cursor: pointer;
}
.c-s12-game--selected {
overflow: visible;
z-index: 1;
}
.c-s12-game__inner::before {
content: "";
position: absolute;
inset: 0;
z-index: -1;
opacity: 0;
background-image: linear-gradient(rgba(13, 120, 242, 0.2), rgba(13, 120, 242, 0.25));
border: 0.1rem solid #82a5d0;
border-radius: 0.5rem;
box-shadow: inset 0 0 0.2rem 0.1rem rgba(255, 255, 255, 0.7);
transition: opacity 0.2s;
}
.c-s12-game:hover .c-s12-game__inner::before {
opacity: 0.5;
}
.c-s12-game.c-s12-game--selected .c-s12-game__inner::before {
opacity: 1;
}
.c-s12-game__img {
height: var(--icon-size);
margin: var(--icon-margin);
}
.c-s12-game__text {
overflow: hidden;
width: 100%;
text-align: center;
font-family: "Segoe UI", Typewriter;
font-size: var(--icon-font-size);
font-weight: normal;
line-height: var(--icon-line-height);
color: black;
}
</style>

View File

@ -0,0 +1,64 @@
<script>
import ModalWrapper from "@/components/modals/ModalWrapper";
import S12GameEntries from "./S12GameEntries";
import S12Games from "./s12-games";
export default {
name: "S12GamesModal",
components: {
ModalWrapper,
S12GameEntries,
},
data() {
return {
S12Games,
};
},
methods: {
update() {
if (this.$viewModel.theme !== "S12") EventHub.dispatch(GAME_EVENT.CLOSE_MODAL);
}
}
};
</script>
<template>
<ModalWrapper class="c-modal-s12-games">
<div class="c-modal__title">
Games
</div>
<S12GameEntries />
<div class="c-modal-s12-games__magnified-display">
<template v-if="S12Games.selected !== -1">
<img
class="c-modal-s12-games__magnified-display__img"
:src="`images/s12/${S12Games.entries[S12Games.selected].image}`"
>
<b class="c-modal-s12-games__magnified-display__text">
{{ S12Games.entries[S12Games.selected].name }}
</b>
</template>
</div>
</ModalWrapper>
</template>
<style scoped>
.c-modal-s12-games {
display: flex;
width: 64rem;
}
.c-modal-s12-games__magnified-display {
width: 100%;
align-self: stretch;
text-align: center;
border-left: 0.1rem solid #86b2df;
padding: 2rem;
}
.c-modal-s12-games__magnified-display__img {
width: 100%;
margin: 2rem 0 6rem;
}
</style>

Some files were not shown because too many files have changed in this diff Show More