diff --git a/Pictures/Default/BlueberryLuckDilator.png b/Pictures/Default/BlueberryLuckDilator.png new file mode 100644 index 000000000..f10ea35bf Binary files /dev/null and b/Pictures/Default/BlueberryLuckDilator.png differ diff --git a/Pictures/Default/BlueberryPixelLuck.png b/Pictures/Default/BlueberryPixelLuck.png new file mode 100644 index 000000000..090c01b46 Binary files /dev/null and b/Pictures/Default/BlueberryPixelLuck.png differ diff --git a/Pictures/Default/CorruptSpatialDilation.png b/Pictures/Default/CorruptDilation.png similarity index 100% rename from Pictures/Default/CorruptSpatialDilation.png rename to Pictures/Default/CorruptDilation.png diff --git a/Pictures/Default/CorruptHyperchallenged.png b/Pictures/Default/CorruptHyperchallenge.png similarity index 100% rename from Pictures/Default/CorruptHyperchallenged.png rename to Pictures/Default/CorruptHyperchallenge.png diff --git a/Pictures/Default/CorruptScientificIlliteracy.png b/Pictures/Default/CorruptIlliteracy.png similarity index 100% rename from Pictures/Default/CorruptScientificIlliteracy.png rename to Pictures/Default/CorruptIlliteracy.png diff --git a/Pictures/Default/CorruptFinancialCollapse.png b/Pictures/Default/CorruptRecession.png similarity index 100% rename from Pictures/Default/CorruptFinancialCollapse.png rename to Pictures/Default/CorruptRecession.png diff --git a/Pictures/Default/CorruptViscocity.png b/Pictures/Default/CorruptViscosity.png similarity index 100% rename from Pictures/Default/CorruptViscocity.png rename to Pictures/Default/CorruptViscosity.png diff --git a/Pictures/Default/OcteractPixelLuck.png b/Pictures/Default/OcteractPixelLuck.png new file mode 100644 index 000000000..d94d5b9ae Binary files /dev/null and b/Pictures/Default/OcteractPixelLuck.png differ diff --git a/Pictures/Default/OcteractPixelLuck2.png b/Pictures/Default/OcteractPixelLuck2.png new file mode 100644 index 000000000..75e9d7bc2 Binary files /dev/null and b/Pictures/Default/OcteractPixelLuck2.png differ diff --git a/Pictures/Default/PixelAmbrosiaGeneration.png b/Pictures/Default/PixelAmbrosiaGeneration.png new file mode 100644 index 000000000..216e2cd24 Binary files /dev/null and b/Pictures/Default/PixelAmbrosiaGeneration.png differ diff --git a/Pictures/Default/PixelAmbrosiaGeneration2.png b/Pictures/Default/PixelAmbrosiaGeneration2.png new file mode 100644 index 000000000..2ec933d11 Binary files /dev/null and b/Pictures/Default/PixelAmbrosiaGeneration2.png differ diff --git a/Pictures/Default/PixelAmbrosiaGeneration3.png b/Pictures/Default/PixelAmbrosiaGeneration3.png new file mode 100644 index 000000000..1cef15d39 Binary files /dev/null and b/Pictures/Default/PixelAmbrosiaGeneration3.png differ diff --git a/Pictures/Default/PixelAmbrosiaLuck.png b/Pictures/Default/PixelAmbrosiaLuck.png new file mode 100644 index 000000000..edb13f79a Binary files /dev/null and b/Pictures/Default/PixelAmbrosiaLuck.png differ diff --git a/Pictures/Default/PixelAmbrosiaLuck2.png b/Pictures/Default/PixelAmbrosiaLuck2.png new file mode 100644 index 000000000..8f5f049f2 Binary files /dev/null and b/Pictures/Default/PixelAmbrosiaLuck2.png differ diff --git a/Pictures/Default/PixelAmbrosiaLuck3.png b/Pictures/Default/PixelAmbrosiaLuck3.png new file mode 100644 index 000000000..f397639a5 Binary files /dev/null and b/Pictures/Default/PixelAmbrosiaLuck3.png differ diff --git a/Pictures/Default/PixelBlueberry.png b/Pictures/Default/PixelBlueberry.png new file mode 100644 index 000000000..82caf946e Binary files /dev/null and b/Pictures/Default/PixelBlueberry.png differ diff --git a/Pictures/Default/PixelBlueberry2.png b/Pictures/Default/PixelBlueberry2.png new file mode 100644 index 000000000..5e76d46dd Binary files /dev/null and b/Pictures/Default/PixelBlueberry2.png differ diff --git a/Pictures/Default/PixelBlueberry3.png b/Pictures/Default/PixelBlueberry3.png new file mode 100644 index 000000000..1ea4db145 Binary files /dev/null and b/Pictures/Default/PixelBlueberry3.png differ diff --git a/Pictures/Default/PixelCubes.png b/Pictures/Default/PixelCubes.png new file mode 100644 index 000000000..4080f4e0c Binary files /dev/null and b/Pictures/Default/PixelCubes.png differ diff --git a/Pictures/Default/PixelFreeUpgradeImprovement.png b/Pictures/Default/PixelFreeUpgradeImprovement.png new file mode 100644 index 000000000..2021ebdda Binary files /dev/null and b/Pictures/Default/PixelFreeUpgradeImprovement.png differ diff --git a/Pictures/Default/PixelFreeUpgradeImprovement2.png b/Pictures/Default/PixelFreeUpgradeImprovement2.png new file mode 100644 index 000000000..b8df10430 Binary files /dev/null and b/Pictures/Default/PixelFreeUpgradeImprovement2.png differ diff --git a/Pictures/Default/PixelFreeUpgradeImprovement3.png b/Pictures/Default/PixelFreeUpgradeImprovement3.png new file mode 100644 index 000000000..88b7632cf Binary files /dev/null and b/Pictures/Default/PixelFreeUpgradeImprovement3.png differ diff --git a/Pictures/Default/PixelObtainium.png b/Pictures/Default/PixelObtainium.png new file mode 100644 index 000000000..efb8ffcf3 Binary files /dev/null and b/Pictures/Default/PixelObtainium.png differ diff --git a/Pictures/Default/PixelOfferings.png b/Pictures/Default/PixelOfferings.png new file mode 100644 index 000000000..ca88ab153 Binary files /dev/null and b/Pictures/Default/PixelOfferings.png differ diff --git a/Pictures/Default/PixelPixelGeneration.png b/Pictures/Default/PixelPixelGeneration.png new file mode 100644 index 000000000..0e8992bb7 Binary files /dev/null and b/Pictures/Default/PixelPixelGeneration.png differ diff --git a/Pictures/Default/PixelPixelGeneration2.png b/Pictures/Default/PixelPixelGeneration2.png new file mode 100644 index 000000000..5047d506e Binary files /dev/null and b/Pictures/Default/PixelPixelGeneration2.png differ diff --git a/Pictures/Default/PixelPixelGeneration3.png b/Pictures/Default/PixelPixelGeneration3.png new file mode 100644 index 000000000..10d679a9f Binary files /dev/null and b/Pictures/Default/PixelPixelGeneration3.png differ diff --git a/Pictures/Default/PixelPixelLuck.png b/Pictures/Default/PixelPixelLuck.png new file mode 100644 index 000000000..03f421a6c Binary files /dev/null and b/Pictures/Default/PixelPixelLuck.png differ diff --git a/Pictures/Default/PixelPixelLuckConverter.png b/Pictures/Default/PixelPixelLuckConverter.png new file mode 100644 index 000000000..e06876055 Binary files /dev/null and b/Pictures/Default/PixelPixelLuckConverter.png differ diff --git a/Pictures/Default/PixelPixelLuckConverter2.png b/Pictures/Default/PixelPixelLuckConverter2.png new file mode 100644 index 000000000..e06876055 Binary files /dev/null and b/Pictures/Default/PixelPixelLuckConverter2.png differ diff --git a/Pictures/Default/PixelQuarks.png b/Pictures/Default/PixelQuarks.png new file mode 100644 index 000000000..ade3b8857 Binary files /dev/null and b/Pictures/Default/PixelQuarks.png differ diff --git a/Pictures/Default/PixelRoleBonus.png b/Pictures/Default/PixelRoleBonus.png new file mode 100644 index 000000000..25534fcc0 Binary files /dev/null and b/Pictures/Default/PixelRoleBonus.png differ diff --git a/Pictures/Default/PixelTutorial.png b/Pictures/Default/PixelTutorial.png new file mode 100644 index 000000000..f36eb7c59 Binary files /dev/null and b/Pictures/Default/PixelTutorial.png differ diff --git a/Pictures/Default/PixelTwoMind.png b/Pictures/Default/PixelTwoMind.png new file mode 100644 index 000000000..3d3ff7414 Binary files /dev/null and b/Pictures/Default/PixelTwoMind.png differ diff --git a/Pictures/Default/SingularityPixelLuck.png b/Pictures/Default/SingularityPixelLuck.png new file mode 100644 index 000000000..573534a1f Binary files /dev/null and b/Pictures/Default/SingularityPixelLuck.png differ diff --git a/Pictures/Default/SingularityPixelLuck2.png b/Pictures/Default/SingularityPixelLuck2.png new file mode 100644 index 000000000..e7f182ea5 Binary files /dev/null and b/Pictures/Default/SingularityPixelLuck2.png differ diff --git a/Pictures/Default/UltimatePixel.png b/Pictures/Default/UltimatePixel.png new file mode 100644 index 000000000..489a46e15 Binary files /dev/null and b/Pictures/Default/UltimatePixel.png differ diff --git a/Pictures/Default/ach414.png b/Pictures/Default/ach414.png new file mode 100644 index 000000000..7319b2a19 Binary files /dev/null and b/Pictures/Default/ach414.png differ diff --git a/Pictures/Default/ach415.png b/Pictures/Default/ach415.png new file mode 100644 index 000000000..7319b2a19 Binary files /dev/null and b/Pictures/Default/ach415.png differ diff --git a/Pictures/Default/ach416.png b/Pictures/Default/ach416.png new file mode 100644 index 000000000..7319b2a19 Binary files /dev/null and b/Pictures/Default/ach416.png differ diff --git a/Pictures/Default/ach417.png b/Pictures/Default/ach417.png new file mode 100644 index 000000000..7319b2a19 Binary files /dev/null and b/Pictures/Default/ach417.png differ diff --git a/Pictures/Default/ach418.png b/Pictures/Default/ach418.png new file mode 100644 index 000000000..7319b2a19 Binary files /dev/null and b/Pictures/Default/ach418.png differ diff --git a/Pictures/Default/ach419.png b/Pictures/Default/ach419.png new file mode 100644 index 000000000..7319b2a19 Binary files /dev/null and b/Pictures/Default/ach419.png differ diff --git a/Pictures/Default/ach420.png b/Pictures/Default/ach420.png new file mode 100644 index 000000000..7319b2a19 Binary files /dev/null and b/Pictures/Default/ach420.png differ diff --git a/Pictures/Default/ach421.png b/Pictures/Default/ach421.png new file mode 100644 index 000000000..94e80854e Binary files /dev/null and b/Pictures/Default/ach421.png differ diff --git a/Pictures/Default/ach422.png b/Pictures/Default/ach422.png new file mode 100644 index 000000000..94e80854e Binary files /dev/null and b/Pictures/Default/ach422.png differ diff --git a/Pictures/Default/ach423.png b/Pictures/Default/ach423.png new file mode 100644 index 000000000..94e80854e Binary files /dev/null and b/Pictures/Default/ach423.png differ diff --git a/Pictures/Default/ach424.png b/Pictures/Default/ach424.png new file mode 100644 index 000000000..94e80854e Binary files /dev/null and b/Pictures/Default/ach424.png differ diff --git a/Pictures/Default/ach425.png b/Pictures/Default/ach425.png new file mode 100644 index 000000000..94e80854e Binary files /dev/null and b/Pictures/Default/ach425.png differ diff --git a/Pictures/Default/ach426.png b/Pictures/Default/ach426.png new file mode 100644 index 000000000..94e80854e Binary files /dev/null and b/Pictures/Default/ach426.png differ diff --git a/Pictures/Default/ach427.png b/Pictures/Default/ach427.png new file mode 100644 index 000000000..94e80854e Binary files /dev/null and b/Pictures/Default/ach427.png differ diff --git a/Pictures/Default/ach428.png b/Pictures/Default/ach428.png new file mode 100644 index 000000000..dcc53d245 Binary files /dev/null and b/Pictures/Default/ach428.png differ diff --git a/Pictures/Default/ach429.png b/Pictures/Default/ach429.png new file mode 100644 index 000000000..dcc53d245 Binary files /dev/null and b/Pictures/Default/ach429.png differ diff --git a/Pictures/Default/ach430.png b/Pictures/Default/ach430.png new file mode 100644 index 000000000..dcc53d245 Binary files /dev/null and b/Pictures/Default/ach430.png differ diff --git a/Pictures/Default/ach431.png b/Pictures/Default/ach431.png new file mode 100644 index 000000000..02b5e637c Binary files /dev/null and b/Pictures/Default/ach431.png differ diff --git a/Pictures/Default/ach432.png b/Pictures/Default/ach432.png new file mode 100644 index 000000000..02b5e637c Binary files /dev/null and b/Pictures/Default/ach432.png differ diff --git a/Pictures/Default/ach433.png b/Pictures/Default/ach433.png new file mode 100644 index 000000000..02b5e637c Binary files /dev/null and b/Pictures/Default/ach433.png differ diff --git a/Pictures/Default/ach434.png b/Pictures/Default/ach434.png new file mode 100644 index 000000000..bf3bf6dd5 Binary files /dev/null and b/Pictures/Default/ach434.png differ diff --git a/Pictures/Default/ach435.png b/Pictures/Default/ach435.png new file mode 100644 index 000000000..bf3bf6dd5 Binary files /dev/null and b/Pictures/Default/ach435.png differ diff --git a/Pictures/Default/ach436.png b/Pictures/Default/ach436.png new file mode 100644 index 000000000..bf3bf6dd5 Binary files /dev/null and b/Pictures/Default/ach436.png differ diff --git a/Pictures/Default/ach437.png b/Pictures/Default/ach437.png new file mode 100644 index 000000000..d23166c2e Binary files /dev/null and b/Pictures/Default/ach437.png differ diff --git a/Pictures/Default/ach438.png b/Pictures/Default/ach438.png new file mode 100644 index 000000000..d23166c2e Binary files /dev/null and b/Pictures/Default/ach438.png differ diff --git a/Pictures/Default/ach439.png b/Pictures/Default/ach439.png new file mode 100644 index 000000000..d23166c2e Binary files /dev/null and b/Pictures/Default/ach439.png differ diff --git a/Pictures/Default/patchnotes.png b/Pictures/Default/patchnotes.png index 6a733a0de..281bb2bf3 100644 Binary files a/Pictures/Default/patchnotes.png and b/Pictures/Default/patchnotes.png differ diff --git a/Pictures/Legacy/BlueberryLuckDilator.png b/Pictures/Legacy/BlueberryLuckDilator.png new file mode 100644 index 000000000..f10ea35bf Binary files /dev/null and b/Pictures/Legacy/BlueberryLuckDilator.png differ diff --git a/Pictures/Legacy/BlueberryPixelLuck.png b/Pictures/Legacy/BlueberryPixelLuck.png new file mode 100644 index 000000000..090c01b46 Binary files /dev/null and b/Pictures/Legacy/BlueberryPixelLuck.png differ diff --git a/Pictures/Legacy/CorruptSpatialDilation.png b/Pictures/Legacy/CorruptDilation.png similarity index 100% rename from Pictures/Legacy/CorruptSpatialDilation.png rename to Pictures/Legacy/CorruptDilation.png diff --git a/Pictures/Legacy/CorruptHyperchallenged.png b/Pictures/Legacy/CorruptHyperchallenge.png similarity index 100% rename from Pictures/Legacy/CorruptHyperchallenged.png rename to Pictures/Legacy/CorruptHyperchallenge.png diff --git a/Pictures/Legacy/CorruptScientificIlliteracy.png b/Pictures/Legacy/CorruptIlliteracy.png similarity index 100% rename from Pictures/Legacy/CorruptScientificIlliteracy.png rename to Pictures/Legacy/CorruptIlliteracy.png diff --git a/Pictures/Legacy/CorruptFinancialCollapse.png b/Pictures/Legacy/CorruptRecession.png similarity index 100% rename from Pictures/Legacy/CorruptFinancialCollapse.png rename to Pictures/Legacy/CorruptRecession.png diff --git a/Pictures/Legacy/CorruptViscocity.png b/Pictures/Legacy/CorruptViscosity.png similarity index 100% rename from Pictures/Legacy/CorruptViscocity.png rename to Pictures/Legacy/CorruptViscosity.png diff --git a/Pictures/Legacy/OcteractPixelLuck.png b/Pictures/Legacy/OcteractPixelLuck.png new file mode 100644 index 000000000..d94d5b9ae Binary files /dev/null and b/Pictures/Legacy/OcteractPixelLuck.png differ diff --git a/Pictures/Legacy/OcteractPixelLuck2.png b/Pictures/Legacy/OcteractPixelLuck2.png new file mode 100644 index 000000000..75e9d7bc2 Binary files /dev/null and b/Pictures/Legacy/OcteractPixelLuck2.png differ diff --git a/Pictures/Legacy/PixelAmbrosiaGeneration.png b/Pictures/Legacy/PixelAmbrosiaGeneration.png new file mode 100644 index 000000000..216e2cd24 Binary files /dev/null and b/Pictures/Legacy/PixelAmbrosiaGeneration.png differ diff --git a/Pictures/Legacy/PixelAmbrosiaGeneration2.png b/Pictures/Legacy/PixelAmbrosiaGeneration2.png new file mode 100644 index 000000000..2ec933d11 Binary files /dev/null and b/Pictures/Legacy/PixelAmbrosiaGeneration2.png differ diff --git a/Pictures/Legacy/PixelAmbrosiaGeneration3.png b/Pictures/Legacy/PixelAmbrosiaGeneration3.png new file mode 100644 index 000000000..1cef15d39 Binary files /dev/null and b/Pictures/Legacy/PixelAmbrosiaGeneration3.png differ diff --git a/Pictures/Legacy/PixelAmbrosiaLuck.png b/Pictures/Legacy/PixelAmbrosiaLuck.png new file mode 100644 index 000000000..edb13f79a Binary files /dev/null and b/Pictures/Legacy/PixelAmbrosiaLuck.png differ diff --git a/Pictures/Legacy/PixelAmbrosiaLuck2.png b/Pictures/Legacy/PixelAmbrosiaLuck2.png new file mode 100644 index 000000000..8f5f049f2 Binary files /dev/null and b/Pictures/Legacy/PixelAmbrosiaLuck2.png differ diff --git a/Pictures/Legacy/PixelAmbrosiaLuck3.png b/Pictures/Legacy/PixelAmbrosiaLuck3.png new file mode 100644 index 000000000..f397639a5 Binary files /dev/null and b/Pictures/Legacy/PixelAmbrosiaLuck3.png differ diff --git a/Pictures/Legacy/PixelBlueberry.png b/Pictures/Legacy/PixelBlueberry.png new file mode 100644 index 000000000..82caf946e Binary files /dev/null and b/Pictures/Legacy/PixelBlueberry.png differ diff --git a/Pictures/Legacy/PixelBlueberry2.png b/Pictures/Legacy/PixelBlueberry2.png new file mode 100644 index 000000000..5e76d46dd Binary files /dev/null and b/Pictures/Legacy/PixelBlueberry2.png differ diff --git a/Pictures/Legacy/PixelBlueberry3.png b/Pictures/Legacy/PixelBlueberry3.png new file mode 100644 index 000000000..1ea4db145 Binary files /dev/null and b/Pictures/Legacy/PixelBlueberry3.png differ diff --git a/Pictures/Legacy/PixelCubes.png b/Pictures/Legacy/PixelCubes.png new file mode 100644 index 000000000..4080f4e0c Binary files /dev/null and b/Pictures/Legacy/PixelCubes.png differ diff --git a/Pictures/Legacy/PixelFreeUpgradeImprovement.png b/Pictures/Legacy/PixelFreeUpgradeImprovement.png new file mode 100644 index 000000000..2021ebdda Binary files /dev/null and b/Pictures/Legacy/PixelFreeUpgradeImprovement.png differ diff --git a/Pictures/Legacy/PixelFreeUpgradeImprovement2.png b/Pictures/Legacy/PixelFreeUpgradeImprovement2.png new file mode 100644 index 000000000..b8df10430 Binary files /dev/null and b/Pictures/Legacy/PixelFreeUpgradeImprovement2.png differ diff --git a/Pictures/Legacy/PixelFreeUpgradeImprovement3.png b/Pictures/Legacy/PixelFreeUpgradeImprovement3.png new file mode 100644 index 000000000..88b7632cf Binary files /dev/null and b/Pictures/Legacy/PixelFreeUpgradeImprovement3.png differ diff --git a/Pictures/Legacy/PixelObtainium.png b/Pictures/Legacy/PixelObtainium.png new file mode 100644 index 000000000..efb8ffcf3 Binary files /dev/null and b/Pictures/Legacy/PixelObtainium.png differ diff --git a/Pictures/Legacy/PixelOfferings.png b/Pictures/Legacy/PixelOfferings.png new file mode 100644 index 000000000..ca88ab153 Binary files /dev/null and b/Pictures/Legacy/PixelOfferings.png differ diff --git a/Pictures/Legacy/PixelPixelGeneration.png b/Pictures/Legacy/PixelPixelGeneration.png new file mode 100644 index 000000000..0e8992bb7 Binary files /dev/null and b/Pictures/Legacy/PixelPixelGeneration.png differ diff --git a/Pictures/Legacy/PixelPixelGeneration2.png b/Pictures/Legacy/PixelPixelGeneration2.png new file mode 100644 index 000000000..5047d506e Binary files /dev/null and b/Pictures/Legacy/PixelPixelGeneration2.png differ diff --git a/Pictures/Legacy/PixelPixelGeneration3.png b/Pictures/Legacy/PixelPixelGeneration3.png new file mode 100644 index 000000000..10d679a9f Binary files /dev/null and b/Pictures/Legacy/PixelPixelGeneration3.png differ diff --git a/Pictures/Legacy/PixelPixelLuck.png b/Pictures/Legacy/PixelPixelLuck.png new file mode 100644 index 000000000..03f421a6c Binary files /dev/null and b/Pictures/Legacy/PixelPixelLuck.png differ diff --git a/Pictures/Legacy/PixelPixelLuckConverter.png b/Pictures/Legacy/PixelPixelLuckConverter.png new file mode 100644 index 000000000..e06876055 Binary files /dev/null and b/Pictures/Legacy/PixelPixelLuckConverter.png differ diff --git a/Pictures/Legacy/PixelPixelLuckConverter2.png b/Pictures/Legacy/PixelPixelLuckConverter2.png new file mode 100644 index 000000000..e06876055 Binary files /dev/null and b/Pictures/Legacy/PixelPixelLuckConverter2.png differ diff --git a/Pictures/Legacy/PixelQuarks.png b/Pictures/Legacy/PixelQuarks.png new file mode 100644 index 000000000..ade3b8857 Binary files /dev/null and b/Pictures/Legacy/PixelQuarks.png differ diff --git a/Pictures/Legacy/PixelRoleBonus.png b/Pictures/Legacy/PixelRoleBonus.png new file mode 100644 index 000000000..25534fcc0 Binary files /dev/null and b/Pictures/Legacy/PixelRoleBonus.png differ diff --git a/Pictures/Legacy/PixelTutorial.png b/Pictures/Legacy/PixelTutorial.png new file mode 100644 index 000000000..f36eb7c59 Binary files /dev/null and b/Pictures/Legacy/PixelTutorial.png differ diff --git a/Pictures/Legacy/PixelTwoMind.png b/Pictures/Legacy/PixelTwoMind.png new file mode 100644 index 000000000..3d3ff7414 Binary files /dev/null and b/Pictures/Legacy/PixelTwoMind.png differ diff --git a/Pictures/Legacy/SingularityPixelLuck.png b/Pictures/Legacy/SingularityPixelLuck.png new file mode 100644 index 000000000..573534a1f Binary files /dev/null and b/Pictures/Legacy/SingularityPixelLuck.png differ diff --git a/Pictures/Legacy/SingularityPixelLuck2.png b/Pictures/Legacy/SingularityPixelLuck2.png new file mode 100644 index 000000000..e7f182ea5 Binary files /dev/null and b/Pictures/Legacy/SingularityPixelLuck2.png differ diff --git a/Pictures/Legacy/UltimatePixel.png b/Pictures/Legacy/UltimatePixel.png new file mode 100644 index 000000000..489a46e15 Binary files /dev/null and b/Pictures/Legacy/UltimatePixel.png differ diff --git a/Pictures/Monotonous/CorruptSpatialDilation.png b/Pictures/Monotonous/CorruptDilation.png similarity index 100% rename from Pictures/Monotonous/CorruptSpatialDilation.png rename to Pictures/Monotonous/CorruptDilation.png diff --git a/Pictures/Monotonous/CorruptHyperchallenged.png b/Pictures/Monotonous/CorruptHyperchallenge.png similarity index 100% rename from Pictures/Monotonous/CorruptHyperchallenged.png rename to Pictures/Monotonous/CorruptHyperchallenge.png diff --git a/Pictures/Monotonous/CorruptScientificIlliteracy.png b/Pictures/Monotonous/CorruptIlliteracy.png similarity index 100% rename from Pictures/Monotonous/CorruptScientificIlliteracy.png rename to Pictures/Monotonous/CorruptIlliteracy.png diff --git a/Pictures/Monotonous/CorruptFinancialCollapse.png b/Pictures/Monotonous/CorruptRecession.png similarity index 100% rename from Pictures/Monotonous/CorruptFinancialCollapse.png rename to Pictures/Monotonous/CorruptRecession.png diff --git a/Pictures/Monotonous/CorruptViscocity.png b/Pictures/Monotonous/CorruptViscosity.png similarity index 100% rename from Pictures/Monotonous/CorruptViscocity.png rename to Pictures/Monotonous/CorruptViscosity.png diff --git a/Pictures/Monotonous/PixelAmbrosiaGeneration.png b/Pictures/Monotonous/PixelAmbrosiaGeneration.png new file mode 100644 index 000000000..216e2cd24 Binary files /dev/null and b/Pictures/Monotonous/PixelAmbrosiaGeneration.png differ diff --git a/Pictures/Monotonous/PixelAmbrosiaGeneration2.png b/Pictures/Monotonous/PixelAmbrosiaGeneration2.png new file mode 100644 index 000000000..2ec933d11 Binary files /dev/null and b/Pictures/Monotonous/PixelAmbrosiaGeneration2.png differ diff --git a/Pictures/Monotonous/PixelAmbrosiaGeneration3.png b/Pictures/Monotonous/PixelAmbrosiaGeneration3.png new file mode 100644 index 000000000..1cef15d39 Binary files /dev/null and b/Pictures/Monotonous/PixelAmbrosiaGeneration3.png differ diff --git a/Pictures/Monotonous/PixelAmbrosiaLuck.png b/Pictures/Monotonous/PixelAmbrosiaLuck.png new file mode 100644 index 000000000..edb13f79a Binary files /dev/null and b/Pictures/Monotonous/PixelAmbrosiaLuck.png differ diff --git a/Pictures/Monotonous/PixelAmbrosiaLuck2.png b/Pictures/Monotonous/PixelAmbrosiaLuck2.png new file mode 100644 index 000000000..8f5f049f2 Binary files /dev/null and b/Pictures/Monotonous/PixelAmbrosiaLuck2.png differ diff --git a/Pictures/Monotonous/PixelAmbrosiaLuck3.png b/Pictures/Monotonous/PixelAmbrosiaLuck3.png new file mode 100644 index 000000000..f397639a5 Binary files /dev/null and b/Pictures/Monotonous/PixelAmbrosiaLuck3.png differ diff --git a/Pictures/Monotonous/PixelBlueberry.png b/Pictures/Monotonous/PixelBlueberry.png new file mode 100644 index 000000000..82caf946e Binary files /dev/null and b/Pictures/Monotonous/PixelBlueberry.png differ diff --git a/Pictures/Monotonous/PixelBlueberry2.png b/Pictures/Monotonous/PixelBlueberry2.png new file mode 100644 index 000000000..5e76d46dd Binary files /dev/null and b/Pictures/Monotonous/PixelBlueberry2.png differ diff --git a/Pictures/Monotonous/PixelBlueberry3.png b/Pictures/Monotonous/PixelBlueberry3.png new file mode 100644 index 000000000..1ea4db145 Binary files /dev/null and b/Pictures/Monotonous/PixelBlueberry3.png differ diff --git a/Pictures/Monotonous/PixelCubes.png b/Pictures/Monotonous/PixelCubes.png new file mode 100644 index 000000000..4080f4e0c Binary files /dev/null and b/Pictures/Monotonous/PixelCubes.png differ diff --git a/Pictures/Monotonous/PixelFreeUpgradeImprovement.png b/Pictures/Monotonous/PixelFreeUpgradeImprovement.png new file mode 100644 index 000000000..2021ebdda Binary files /dev/null and b/Pictures/Monotonous/PixelFreeUpgradeImprovement.png differ diff --git a/Pictures/Monotonous/PixelFreeUpgradeImprovement2.png b/Pictures/Monotonous/PixelFreeUpgradeImprovement2.png new file mode 100644 index 000000000..b8df10430 Binary files /dev/null and b/Pictures/Monotonous/PixelFreeUpgradeImprovement2.png differ diff --git a/Pictures/Monotonous/PixelFreeUpgradeImprovement3.png b/Pictures/Monotonous/PixelFreeUpgradeImprovement3.png new file mode 100644 index 000000000..88b7632cf Binary files /dev/null and b/Pictures/Monotonous/PixelFreeUpgradeImprovement3.png differ diff --git a/Pictures/Monotonous/PixelObtainium.png b/Pictures/Monotonous/PixelObtainium.png new file mode 100644 index 000000000..efb8ffcf3 Binary files /dev/null and b/Pictures/Monotonous/PixelObtainium.png differ diff --git a/Pictures/Monotonous/PixelOfferings.png b/Pictures/Monotonous/PixelOfferings.png new file mode 100644 index 000000000..ca88ab153 Binary files /dev/null and b/Pictures/Monotonous/PixelOfferings.png differ diff --git a/Pictures/Monotonous/PixelPixelGeneration.png b/Pictures/Monotonous/PixelPixelGeneration.png new file mode 100644 index 000000000..0e8992bb7 Binary files /dev/null and b/Pictures/Monotonous/PixelPixelGeneration.png differ diff --git a/Pictures/Monotonous/PixelPixelGeneration2.png b/Pictures/Monotonous/PixelPixelGeneration2.png new file mode 100644 index 000000000..5047d506e Binary files /dev/null and b/Pictures/Monotonous/PixelPixelGeneration2.png differ diff --git a/Pictures/Monotonous/PixelPixelGeneration3.png b/Pictures/Monotonous/PixelPixelGeneration3.png new file mode 100644 index 000000000..10d679a9f Binary files /dev/null and b/Pictures/Monotonous/PixelPixelGeneration3.png differ diff --git a/Pictures/Monotonous/PixelPixelLuck.png b/Pictures/Monotonous/PixelPixelLuck.png new file mode 100644 index 000000000..03f421a6c Binary files /dev/null and b/Pictures/Monotonous/PixelPixelLuck.png differ diff --git a/Pictures/Monotonous/PixelPixelLuckConverter.png b/Pictures/Monotonous/PixelPixelLuckConverter.png new file mode 100644 index 000000000..e06876055 Binary files /dev/null and b/Pictures/Monotonous/PixelPixelLuckConverter.png differ diff --git a/Pictures/Monotonous/PixelPixelLuckConverter2.png b/Pictures/Monotonous/PixelPixelLuckConverter2.png new file mode 100644 index 000000000..e06876055 Binary files /dev/null and b/Pictures/Monotonous/PixelPixelLuckConverter2.png differ diff --git a/Pictures/Monotonous/PixelQuarks.png b/Pictures/Monotonous/PixelQuarks.png new file mode 100644 index 000000000..ade3b8857 Binary files /dev/null and b/Pictures/Monotonous/PixelQuarks.png differ diff --git a/Pictures/Monotonous/PixelRoleBonus.png b/Pictures/Monotonous/PixelRoleBonus.png new file mode 100644 index 000000000..25534fcc0 Binary files /dev/null and b/Pictures/Monotonous/PixelRoleBonus.png differ diff --git a/Pictures/Monotonous/PixelTutorial.png b/Pictures/Monotonous/PixelTutorial.png new file mode 100644 index 000000000..f36eb7c59 Binary files /dev/null and b/Pictures/Monotonous/PixelTutorial.png differ diff --git a/Pictures/Monotonous/PixelTwoMind.png b/Pictures/Monotonous/PixelTwoMind.png new file mode 100644 index 000000000..3d3ff7414 Binary files /dev/null and b/Pictures/Monotonous/PixelTwoMind.png differ diff --git a/Pictures/Simplified/CorruptSpatialDilation.png b/Pictures/Simplified/CorruptDilation.png similarity index 100% rename from Pictures/Simplified/CorruptSpatialDilation.png rename to Pictures/Simplified/CorruptDilation.png diff --git a/Pictures/Simplified/CorruptHyperchallenged.png b/Pictures/Simplified/CorruptHyperchallenge.png similarity index 100% rename from Pictures/Simplified/CorruptHyperchallenged.png rename to Pictures/Simplified/CorruptHyperchallenge.png diff --git a/Pictures/Simplified/CorruptScientificIlliteracy.png b/Pictures/Simplified/CorruptIlliteracy.png similarity index 100% rename from Pictures/Simplified/CorruptScientificIlliteracy.png rename to Pictures/Simplified/CorruptIlliteracy.png diff --git a/Pictures/Simplified/CorruptFinancialCollapse.png b/Pictures/Simplified/CorruptRecession.png similarity index 100% rename from Pictures/Simplified/CorruptFinancialCollapse.png rename to Pictures/Simplified/CorruptRecession.png diff --git a/Pictures/Simplified/CorruptViscocity.png b/Pictures/Simplified/CorruptViscosity.png similarity index 100% rename from Pictures/Simplified/CorruptViscocity.png rename to Pictures/Simplified/CorruptViscosity.png diff --git a/Pictures/Simplified/PixelAmbrosiaGeneration.png b/Pictures/Simplified/PixelAmbrosiaGeneration.png new file mode 100644 index 000000000..216e2cd24 Binary files /dev/null and b/Pictures/Simplified/PixelAmbrosiaGeneration.png differ diff --git a/Pictures/Simplified/PixelAmbrosiaGeneration2.png b/Pictures/Simplified/PixelAmbrosiaGeneration2.png new file mode 100644 index 000000000..2ec933d11 Binary files /dev/null and b/Pictures/Simplified/PixelAmbrosiaGeneration2.png differ diff --git a/Pictures/Simplified/PixelAmbrosiaGeneration3.png b/Pictures/Simplified/PixelAmbrosiaGeneration3.png new file mode 100644 index 000000000..1cef15d39 Binary files /dev/null and b/Pictures/Simplified/PixelAmbrosiaGeneration3.png differ diff --git a/Pictures/Simplified/PixelAmbrosiaLuck.png b/Pictures/Simplified/PixelAmbrosiaLuck.png new file mode 100644 index 000000000..edb13f79a Binary files /dev/null and b/Pictures/Simplified/PixelAmbrosiaLuck.png differ diff --git a/Pictures/Simplified/PixelAmbrosiaLuck2.png b/Pictures/Simplified/PixelAmbrosiaLuck2.png new file mode 100644 index 000000000..8f5f049f2 Binary files /dev/null and b/Pictures/Simplified/PixelAmbrosiaLuck2.png differ diff --git a/Pictures/Simplified/PixelAmbrosiaLuck3.png b/Pictures/Simplified/PixelAmbrosiaLuck3.png new file mode 100644 index 000000000..f397639a5 Binary files /dev/null and b/Pictures/Simplified/PixelAmbrosiaLuck3.png differ diff --git a/Pictures/Simplified/PixelBlueberry.png b/Pictures/Simplified/PixelBlueberry.png new file mode 100644 index 000000000..82caf946e Binary files /dev/null and b/Pictures/Simplified/PixelBlueberry.png differ diff --git a/Pictures/Simplified/PixelBlueberry2.png b/Pictures/Simplified/PixelBlueberry2.png new file mode 100644 index 000000000..5e76d46dd Binary files /dev/null and b/Pictures/Simplified/PixelBlueberry2.png differ diff --git a/Pictures/Simplified/PixelBlueberry3.png b/Pictures/Simplified/PixelBlueberry3.png new file mode 100644 index 000000000..1ea4db145 Binary files /dev/null and b/Pictures/Simplified/PixelBlueberry3.png differ diff --git a/Pictures/Simplified/PixelCubes.png b/Pictures/Simplified/PixelCubes.png new file mode 100644 index 000000000..4080f4e0c Binary files /dev/null and b/Pictures/Simplified/PixelCubes.png differ diff --git a/Pictures/Simplified/PixelFreeUpgradeImprovement.png b/Pictures/Simplified/PixelFreeUpgradeImprovement.png new file mode 100644 index 000000000..2021ebdda Binary files /dev/null and b/Pictures/Simplified/PixelFreeUpgradeImprovement.png differ diff --git a/Pictures/Simplified/PixelFreeUpgradeImprovement2.png b/Pictures/Simplified/PixelFreeUpgradeImprovement2.png new file mode 100644 index 000000000..b8df10430 Binary files /dev/null and b/Pictures/Simplified/PixelFreeUpgradeImprovement2.png differ diff --git a/Pictures/Simplified/PixelFreeUpgradeImprovement3.png b/Pictures/Simplified/PixelFreeUpgradeImprovement3.png new file mode 100644 index 000000000..88b7632cf Binary files /dev/null and b/Pictures/Simplified/PixelFreeUpgradeImprovement3.png differ diff --git a/Pictures/Simplified/PixelObtainium.png b/Pictures/Simplified/PixelObtainium.png new file mode 100644 index 000000000..efb8ffcf3 Binary files /dev/null and b/Pictures/Simplified/PixelObtainium.png differ diff --git a/Pictures/Simplified/PixelOfferings.png b/Pictures/Simplified/PixelOfferings.png new file mode 100644 index 000000000..ca88ab153 Binary files /dev/null and b/Pictures/Simplified/PixelOfferings.png differ diff --git a/Pictures/Simplified/PixelPixelGeneration.png b/Pictures/Simplified/PixelPixelGeneration.png new file mode 100644 index 000000000..0e8992bb7 Binary files /dev/null and b/Pictures/Simplified/PixelPixelGeneration.png differ diff --git a/Pictures/Simplified/PixelPixelGeneration2.png b/Pictures/Simplified/PixelPixelGeneration2.png new file mode 100644 index 000000000..5047d506e Binary files /dev/null and b/Pictures/Simplified/PixelPixelGeneration2.png differ diff --git a/Pictures/Simplified/PixelPixelGeneration3.png b/Pictures/Simplified/PixelPixelGeneration3.png new file mode 100644 index 000000000..10d679a9f Binary files /dev/null and b/Pictures/Simplified/PixelPixelGeneration3.png differ diff --git a/Pictures/Simplified/PixelPixelLuck.png b/Pictures/Simplified/PixelPixelLuck.png new file mode 100644 index 000000000..03f421a6c Binary files /dev/null and b/Pictures/Simplified/PixelPixelLuck.png differ diff --git a/Pictures/Simplified/PixelPixelLuckConverter.png b/Pictures/Simplified/PixelPixelLuckConverter.png new file mode 100644 index 000000000..e06876055 Binary files /dev/null and b/Pictures/Simplified/PixelPixelLuckConverter.png differ diff --git a/Pictures/Simplified/PixelPixelLuckConverter2.png b/Pictures/Simplified/PixelPixelLuckConverter2.png new file mode 100644 index 000000000..e06876055 Binary files /dev/null and b/Pictures/Simplified/PixelPixelLuckConverter2.png differ diff --git a/Pictures/Simplified/PixelQuarks.png b/Pictures/Simplified/PixelQuarks.png new file mode 100644 index 000000000..ade3b8857 Binary files /dev/null and b/Pictures/Simplified/PixelQuarks.png differ diff --git a/Pictures/Simplified/PixelRoleBonus.png b/Pictures/Simplified/PixelRoleBonus.png new file mode 100644 index 000000000..25534fcc0 Binary files /dev/null and b/Pictures/Simplified/PixelRoleBonus.png differ diff --git a/Pictures/Simplified/PixelTutorial.png b/Pictures/Simplified/PixelTutorial.png new file mode 100644 index 000000000..f36eb7c59 Binary files /dev/null and b/Pictures/Simplified/PixelTutorial.png differ diff --git a/Pictures/Simplified/PixelTwoMind.png b/Pictures/Simplified/PixelTwoMind.png new file mode 100644 index 000000000..3d3ff7414 Binary files /dev/null and b/Pictures/Simplified/PixelTwoMind.png differ diff --git a/Synergism.css b/Synergism.css index e170d65e9..b1adebb1d 100644 --- a/Synergism.css +++ b/Synergism.css @@ -148,6 +148,12 @@ body.loading { background-color: var(--box-color); } +.pixelBoxColor { + border: 3px solid; + border-color: var(--red-text-color); + background-color: var(--box-color); +} + a { color: white; text-decoration: none; @@ -321,7 +327,8 @@ body button:active { background-color: var(--hover-color); } -#confirmationBox { +#confirmationBox, +#captchaHolder { display: none; position: fixed; top: 50vh; @@ -1961,7 +1968,8 @@ p#reincarnatehotkeys { #goldenQuarksDisplay, #octeractsDisplay, #totalOcteractsDisplay, -#ambrosiaDisplay { +#ambrosiaDisplay, +#ultimatePixelDisplay { display: flex; flex-direction: row; align-items: center; @@ -1993,7 +2001,8 @@ p#reincarnatehotkeys { margin-left: 5px; } -#ambrosiaAmount { +#ambrosiaAmount, +#ultimatePixelAmount { font-size: 1.2em; margin-left: 5px; } @@ -3523,7 +3532,8 @@ header #obtainiumDisplay { color: pink; } #singularityUpgradeContainer, #singularityOcteracts, -#singularityAmbrosia { +#singularityAmbrosia, +#singularityUltimatePixels { display: flex; flex-direction: column; align-items: center; @@ -3531,7 +3541,9 @@ header #obtainiumDisplay { color: pink; } #actualSingularityUpgradeContainer, #octeractUpgradeContainer, -#blueberryUpgradeContainer { +#blueberryUpgradeContainer, +#pixelUpgradeContainer { + position: relative; display: flex; flex-wrap: wrap; justify-content: center; @@ -3557,7 +3569,8 @@ header #obtainiumDisplay { color: pink; } .singularityUpgrade, .octeractUpgrade, .singularityChallenge, -.blueberryUpgrade { +.blueberryUpgrade, +.pixelUpgrade { font-size: 0; cursor: pointer; } @@ -3789,6 +3802,12 @@ img#singularityPerksIcon { text-align: center; } +#testing { + position: relative; + padding: 0; + text-align: center; +} + @keyframes rotation { from { transform: rotate(0deg); @@ -3872,6 +3891,36 @@ img#singularityPerksIcon { image-rendering: auto; } +#metaPixelProgressBar { + width: 25%; + height: 30px; + background-color: black; + border: solid white; + border-radius: 5px; + box-shadow: 0 1px 3px rgb(0 0 0 / 20%); + position: relative; +} + +#metaPixelProgress { + height: 100%; + background: linear-gradient(to right, #ff5e0f, orange); + border-radius: 0; + transition: width 0.4s ease; +} + +#metaPixelProgressText { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; /* Center the text vertically */ + justify-content: center; /* Center the text horizontally */ + color: white; + font-weight: bold; +} + #pixelProgressBar { width: 25%; height: 30px; @@ -3885,7 +3934,7 @@ img#singularityPerksIcon { #pixelProgress { height: 100%; background: linear-gradient(to right, maroon, red); - border-radius: 5px; + border-radius: 0; transition: width 0.4s ease; } @@ -3936,3 +3985,91 @@ form input:hover { background-color: var(--hover-color); cursor: pointer; } + +#pixelTextBox { + visibility: hidden; + width: 500px; + background-color: black; + color: white; + text-align: center; + border-radius: 5px; + border: 3px solid gold; + justify-content: center; + position: absolute; + z-index: 1; + left: 50%; + transform: translateX(-50%); + box-shadow: 0 8px 16px 0 rgb(0 0 0 / 20%); +} + +#pixelTextBox p { + padding: 0; + margin: 0 12px; +} + +#pixelUpgradeName { + font-size: 1.1em; + color: gold; +} + +#pixelUpgradeDescription { + border: 1px gold; + border-style: none none solid; + padding: 0 8px; + margin: 0 8px; +} + +.pixelBarBonus { + display: flex; + flex-direction: row; + align-items: center; + z-index: 3; + margin-bottom: 2px; +} + +.pixelBarBonus > p { + display: flex; + z-index: 5; +} + +#pixelBarLevelBonusTextBox { + visibility: hidden; + width: 500px; + background-color: black; + color: white; + text-align: center; + border-radius: 5px; + border: 3px solid red; + justify-content: center; + position: absolute; + z-index: 1; + left: 50%; + transform: translateX(-50%); + box-shadow: 0 8px 16px 0 rgb(0 0 0 / 20%); +} + +#pixelBarLevelBonusTextBox div { + padding: 0; + margin: 0 12px; +} + +.pixelBarBonus p { + padding: 0; + margin: 0 12px; +} + +#goldenQuarkResetFunction { + padding: 3; + margin: 3 3px; + cursor: pointer; +} + +#ascSingularityCountStats { + cursor: pointer; +} + +#captchaHolder > .cf-turnstile { + max-width: fit-content; + max-height: fit-content; + margin: auto; +} diff --git a/index.html b/index.html index 960f08b84..c4a1f29df 100644 --- a/index.html +++ b/index.html @@ -16,9 +16,15 @@ Synergism + + +
+
+
+
@@ -106,6 +112,14 @@
+
+ + +
+
+ + +
@@ -873,9 +887,13 @@ Notification +
+ + +
-
- +
+
@@ -903,20 +921,6 @@ - - - - - - - - - - - - - - @@ -945,20 +949,6 @@ - - - - - - - - - - - - - - @@ -987,20 +977,6 @@ - - - - - - - - - - - - - - @@ -1029,20 +1005,6 @@ - - - - - - - - - - - - - - @@ -1071,20 +1033,6 @@ - - - - - - - - - - - - - - @@ -1113,20 +1061,6 @@ - - - - - - - - - - - - - - @@ -1155,23 +1089,139 @@ - - - - - - - - - - - - - -
ach1 ach8ach141 ach169 ach176ach183ach190ach197ach204ach211ach218ach225ach232ach239ach246ach253ach260ach267ach274
ach2 ach177ach184ach191ach198ach205ach212ach219ach226ach233ach240ach247ach254ach261ach268ach275
ach3 ach171 ach178ach185ach192ach199ach206ach213ach220ach227ach234ach241ach248ach255ach262ach269ach276
ach4 ach172 ach179ach186ach193ach200ach207ach214ach221ach228ach235ach242ach249ach256ach263ach270ach277
ach5 ach173 ach180ach187ach194ach201ach208ach215ach222ach229ach236ach243ach250ach257ach264ach271ach278
ach6 ach181ach188ach195ach202ach209ach216ach223ach230ach237ach244ach251ach258ach265ach272ach279
ach7 ach182ach189ach196ach203ach210ach217ach224ach231ach238ach245ach252ach259ach266ach273ach280
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ach183ach190ach197ach204ach211ach218ach225ach232ach239ach246ach253ach260ach267ach274ach281ach288
ach184ach191ach198ach205ach212ach219ach226ach233ach240ach247ach254ach261ach268ach275ach282ach289
ach185ach192ach199ach206ach213ach220ach227ach234ach241ach248ach255ach262ach269ach276ach283ach290
ach186ach193ach200ach207ach214ach221ach228ach235ach242ach249ach256ach263ach270ach277ach284ach291
ach187ach194ach201ach208ach215ach222ach229ach236ach243ach250ach257ach264ach271ach278ach285ach292
ach188ach195ach202ach209ach216ach223ach230ach237ach244ach251ach258ach265ach272ach279ach286ach293
ach189ach196ach203ach210ach217ach224ach231ach238ach245ach252ach259ach266ach273ach280ach287ach294
+

@@ -2790,16 +2840,10 @@
- - - - - - - + - - + + @@ -2807,11 +2851,17 @@ - - + + - + + + + + + +
@@ -2820,28 +2870,28 @@ - + - + - + - + - + - + - + - + @@ -3068,6 +3118,8 @@

Artists

+ +
@@ -3155,8 +3207,10 @@

Artists

Offering Electrolosis [OC]: 0

RNG-Based Offering Multiplier: 0

20 Ascensions X20 [EXALT ONLY]: 0

-

Shop EX ULTIMATE: 0

-

Event: 0

+

20 Ascensions X20 [EXALT ONLY]: 0

+

20 Ascensions X20 [EXALT ONLY]: 0

+

Shop EX ULTIMATE: 0

+

Event: 0

TOTAL OFFERING MULTIPLIER: 0

@@ -3569,6 +3626,10 @@

Artists

a0

a0

a0

+

a0

+

a0

+

a0

+

a0

Multipliers (Additive)0

TOTAL AMBROSIA LUCK: 0

@@ -3586,10 +3647,38 @@

Artists

a0

a0

a0

+

a0

+

a0

+

a0

+

a0

BLUEBERRY TIME /S: 0

+
+

Pixel Luck

+

aA

+

aA

+

aA

+

aA

+

aA

+

aA

+

aA

+

aA

+

aA

+

aA

+

Multipliers (Additive)0

+

TOTAL PIXEL LUCK: + 0

+
+ +
+

Pixel Generation

+

aA

+

PIXEL GENERATION /S: + 0

+
+
@@ -4069,7 +4158,9 @@

Artists

- + + +
@@ -4078,6 +4169,9 @@

Artists

+
+

Set your Singularity here! [WIP Box to be replaced with an icon]

+

@@ -4286,6 +4380,12 @@

Artists

+
+ +
+
+ +
@@ -4442,6 +4542,12 @@

Artists

+
+ +
+
+ +
@@ -4457,9 +4563,7 @@

Artists

-

-

@@ -4467,10 +4571,6 @@

Artists

EVAL 492942 + 4294256! -
-
- EVAL 492942 + 4294256! -
@@ -4499,6 +4599,9 @@

Artists

+
+ +
@@ -4530,6 +4633,14 @@

Artists

+
+ +
+
+
+
+ +
@@ -4554,6 +4665,142 @@

Artists

+
@@ -4561,5 +4808,19 @@

Artists

+ +
+

Welcome to the exclusive testing realm!

+ + + + +
diff --git a/package.json b/package.json index 919689051..9ad6c7209 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "break_infinity.js": "^2.0.0", "clipboard": "^2.0.11", "eventemitter3": "^4.0.7", + "fast-mersenne-twister": "^1.0.3", "i18next": "^22.4.9", "localforage": "^1.10.0", "lodash.clonedeepwith": "^4.5.0", @@ -17,6 +18,7 @@ }, "devDependencies": { "@biomejs/biome": "^1.4.1", + "@types/cloudflare-turnstile": "^0.2.2", "@types/lodash.clonedeepwith": "^4.5.9", "@types/lz-string": "^1.3.34", "deep-object-diff": "^1.1.9", diff --git a/src/Achievements.ts b/src/Achievements.ts index 95ad7cbc9..ca05eba63 100644 --- a/src/Achievements.ts +++ b/src/Achievements.ts @@ -50,7 +50,9 @@ export const achievementpointvalues = [ 50, 75, 75, 75, 100, 100, 150, 50, 75, 75, 75, 100, 100, 150, 50, 75, 75, 75, 100, 100, 150, - 10, 10, 20, 20, 30, 40, 50 + 10, 10, 20, 20, 30, 40, 50, + 20, 30, 40, 50, 60, 70, 80, + 20, 30, 40, 50, 60, 70, 80 ] export const totalachievementpoints = achievementpointvalues.reduce((a, b) => a + b, 0) @@ -114,7 +116,8 @@ export const areward = (i: number): string => { 140, 141, 147, 171, 172, 173, 176, 177, 178, 179, 180, 181, 182, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209, 211, 212, 213, 214, 215, 218, - 219, 220, 221, 222, 250, 251, 253, 259, 260, 261 + 219, 220, 221, 222, 250, 251, 253, 259, 260, 261, + 284, 285, 286, 287, 289, 291, 293, 294, ] if (descs.includes(i) || i in extra) { @@ -307,7 +310,8 @@ export const challengeachievementcheck = (i: number, auto?: boolean) => { } if ( - player.challengecompletions[10] >= 50 && i === 11 && player.usedCorruptions[7] >= 5 && player.achievements[247] < 1 + player.challengecompletions[10] >= 50 && i === 11 && player.corruptions.used.getLevel('drought') >= 5 + && player.achievements[247] < 1 ) { achievementaward(247) } diff --git a/src/Ants.ts b/src/Ants.ts index 3b025319f..c105d2612 100644 --- a/src/Ants.ts +++ b/src/Ants.ts @@ -282,7 +282,7 @@ export const antUpgradeDescription = (i: number) => { x: format( Decimal.pow( G.antUpgradeCostIncreases[i - 1], - player.antUpgrades[i - 1]! * G.extinctionMultiplier[player.usedCorruptions[10]] + player.antUpgrades[i - 1]! * player.corruptions.used.corruptionEffects('extinction') ).times(G.antUpgradeBaseCost[i - 1]) ) }) diff --git a/src/BlueberryUpgrades.ts b/src/BlueberryUpgrades.ts index 246bf7682..01446f1fe 100644 --- a/src/BlueberryUpgrades.ts +++ b/src/BlueberryUpgrades.ts @@ -1,6 +1,11 @@ import i18next from 'i18next' import { DOMCacheGetOrSet } from './Cache/DOM' -import { calculateAmbrosiaGenerationSpeed, calculateAmbrosiaLuck } from './Calculate' +import { + calculateAdditiveLuckMult, + calculateAmbrosiaGenerationSpeed, + calculateAmbrosiaLuck, + calculatePixelLuck +} from './Calculate' import { DynamicUpgrade } from './DynamicUpgrade' import type { IUpgradeData } from './DynamicUpgrade' import { exportData, saveFilename } from './ImportExport' @@ -27,6 +32,8 @@ export type blueberryUpgradeNames = | 'ambrosiaLuck2' | 'ambrosiaObtainium1' | 'ambrosiaOffering1' + | 'ambrosiaPixelLuck' + | 'ambrosiaPixelLuck2' export type BlueberryOpt = Partial> export type BlueberryLoadoutMode = 'saveTree' | 'loadTree' @@ -750,6 +757,89 @@ export const blueberryUpgradeData: Record< ) } } + }, + ambrosiaPixelLuck: { + maxLevel: 10, + costPerLevel: 50, + blueberryCost: 1, + costFormula: (level: number, baseCost: number): number => { + return (baseCost * (Math.pow(level + 1, 4) - Math.pow(level, 4))) + }, + rewards: (n: number) => { + const pixelLuck = n + return { + pixelLuck: 2 * n, + desc: String(i18next.t('ambrosia.data.ambrosiaPixelLuck.effect', { + pixelLuck: pixelLuck + })) + } + }, + prerequisites: { + ambrosiaTutorial: 10 + }, + cacheUpdates: [ + () => { + G.pixelCurrStats.pixelLuck = calculatePixelLuck().value + } + ] + }, + ambrosiaPixelLuck2: { + maxLevel: 20, + costPerLevel: 300, + blueberryCost: 2, + costFormula: (level: number, baseCost: number): number => { + return (baseCost * (Math.pow(level + 1, 3) - Math.pow(level, 3))) + }, + rewards: (n: number) => { + const pixelLuck = n + return { + pixelLuck: 3 * n, + desc: String(i18next.t('ambrosia.data.ambrosiaPixelLuck2.effect', { + pixelLuck: pixelLuck + })) + } + }, + prerequisites: { + ambrosiaLuck1: 80, + ambrosiaPixelLuck: 8 + }, + cacheUpdates: [ + () => { + G.pixelCurrStats.pixelLuck = calculatePixelLuck().value + } + ] + }, + ambrosiaLuckDilator: { + maxLevel: 5, + costPerLevel: 100000, + blueberryCost: 2, + costFormula: (level: number, baseCost: number): number => { + return (baseCost * (Math.pow(level + 1, 2) - Math.pow(level, 2))) + }, + rewards: (n: number) => { + const ambrosiaLuckMult = 0.6 * +(n > 0) + (+(n > 1) * (n - 1) / 10) + return { + ambrosiaLuckMult: ambrosiaLuckMult, + desc: String(i18next.t('ambrosia.data.ambrosiaLuckDilator.effect', { + ambrosiaLuckMult: format(100 * ambrosiaLuckMult, 0, true) + })) + } + }, + prerequisites: { + ambrosiaTutorial: 10, + ambrosiaLuck1: 100 + }, + cacheUpdates: [ + () => { + G.ambrosiaCurrStats.ambrosiaLuck = calculateAmbrosiaLuck().value + }, + () => { + G.ambrosiaCurrStats.ambrosiaAdditiveLuckMult = calculateAdditiveLuckMult().value + }, + () => { + G.ambrosiaCurrStats.ambrosiaGenerationSpeed = calculateAmbrosiaGenerationSpeed().value + } + ] } } diff --git a/src/Calculate.ts b/src/Calculate.ts index 700077ac7..dce3a0d6f 100644 --- a/src/Calculate.ts +++ b/src/Calculate.ts @@ -3,10 +3,12 @@ import i18next from 'i18next' import { achievementaward } from './Achievements' import { DOMCacheGetOrSet } from './Cache/DOM' import { CalcECC } from './Challenges' +import type { Corruptions } from './Corruptions' import { BuffType, calculateEventSourceBuff } from './Event' import { addTimers, automaticTools } from './Helper' import { hepteractEffective } from './Hepteracts' import { disableHotkeys, enableHotkeys } from './Hotkeys' +import { computeMetaBarLevel } from './PixelUpgrades' import { getQuarkBonus, quarkHandler } from './Quark' import { reset } from './Reset' import { calculateSingularityDebuff } from './singularity' @@ -232,7 +234,7 @@ export function calculateRuneExpGiven ( // Corruption Divisor const droughtEffect = 1 / Math.pow( - G.droughtMultiplier[player.usedCorruptions[8]], + player.corruptions.used.corruptionEffects('drought'), 1 - (1 / 2) * player.platonicUpgrades[13] ) @@ -311,7 +313,7 @@ export const calculateRuneExpToLevel = ( multiplier = Math.pow(100, runeLevel) } if (runeIndex === 6) { - multiplier = Math.pow(1e25, runeLevel) * (player.highestSingularityCount + 1) + multiplier = Math.pow(1e25, runeLevel) * (player.singularityCount + 1) } return multiplier * G.runeexpbase[runeIndex] } @@ -497,6 +499,8 @@ export function calculateOfferings ( 1 + player.cubeUpgrades[54] / 100, // Cube upgrade 6x4 (Cx4) +player.octeractUpgrades.octeractOfferings1.getEffect().bonus, // Offering Electrolosis OC Upgrade 1 + 0.001 * +player.blueberryUpgrades.ambrosiaOffering1.bonus.offeringMult, // Ambrosia!! + calculatePixelBarLevelBonuses().OfferingMult, + +player.pixelUpgrades.pixelOfferings.bonus.offerings, calculateEXALTBonusMult(), // 20 Ascensions X20 Bonus [EXALT ONLY] calculateEXUltraOfferingBonus(), // EX Ultra Shop Upgrade 1 + calculateEventBuff(BuffType.Offering) // Event @@ -636,7 +640,7 @@ export const calculateObtainium = () => { G.obtainiumGain, Math.min( 1, - G.illiteracyPower[player.usedCorruptions[5]] + player.corruptions.used.corruptionEffects('illiteracy') * (1 + (9 / 100) * player.platonicUpgrades[9] @@ -678,6 +682,8 @@ export const calculateObtainium = () => { G.obtainiumGain *= calculateEXUltraObtainiumBonus() G.obtainiumGain *= calculateEXALTBonusMult() + G.obtainiumGain *= calculatePixelBarLevelBonuses().ObtainiumMult + G.obtainiumGain *= +player.pixelUpgrades.pixelObtainium.bonus.obtainium if (!isFinite(G.obtainiumGain)) { G.obtainiumGain = 1e300 @@ -685,10 +691,10 @@ export const calculateObtainium = () => { G.obtainiumGain = Math.min(1e300, G.obtainiumGain) G.obtainiumGain /= calculateSingularityDebuff('Obtainium') - if (player.usedCorruptions[5] >= 15) { + if (player.corruptions.used.getLevel('illiteracy') >= 15) { G.obtainiumGain = Math.pow(G.obtainiumGain, 1 / 4) } - if (player.usedCorruptions[5] >= 16) { + if (player.corruptions.used.getLevel('illiteracy') >= 16) { G.obtainiumGain = Math.pow(G.obtainiumGain, 1 / 3) } @@ -1396,7 +1402,9 @@ export const calculateOffline = async (forceTime = 0) => { ants: timeAdd * G.timeMultiplier, antsReal: timeAdd, ascension: player.ascensionCounter, // Calculate this after the fact - quarks: quarkHandler().gain // Calculate this after the fact + quarks: quarkHandler().gain, // Calculate this after the fact + ambrosia: player.lifetimeAmbrosia, + pixels: player.ultimatePixels } cacheReinitialize() @@ -1407,12 +1415,15 @@ export const calculateOffline = async (forceTime = 0) => { addTimers('singularity', timeAdd) addTimers('octeracts', timeTick) addTimers('ambrosia', timeAdd) + addTimers('pixel', timeAdd) player.prestigeCount += resetAdd.prestige player.transcendCount += resetAdd.transcension player.reincarnationCount += resetAdd.reincarnation timerAdd.ascension = player.ascensionCounter - timerAdd.ascension timerAdd.quarks = quarkHandler().gain - timerAdd.quarks + timerAdd.ambrosia = player.lifetimeAmbrosia - timerAdd.ambrosia + timerAdd.pixels = player.ultimatePixels - timerAdd.pixels // 200 simulated all ticks [July 12, 2021] const runOffline = setInterval(() => { @@ -1528,6 +1539,18 @@ export const calculateOffline = async (forceTime = 0) => { value: format(timerAdd.quarks, 0, true) } ) + DOMCacheGetOrSet('offlineAmbrosiaCount').innerHTML = i18next.t( + 'offlineProgress.lifetimeAmbrosia', + { + value: format(timerAdd.ambrosia, 0, true) + } + ) + DOMCacheGetOrSet('offlinePixelCount').innerHTML = i18next.t( + 'offlineProgress.pixels', + { + value: format(timerAdd.pixels, 0, true) + } + ) DOMCacheGetOrSet('progressbardescription').textContent = i18next.t( 'calculate.offlineEarnings' @@ -1751,6 +1774,12 @@ export const calculateAllCubeMultiplier = () => { calculateTotalOcteractCubeBonus(), // No Singularity Upgrades Challenge +player.singularityChallenges.noSingularityUpgrades.rewards.cubes, + // Pixel Tutorial + +player.pixelUpgrades.pixelTutorial.bonus.cubes, + // Pixel Bar Level + calculatePixelBarLevelBonuses().CubeMult, + // Pixel Upgrade: Cubes!!! + +player.pixelUpgrades.pixelCubes.bonus.cubes, // Singularity Citadel +player.singularityUpgrades.singCitadel.getEffect().bonus, // Singularity Citadel 2 @@ -1856,7 +1885,7 @@ export const calculateCubeMultiplier = (score = -1) => { // Platonic 1x1 1 + 0.00009 - * sumContents(player.usedCorruptions) + * player.corruptions.used.totalLevels * player.platonicUpgrades[1], // Cube Upgrade 63 (Cx13) 1 @@ -1878,7 +1907,7 @@ export const calculateTesseractMultiplier = (score = -1) => { score = calculateAscensionScore().effectiveScore } - const corrSum = sumContents(player.usedCorruptions.slice(2, 10)) + const corrSum = player.corruptions.used.totalLevels const arr = [ // Ascension Score Multiplier Math.pow(1 + Math.max(0, score - 1e5) / 1e4, 0.35), @@ -1963,7 +1992,7 @@ export const calculateHypercubeMultiplier = (score = -1) => { // Platonic Upgrade 1x3 1 + 0.00054 - * sumContents(player.usedCorruptions) + * player.corruptions.used.totalLevels * player.platonicUpgrades[3], // Hyperreal Hepteract Bonus 1 + (0.6 / 1000) * hepteractEffective('hyperrealism') @@ -2059,7 +2088,7 @@ export const calculateHepteractMultiplier = (score = -1) => { } export const getOcteractValueMultipliers = () => { - const corruptionLevelSum = sumContents(player.usedCorruptions.slice(2, 10)) + const corruptionLevelSum = player.corruptions.used.totalLevels return [ 1 + (1.5 * player.shopUpgrades.seasonPass3) / 100, 1 + (0.75 * player.shopUpgrades.seasonPassY) / 100, @@ -2201,7 +2230,7 @@ export const calculateTimeAcceleration = () => { // Global Speed softcap + Corruption / Corruption-like effects const corruptionArr: number[] = [ - G.lazinessMultiplier[player.usedCorruptions[3]] // Corruption: Spacial Dilation + player.corruptions.used.corruptionEffects('dilation') // Corruption: Spacial Dilation ] const corruptableTimeMult = productContents(preCorruptionArr) * corruptionArr[0] // DR applies after base corruption. @@ -2242,7 +2271,7 @@ export const calculateTimeAcceleration = () => { * productContents(corruptionArr) * productContents(postCorruptionArr) - if (player.usedCorruptions[3] >= 6 && player.achievements[241] < 1) { + if (player.corruptions.used.getLevel('dilation') >= 6 && player.achievements[241] < 1) { achievementaward(241) } if (timeMult > 3600 && player.achievements[242] < 1) { @@ -2284,7 +2313,7 @@ export const calculateAscensionSpeedMultiplier = () => { + Math.min(0.1, (1 / 100) * Math.log10(player.ascensionCount + 1)) * player.achievements[263], // Achievement 263 Bonus 1 - + 0.002 * sumContents(player.usedCorruptions) * player.platonicUpgrades[15], // Platonic Omega + + 0.002 * player.corruptions.used.totalLevels * player.platonicUpgrades[15], // Platonic Omega G.challenge15Rewards.ascensionSpeed, // Challenge 15 Reward 1 + (1 / 400) * player.cubeUpgrades[59], // Cookie Upgrade 9 1 @@ -2350,13 +2379,13 @@ export const calculateSingularityQuarkMilestoneMultiplier = () => { 220, 225, 250, 255, 260, 261, 262, ]; for (const sing of singThresholds) { - if (player.highestSingularityCount >= sing) { + if (player.singularityCount >= sing) { multiplier *= 1.05 } } - if (player.highestSingularityCount >= 200) { - multiplier *= Math.pow((player.highestSingularityCount - 179) / 20, 2) + if (player.singularityCount >= 200) { + multiplier *= Math.pow((player.singularityCount - 179) / 20, 2) } return multiplier @@ -2456,6 +2485,9 @@ export const calculateQuarkMultiplier = () => { multiplier *= +player.blueberryUpgrades.ambrosiaLuckQuark1.bonus.quarks multiplier *= +player.blueberryUpgrades.ambrosiaQuarks2.bonus.quarks multiplier *= calculateCashGrabQuarkBonus() + multiplier *= +player.pixelUpgrades.pixelTutorial.bonus.quarks + multiplier *= calculatePixelBarLevelBonuses().QuarkMult + multiplier *= +player.pixelUpgrades.pixelQuarks.bonus.quarks if (player.highestSingularityCount === 0) { multiplier *= 1.25 @@ -2476,13 +2508,13 @@ export const calculateGoldenQuarkMultiplier = (computeMultiplier = false) => { } let perkMultiplier = 1 - if (player.highestSingularityCount >= 200) { + if (player.singularityCount >= 200) { perkMultiplier = 3 } - if (player.highestSingularityCount >= 208) { + if (player.singularityCount >= 208) { perkMultiplier = 5 } - if (player.highestSingularityCount >= 221) { + if (player.singularityCount >= 221) { perkMultiplier = 8 } @@ -2494,8 +2526,8 @@ export const calculateGoldenQuarkMultiplier = (computeMultiplier = false) => { +player.singularityChallenges.noSingularityUpgrades.rewards.goldenQuarks, // No Singularity Upgrades 1 + calculateEventBuff(BuffType.GoldenQuark), // Event 1 + getFastForwardTotalMultiplier(), // Singularity Fast Forwards - player.highestSingularityCount >= 100 - ? 1 + Math.min(1, player.highestSingularityCount / 250) + player.singularityCount >= 100 + ? 1 + Math.min(1, player.singularityCount / 250) : 1, // Golden Revolution II perkMultiplier // Immaculate Alchemy ] @@ -2521,13 +2553,10 @@ export const calculateGoldenQuarkGain = (computeMultiplier = false): number => { export const calculateCorruptionPoints = () => { let basePoints = 400 - const bonusLevel = player.singularityUpgrades.corruptionFifteen.getEffect() - .bonus - ? 1 - : 0 - for (let i = 1; i <= 9; i++) { - basePoints += 16 * Math.pow(player.usedCorruptions[i] + bonusLevel, 2) + for (const corr in player.corruptions.used) { + const corrKey = corr as keyof Corruptions + basePoints += 16 * Math.pow(player.corruptions.used.getLevel(corrKey) + player.corruptions.used.getBonusLevel(), 2) } return basePoints @@ -2804,30 +2833,8 @@ export const calculateAscensionScore = () => { + 0.0025 * (player.platonicUpgrades[5] + player.platonicUpgrades[10]), player.highestchallengecompletions[10] ) - // Corruption Multiplier is the product of all Corruption Score multipliers based on used corruptions - let bonusVal = player.singularityUpgrades.advancedPack.getEffect().bonus - ? 0.33 - : 0 - bonusVal += +player.singularityChallenges.oneChallengeCap.rewards.corrScoreIncrease - for (let i = 2; i < 10; i++) { - const exponent = i === 2 && player.usedCorruptions[i] >= 10 - ? 1 - + 2 * Math.min(1, player.platonicUpgrades[17]) - + 0.04 * player.platonicUpgrades[17] - : 1 - corruptionMultiplier *= Math.pow( - G.corruptionPointMultipliers[player.usedCorruptions[i] + bonusLevel], - exponent - ) + bonusVal - - if ( - player.usedCorruptions[i] >= 14 - && player.singularityUpgrades.masterPack.getEffect().bonus - ) { - corruptionMultiplier *= 1.1 - } - } + corruptionMultiplier = player.corruptions.used.getTotalScore() const bonusMultiplier = computeAscensionScoreBonusMultiplier() effectiveScore = baseScore * corruptionMultiplier * bonusMultiplier @@ -2998,55 +3005,55 @@ export const calculateCubeQuarkMultiplier = () => { + calculateSigmoid(1.5, Math.pow(player.overfluxOrbs, 0.5), 640) + calculateSigmoid( 1.15, - +(player.highestSingularityCount >= 1) + +(player.singularityCount >= 1) * Math.pow(player.overfluxOrbs, 0.45), 2560 ) + calculateSigmoid( 1.15, - +(player.highestSingularityCount >= 2) + +(player.singularityCount >= 2) * Math.pow(player.overfluxOrbs, 0.4), 10000 ) + calculateSigmoid( 1.25, - +(player.highestSingularityCount >= 5) + +(player.singularityCount >= 5) * Math.pow(player.overfluxOrbs, 0.35), 40000 ) + calculateSigmoid( 1.25, - +(player.highestSingularityCount >= 10) + +(player.singularityCount >= 10) * Math.pow(player.overfluxOrbs, 0.32), 160000 ) + calculateSigmoid( 1.35, - +(player.highestSingularityCount >= 15) + +(player.singularityCount >= 15) * Math.pow(player.overfluxOrbs, 0.27), 640000 ) + calculateSigmoid( 1.45, - +(player.highestSingularityCount >= 20) + +(player.singularityCount >= 20) * Math.pow(player.overfluxOrbs, 0.24), 2e6 ) + calculateSigmoid( 1.55, - +(player.highestSingularityCount >= 25) + +(player.singularityCount >= 25) * Math.pow(player.overfluxOrbs, 0.21), 1e7 ) + calculateSigmoid( 1.85, - +(player.highestSingularityCount >= 30) + +(player.singularityCount >= 30) * Math.pow(player.overfluxOrbs, 0.18), 4e7 ) + calculateSigmoid( 3, - +(player.highestSingularityCount >= 35) + +(player.singularityCount >= 35) * Math.pow(player.overfluxOrbs, 0.15), 1e8 ) @@ -3074,13 +3081,13 @@ export const calculateSingularityAmbrosiaLuckMilestoneBonus = () => { const singThresholds2 = [135, 142, 149, 156, 163, 170, 177] for (const sing of singThresholds1) { - if (player.highestSingularityCount >= sing) { + if (player.singularityCount >= sing) { bonus += 5 } } for (const sing of singThresholds2) { - if (player.highestSingularityCount >= sing) { + if (player.singularityCount >= sing) { bonus += 6 } } @@ -3179,6 +3186,11 @@ export const calculateRequiredBlueberryTime = () => { val *= 2 } } + + if (player.blueberryUpgrades.ambrosiaLuckDilator.level > 0) { + val *= 2 + } + return val } @@ -3259,6 +3271,75 @@ export const calculateEXUltraCubeBonus = () => { return calculateEXUltraBonus(EX_ULTRA_CUBES) } +type BarBonuses = { + AmbrosiaLuck: number + AmbrosiaLuckMult: number + PixelLuck: number + PixelLuckMult: number + OfferingMult: number + ObtainiumMult: number + CubeMult: number + QuarkMult: number + BlueberrySpeedMult: number + PixelProgressMult: number +} + +export const calculatePixelBarLevelBonuses = (): BarBonuses => { + const level = computeMetaBarLevel() + return { + AmbrosiaLuck: calculatePixelBarLevelLuckBonus(level), + AmbrosiaLuckMult: calculatePixelBarLevelLuckAdditiveMultBonus(level), + PixelLuck: calculatePixelBarLevelPixelLuckBonus(level), + PixelLuckMult: calculatePixelBarLevelPixelLuckAdditiveMultBonus(level), + OfferingMult: calculatePixelBarLevelOfferingMult(level), + ObtainiumMult: calculatePixelBarLevelObtainiumMult(level), + CubeMult: calculatePixelBarLevelCubeMult(level), + QuarkMult: calculatePixelBarLevelQuarkMult(level), + BlueberrySpeedMult: calculatePixelBarLevelBlueberrySpeedMult(level), + PixelProgressMult: calculatePixelBarLevelProgressSpeedMult(level) + } +} + +export const calculatePixelBarLevelLuckBonus = (level: number) => { + return Math.floor(Math.pow(2, level / 100) * 5 * level) +} + +export const calculatePixelBarLevelLuckAdditiveMultBonus = (level: number) => { + return Math.floor(level / 10) / 100 +} + +export const calculatePixelBarLevelPixelLuckBonus = (level: number) => { + return Math.floor(level / 2) +} + +export const calculatePixelBarLevelPixelLuckAdditiveMultBonus = (level: number) => { + return Math.floor(level / 10) / 100 +} + +export const calculatePixelBarLevelCubeMult = (level: number) => { + return Math.pow(1.03, level) +} + +export const calculatePixelBarLevelOfferingMult = (level: number) => { + return Math.pow(1.03, level) +} + +export const calculatePixelBarLevelObtainiumMult = (level: number) => { + return Math.pow(1.03, level) +} + +export const calculatePixelBarLevelQuarkMult = (level: number) => { + return 1 + 0.5 * level / 100 * Math.pow(2, level / 100) +} + +export const calculatePixelBarLevelBlueberrySpeedMult = (level: number) => { + return 1 + level / 100 * Math.pow(2, level / 100) +} + +export const calculatePixelBarLevelProgressSpeedMult = (level: number) => { + return 1 + level / 200 * Math.pow(2, level / 100) +} + export const calculateEXALTBonusMult = () => { if (!player.singularityChallenges.limitedAscensions.rewards.exaltBonus) { return 1 @@ -3273,7 +3354,7 @@ export const calculateEXALTBonusMult = () => { export const calculateDilatedFiveLeafBonus = () => { const singThresholds = [100, 150, 200, 225, 250, 255, 260, 265, 269, 272] for (let i = 0; i < singThresholds.length; i++) { - if (player.highestSingularityCount < singThresholds[i]) return i / 100 + if (player.singularityCount < singThresholds[i]) return i / 100 } return singThresholds.length / 100 @@ -3287,7 +3368,9 @@ export const calculateAdditiveLuckMult = () => { const arr = [ 1, +player.singularityChallenges.noSingularityUpgrades.rewards.luckBonus, // No Singularity Upgrade 1x30 + +player.blueberryUpgrades.ambrosiaLuckDilator.bonus.ambrosiaLuckMult, // Blueberry Upgrade (Dilator) calculateDilatedFiveLeafBonus(), // Dilated Five Leaf Clover Perk + calculatePixelBarLevelBonuses().AmbrosiaLuckMult, // Computed Bar Level Bonus player.shopUpgrades.shopAmbrosiaLuckMultiplier4 / 100, // EXALT-unlocked shop upgrade +player.singularityChallenges.noAmbrosiaUpgrades.rewards.luckBonus, // No Ambrosia Challenge Reward G.isEvent ? calculateEventBuff(BuffType.AmbrosiaLuck) : 0 // Event @@ -3314,6 +3397,10 @@ export const calculateAmbrosiaLuck = () => { +player.blueberryUpgrades.ambrosiaLuck2.bonus.ambrosiaLuck, // Ambrosia Luck from Luck Module II +player.blueberryUpgrades.ambrosiaCubeLuck1.bonus.ambrosiaLuck, // Ambrosia Luck from Cube-Luck Synergy Module +player.blueberryUpgrades.ambrosiaQuarkLuck1.bonus.ambrosiaLuck, // Ambrosia Luck from Quark-Luck Synergy Module + calculatePixelBarLevelBonuses().AmbrosiaLuck, // Bar Level Ambrosia Luck Bonuses! + +player.pixelUpgrades.pixelAmbrosiaLuck.bonus.ambrosiaLuck, // Pixel Upgrade Inducer + +player.pixelUpgrades.pixelAmbrosiaLuck2.bonus.ambrosiaLuck, // Pixel Upgrade Deducer + +player.pixelUpgrades.pixelAmbrosiaLuck3.bonus.ambrosiaLuck, // Pixel Upgrade Convector player.highestSingularityCount >= 131 ? 131 : 0, // Singularity Perk "One Hundred Thirty One!" player.highestSingularityCount >= 269 ? 269 : 0, // Singularity Perk "Two Hundred Sixty Nine!" player.shopUpgrades.shopOcteractAmbrosiaLuck * (1 + Math.floor(Math.log10(player.totalWowOcteracts + 1))), // Octeract -> Ambrosia Shop Upgrade @@ -3337,7 +3424,10 @@ export const calculateBlueberryInventory = () => { +(player.singularityChallenges.noSingularityUpgrades.completions > 0), // E1x1 Clear! +player.singularityUpgrades.blueberries.getEffect().bonus, // Singularity Blueberry Upgrade calculateSingularityMilestoneBlueberries(), // Singularity Milestones (Congealed Blueberries) - +player.singularityChallenges.noAmbrosiaUpgrades.rewards.blueberries // No Ambrosia Challenge Reward + +player.singularityChallenges.noAmbrosiaUpgrades.rewards.blueberries, // No Ambrosia Challenge Reward + +player.pixelUpgrades.pixelBlueberry.bonus.blueberry, + +player.pixelUpgrades.pixelBlueberry2.bonus.blueberry, + +player.pixelUpgrades.pixelBlueberry3.bonus.blueberry ] return { @@ -3354,6 +3444,10 @@ export const calculateAmbrosiaGenerationSpeed = () => { calculateAmbrosiaGenerationSingularityUpgrade(), calculateAmbrosiaGenerationOcteractUpgrade(), +player.blueberryUpgrades.ambrosiaPatreon.bonus.blueberryGeneration, + calculatePixelBarLevelBonuses().BlueberrySpeedMult, // Bar Level Bonus! + +player.pixelUpgrades.pixelAmbrosiaGeneration.bonus.ambrosiaGeneration, + +player.pixelUpgrades.pixelAmbrosiaGeneration2.bonus.ambrosiaGeneration, + +player.pixelUpgrades.pixelAmbrosiaGeneration3.bonus.ambrosiaGeneration, +player.singularityChallenges.oneChallengeCap.rewards.blueberrySpeedMult, +player.singularityChallenges.noAmbrosiaUpgrades.rewards.blueberrySpeedMult, G.isEvent ? 1 + calculateEventBuff(BuffType.BlueberryTime) : 1, @@ -3366,6 +3460,64 @@ export const calculateAmbrosiaGenerationSpeed = () => { } } +export const calculateAdditivePixelLuckMult = () => { + const arr = [ + 1, + calculatePixelBarLevelBonuses().PixelLuckMult, + +player.singularityChallenges.noSingularityUpgrades.rewards.luckBonus, + G.isEvent ? calculateEventBuff(BuffType.AmbrosiaLuck) : 0 + ] + + return { + value: sumContents(arr), + array: arr + } +} + +export const calculatePixelLuck = () => { + const ambrosiaLuck = calculateAmbrosiaLuck().value + const arr = [ + 100, + calculatePixelBarLevelBonuses().PixelLuck, + +player.pixelUpgrades.pixelPixelLuck.bonus.pixelLuck, + +player.singularityUpgrades.singPixelLuck.getEffect().bonus, + +player.singularityUpgrades.singPixelLuck2.getEffect().bonus, + +player.octeractUpgrades.octeractPixelLuck.getEffect().bonus, + +player.octeractUpgrades.octeractPixelLuck2.getEffect().bonus, + +player.blueberryUpgrades.ambrosiaPixelLuck.bonus.pixelLuck, + +player.blueberryUpgrades.ambrosiaPixelLuck2.bonus.pixelLuck, + Math.floor( + (+player.pixelUpgrades.pixelPixelLuckConverter.bonus.purchased + + +player.pixelUpgrades.pixelPixelLuckConverter2.bonus.purchased) * ambrosiaLuck / 1000 + ) + ] + + const multiplicativeLuck = calculateAdditivePixelLuckMult().value + + return { + value: sumContents(arr) * multiplicativeLuck, + array: arr.concat(multiplicativeLuck) + } +} + +export const calculatePixelGenerationSpeed = () => { + const ambrosiaGen = calculateAmbrosiaGenerationSpeed().value + + const arr = [ + +player.singularityChallenges.limitedAscensions.rewards.ultimateProgressBarUnlock, + Math.min(ambrosiaGen, Math.pow(1000000 * ambrosiaGen, 1 / 3)) + + +player.pixelUpgrades.pixelPixelGeneration.bonus.pixelGenerationAdd + + +player.pixelUpgrades.pixelPixelGeneration2.bonus.pixelGenerationAdd + + +player.pixelUpgrades.pixelPixelGeneration3.bonus.pixelGenerationAdd, + calculatePixelBarLevelBonuses().PixelProgressMult + ] + + return { + value: productContents(arr), + array: arr + } +} + export const dailyResetCheck = () => { if (!player.dayCheck) { return @@ -3446,10 +3598,10 @@ export const derpsmithCornucopiaBonus = () => { 248 ] for (const sing of singCounts) { - if (player.highestSingularityCount >= sing) { + if (player.singularityCount >= sing) { counter += 1 } } - return 1 + (counter * player.highestSingularityCount) / 100 + return 1 + (counter * player.singularityCount) / 100 } diff --git a/src/Campaign.ts b/src/Campaign.ts new file mode 100644 index 000000000..f4719bb86 --- /dev/null +++ b/src/Campaign.ts @@ -0,0 +1,131 @@ +import i18next from 'i18next' +import { CorruptionLoadout, type Corruptions } from './Corruptions' +import { player } from './Synergism' + +export type AscensionModifiers = 'GlobalSpeed' + +export type CampaignLoadout = Partial +export type CampaignModifiers = Partial> + +export type CampaignKeys = 'test1' | 'test2' | 'test3' + +export interface ICampaignManagerData { + currentCampaign: CampaignKeys | undefined + campaigns: Record +} + +export interface ICampaignData { + campaignLoadout: CampaignLoadout + campaignModifiers: CampaignModifiers + limit: number + isMeta: boolean + c10Completions?: number +} + +export class CampaignManager { + totalCampaignTokens: number + currentCampaign: Campaign | undefined + campaigns!: Record + + constructor (campaignManagerData: ICampaignManagerData) { + for (const campaignKey of Object.keys(campaignManagerData.campaigns)) { + const key = campaignKey as keyof typeof campaignManagerData.campaigns + this.campaigns[key] = new Campaign(campaignDatas[key], key) + } + + const currentKey = campaignManagerData.currentCampaign + + if (currentKey !== undefined) { + this.currentCampaign = this.campaigns[currentKey] + player.corruptions.used = this.currentCampaign.createUsableLoadout() + } else { + this.currentCampaign = undefined + } + + this.totalCampaignTokens = this.computeTotalCampaignTokens() + } + + computeTotalCampaignTokens = () => { + let sum = 0 + for (const campaign in this.campaigns) { + const key = campaign as keyof typeof this.campaigns + sum += this.campaigns[key].computeTokenValue() + } + return sum + } +} + +export class Campaign { + // Stored as variable out of scope + name: string + description: string + campaignLoadout: CampaignLoadout + campaignModifiers: CampaignModifiers + limit: number + isMeta: boolean + + // Saved as a variable + _c10Completions = 0 + + constructor (campaignData: ICampaignData, key: string) { + this.name = i18next.t(`campaigns.data.${key}.name`) + this.description = i18next.t(`campaigns.data.${key}.description`) + this.campaignLoadout = campaignData.campaignLoadout + this.campaignModifiers = campaignData.campaignModifiers + this.limit = campaignData.limit + this.isMeta = campaignData.isMeta + this._c10Completions = campaignData.c10Completions ?? 0 + } + + public computeTokenValue = () => { + const metaMultiplier = this.isMeta ? 2 : 1 + return metaMultiplier * Math.min(this.c10Completions, this.limit) + } + + public createUsableLoadout = (): CorruptionLoadout => { + return new CorruptionLoadout(this.campaignLoadout) + } + + public set c10Completions (value: number) { + this._c10Completions = Math.min(value, this.limit) + } + public get c10Completions () { + return this._c10Completions + } +} + +export const campaignDatas: Record = { + test1: { + campaignLoadout: { + viscosity: 1 + }, + campaignModifiers: { + GlobalSpeed: 1 + }, + isMeta: true, + limit: 10 + }, + test2: { + campaignLoadout: { + viscosity: 1, + deflation: 1 + }, + campaignModifiers: { + GlobalSpeed: 1 + }, + isMeta: true, + limit: 15 + }, + test3: { + campaignLoadout: { + viscosity: 1, + deflation: 1, + dilation: 1 + }, + campaignModifiers: { + GlobalSpeed: 1 + }, + isMeta: true, + limit: 20 + } +} diff --git a/src/Challenges.ts b/src/Challenges.ts index 0f306e5ca..f62470e12 100644 --- a/src/Challenges.ts +++ b/src/Challenges.ts @@ -403,14 +403,9 @@ export const calculateChallengeRequirementMultiplier = ( completions: number, special = 0 ) => { - let requirementMultiplier = Math.max( - 1, - G.hyperchallengedMultiplier[player.usedCorruptions[4]] / (1 + player.platonicUpgrades[8] / 2.5) - ) - if (type === 'ascension') { - // Normalize back to 1 if looking at ascension challenges in particular. - requirementMultiplier = 1 - } + let requirementMultiplier = (type === 'ascension') + ? 1 + : player.corruptions.used.corruptionEffects('hyperchallenge') switch (type) { case 'transcend': requirementMultiplier *= G.challenge15Rewards.transcendChallengeReduction diff --git a/src/Config.ts b/src/Config.ts index 5f89b5114..6a6578331 100644 --- a/src/Config.ts +++ b/src/Config.ts @@ -1,4 +1,4 @@ -export const version = '3.0.0 pt 5.2: June 27, 2024: Fall of the Octeracts 2' +export const version = '3.0.0 pt 6: August 5, 2024: Pixel Update Beta [II]' /** * PSEUDO DO NOT CHANGE THIS LINE @@ -8,7 +8,7 @@ export const version = '3.0.0 pt 5.2: June 27, 2024: Fall of the Octeracts 2' * PSEUDO DO NOT CHANGE THIS LINE * PSEUDO DO NOT CHANGE THIS LINE */ -export const testing: boolean = false +export const testing: boolean = true export const lastUpdated = new Date('##LAST_UPDATED##') /** * CHANGE THIS ONE INSTEAD diff --git a/src/Corruptions.ts b/src/Corruptions.ts index 64247efbd..896ee0849 100644 --- a/src/Corruptions.ts +++ b/src/Corruptions.ts @@ -4,9 +4,289 @@ import { format, player } from './Synergism' import { IconSets } from './Themes' import { toggleCorruptionLevel } from './Toggles' import { Alert, Prompt } from './UpdateHTML' -import { getElementById } from './Utility' +import { getElementById, productContents, sumContents, validateNonnegativeInteger } from './Utility' import { Globals as G } from './Variables' +// export const corruptions = ['viscosity', 'drought', 'deflation', 'extinction', 'illiteracy', 'recession', 'dilation', 'hyperchallenge'] as const +// export type Corruptions = typeof corruptions[number] + +export const convertInputToCorruption = (array: number[]): Corruptions => { + return { + viscosity: array[0], + dilation: array[1], + hyperchallenge: array[2], + illiteracy: array[3], + deflation: array[4], + extinction: array[5], + drought: array[6], + recession: array[7] + } +} + +export type Corruptions = { + viscosity: number + drought: number + deflation: number + extinction: number + illiteracy: number + recession: number + dilation: number + hyperchallenge: number +} + +export const c15Corruptions: Corruptions = { + viscosity: 11, + drought: 11, + deflation: 11, + extinction: 11, + illiteracy: 11, + recession: 11, + dilation: 11, + hyperchallenge: 11 +} + +export class CorruptionLoadout { + #totalScoreMult = 1 + #corruptionScoreMults = [1, 3, 4, 5, 6, 7, 7.75, 8.5, 9.25, 10, 10.75, 11.5, 12.25, 13, 16, 20, 25, 33, 35] + #levels: Corruptions = { + viscosity: 0, + drought: 0, + deflation: 0, + extinction: 0, + illiteracy: 0, + recession: 0, + dilation: 0, + hyperchallenge: 0 + } + #bonusLevels = 0 + + constructor (p: Partial) { + Object.assign(this.#levels, p) + } + + public setCorruptionLevels (corruptions: Partial) { + Object.assign(this.#levels, corruptions) + this.clipCorruptionLevels() + this.#totalScoreMult = this.#calcTotalScoreMult() + this.#bonusLevels = this.#calcBonusLevels() + } + + public setCorruptionLevelsWithChallengeRequirement (corruptions: Partial) { + Object.assign(this.#levels, corruptions) + for (const corr in this.#levels) { + const corrKey = corr as keyof Corruptions + if ( + player.challengecompletions[corrChallengeMinimum(corrKey)] === 0 + && !player.singularityUpgrades.platonicTau.getEffect().bonus + ) { + this.setLevel(corrKey, 0) + } + } + this.#bonusLevels = this.#calcBonusLevels() + this.clipCorruptionLevels() + this.#totalScoreMult = this.#calcTotalScoreMult() + } + + public clipCorruptionLevels () { + const minLevel = 0 + const maxLevel = maxCorruptionLevel() + + for (const [corr, level] of Object.entries(this.#levels)) { + const corruption = corr as keyof Corruptions + + // Standard Validation + if (!validateNonnegativeInteger(level)) { + this.#levels[corruption] = 0 + } + + this.#levels[corruption] = Math.max(minLevel, this.#levels[corruption]) + this.#levels[corruption] = Math.min(maxLevel, this.#levels[corruption]) + } + } + + public calculateIndividualRawMultiplier (corr: keyof Corruptions) { + let bonusVal = player.singularityUpgrades.advancedPack.getEffect().bonus + ? 0.33 + : 0 + bonusVal += +player.singularityChallenges.oneChallengeCap.rewards.corrScoreIncrease + + let bonusMult = 1 + if (this.#levels[corr] >= 14) { + bonusMult *= 1.1 + } + + const totalLevel = this.#levels[corr] + this.#bonusLevels + const scoreMultLength = this.#corruptionScoreMults.length + + if (totalLevel < scoreMultLength - 1) { + const portionAboveLevel = Math.ceil(totalLevel) - totalLevel + return this.#corruptionScoreMults[Math.floor(totalLevel)] + + portionAboveLevel * this.#corruptionScoreMults[Math.ceil(totalLevel)] + } else { + return (this.#corruptionScoreMults[scoreMultLength - 1] + bonusVal) + * Math.pow(1.2, totalLevel - scoreMultLength + 1) + } + } + + #viscosityEffect () { + const base = G.viscosityPower[this.#levels.viscosity] + const multiplier = 1 + player.platonicUpgrades[6] + return Math.min(base * multiplier, 1) + } + + #droughtEffect () { + return G.droughtMultiplier[this.#levels.drought] + } + + #deflationEffect () { + return G.deflationMultiplier[this.#levels.deflation] + } + + #extinctionEffect () { + return G.extinctionMultiplier[this.#levels.extinction] + } + + #illiteracyEffect () { + const base = G.illiteracyPower[this.#levels.illiteracy] + const multiplier = 1 + + (9 / 100) * player.platonicUpgrades[9] * Math.min(100, Math.log10(player.researchPoints + 10)) + return Math.min(base * multiplier, 1) + } + + #recessionEffect () { + return G.recessionPower[this.#levels.recession] + } + + #dilationEffect () { + return G.dilationMultiplier[this.#levels.dilation] + } + + #hyperchallengeEffect () { + const baseEffect = G.hyperchallengeMultiplier[this.#levels.hyperchallenge] + let divisor = 1 + divisor *= 1 + 2 / 5 * player.platonicUpgrades[8] + return Math.max(1, baseEffect / divisor) + } + + corruptionEffects (corr: keyof Corruptions) { + switch (corr) { + case 'deflation': { + return this.#deflationEffect() + } + case 'dilation': { + return this.#dilationEffect() + } + case 'drought': { + return this.#droughtEffect() + } + case 'extinction': { + return this.#extinctionEffect() + } + case 'hyperchallenge': { + return this.#hyperchallengeEffect() + } + case 'illiteracy': { + return this.#illiteracyEffect() + } + case 'recession': { + return this.#recessionEffect() + } + case 'viscosity': { + return this.#viscosityEffect() + } + } + } + + get totalLevels () { + return sumContents(Object.values(this.#levels)) + } + + #calcBonusLevels () { + let bonusLevel = (player.singularityUpgrades.corruptionFifteen.level > 0) ? 1 : 0 + bonusLevel += +player.singularityChallenges.oneChallengeCap.rewards.freeCorruptionLevel + return bonusLevel + } + + public scoreMult (corruption: keyof Corruptions) { + if (corruption !== 'viscosity') { + return this.calculateIndividualRawMultiplier(corruption) + } else { + // player.platonicUpgrades[17] is the 17th platonic upgrade, known usually as P4x2, makes + // Exponent 3 + 0.04 * level if the corr is viscosity and it is set at least level 10. + const power = (player.platonicUpgrades[17] > 0 && this.#levels.viscosity >= 10) + ? 3 + 0.04 * player.platonicUpgrades[17] + : 1 + return Math.pow(this.calculateIndividualRawMultiplier(corruption), power) + } + } + + #calcTotalScoreMult () { + return productContents( + Object.keys(this.#levels).map((key) => { + const corrKey = key as keyof Corruptions + return this.scoreMult(corrKey) + }) + ) + } + + getLevel (corr: keyof Corruptions) { + return this.#levels[corr] + } + + getLoadout () { + return this.#levels + } + + getBonusLevel () { + return this.#bonusLevels + } + + setLevel (corr: keyof Corruptions, newLevel: number) { + this.#levels[corr] = newLevel + } + + resetCorruptions () { + for (const corr in this.#levels) { + const corrKey = corr as keyof Corruptions + this.setLevel(corrKey, 0) + corruptionDisplay(corrKey) + } + this.#totalScoreMult = this.#calcTotalScoreMult() + corruptionLoadoutTableUpdate(true, 0) + } + + incrementDecrementLevel (corr: keyof Corruptions, val: number) { + const level = this.getLevel(corr) + const minLevel = 0 + const maxLevel = maxCorruptionLevel() + + const newLevel = Math.max(minLevel, Math.min(maxLevel, level + val)) + this.setLevel(corr, newLevel) + } + + getTotalScore () { + return this.#totalScoreMult + } +} + +export type SavedCorruption = { + name: string + loadout: CorruptionLoadout +} + +export class CorruptionSaves { + #saves: Array = [] + constructor (corrSaveData: Record>) { + for (const saveKey of Object.keys(corrSaveData).slice(0, 8)) { + this.#saves.push({ name: saveKey, loadout: new CorruptionLoadout(corrSaveData[saveKey]) }) + } + } + + getSaves () { + return this.#saves + } +} + export const maxCorruptionLevel = () => { let max = 0 @@ -42,46 +322,24 @@ export const maxCorruptionLevel = () => { return max } -export const corruptionDisplay = (index: number) => { +const corrIcons: Record = { + viscosity: '/CorruptViscosity.png', + drought: '/CorruptDrought.png', + deflation: '/CorruptDeflation.png', + extinction: '/CorruptExtinction.png', + illiteracy: '/CorruptIlliteracy.png', + recession: '/CorruptRecession.png', + dilation: '/CorruptDilation.png', + hyperchallenge: '/CorruptHyperchallenge.png' +} + +export const corruptionDisplay = (corr: keyof Corruptions | 'exit') => { if (DOMCacheGetOrSet('corruptionDetails').style.visibility !== 'visible') { DOMCacheGetOrSet('corruptionDetails').style.visibility = 'visible' } if (DOMCacheGetOrSet('corruptionSelectedPic').style.visibility !== 'visible') { DOMCacheGetOrSet('corruptionSelectedPic').style.visibility = 'visible' } - G.corruptionTrigger = index - const currentExponent = ((index === 2) && player.usedCorruptions[index] >= 10) - ? 1 + 0.04 * player.platonicUpgrades[17] + 2 * Math.min(1, player.platonicUpgrades[17]) - : 1 - const protoExponent = ((index === 2) && player.prototypeCorruptions[index] >= 10) - ? 1 + 0.04 * player.platonicUpgrades[17] + 2 * Math.min(1, player.platonicUpgrades[17]) - : 1 - let bonusLevel = (player.singularityUpgrades.corruptionFifteen.level > 0) ? 1 : 0 - bonusLevel += +player.singularityChallenges.oneChallengeCap.rewards.freeCorruptionLevel - const bonusText = (bonusLevel > 0) ? `[+${bonusLevel}]` : '' - - const corruptEffectValues: number[][] = [ - G.viscosityPower, - G.lazinessMultiplier, - G.hyperchallengedMultiplier, - G.illiteracyPower, - G.deflationMultiplier, - G.extinctionMultiplier, - G.droughtMultiplier, - G.financialcollapsePower, - [0] - ] - - const iconExtensions: string[] = [ - '/CorruptViscocity.png', - '/CorruptSpatialDilation.png', - '/CorruptHyperchallenged.png', - '/CorruptScientificIlliteracy.png', - '/CorruptDeflation.png', - '/CorruptExtinction.png', - '/CorruptDrought.png', - '/CorruptFinancialCollapse.png' - ] let text = { name: i18next.t('corruptions.exitCorruption.name'), @@ -93,34 +351,28 @@ export const corruptionDisplay = (index: number) => { image: `Pictures/${IconSets[player.iconSet][0]}/CorruptExit.png` } satisfies Record - if (index < 10) { + if (corr !== 'exit') { + console.log(player.corruptions.next.scoreMult(corr)) text = { - name: i18next.t(`corruptions.names.${index - 1}`), - description: i18next.t(`corruptions.descriptions.${index - 1}`), - current: i18next.t(`corruptions.currentLevel.${index - 1}`, { - level: format(player.usedCorruptions[index]) + bonusText, - effect: format(corruptEffectValues[index - 2][player.usedCorruptions[index]], 3) + name: i18next.t(`corruptions.names.${corr}`), + description: i18next.t(`corruptions.descriptions.${corr}`), + current: i18next.t(`corruptions.currentLevel.${corr}`, { + level: player.corruptions.used.getLevel(corr), + effect: player.corruptions.used.corruptionEffects(corr) }), - planned: i18next.t(`corruptions.prototypeLevel.${index - 1}`, { - level: format(player.prototypeCorruptions[index]) + bonusText, - effect: format(corruptEffectValues[index - 2][player.prototypeCorruptions[index]], 3) + planned: i18next.t(`corruptions.prototypeLevel.${corr}`, { + level: player.corruptions.next.getLevel(corr), + effect: player.corruptions.next.corruptionEffects(corr) }), multiplier: i18next.t('corruptions.scoreMultiplier', { - curr: format( - Math.pow(G.corruptionPointMultipliers[player.usedCorruptions[index] + bonusLevel], currentExponent), - 1 - ), - next: format( - Math.pow(G.corruptionPointMultipliers[player.prototypeCorruptions[index] + bonusLevel], protoExponent), - 1 - ) + curr: player.corruptions.used.scoreMult(corr), + next: player.corruptions.next.scoreMult(corr) }), - spiritContribution: i18next.t('corruptions.spiritEffect', { - curr: format(4 * Math.pow(player.usedCorruptions[index] + bonusLevel, 2), 1), - next: format(4 * Math.pow(player.prototypeCorruptions[index] + bonusLevel, 2), 1) - }), - image: `Pictures/${IconSets[player.iconSet][0]}${iconExtensions[index - 2]}` + spiritContribution: i18next.t('corruptions.spiritEffect', { curr: 1, next: 1 }), + image: `Pictures/${IconSets[player.iconSet][0]}${corrIcons[corr]}` } + DOMCacheGetOrSet(`corrCurrent${corr}`).textContent = format(player.corruptions.used.getLevel(corr)) + DOMCacheGetOrSet(`corrNext${corr}`).textContent = format(player.corruptions.next.getLevel(corr)) } DOMCacheGetOrSet('corruptionName').textContent = text.name @@ -130,28 +382,26 @@ export const corruptionDisplay = (index: number) => { DOMCacheGetOrSet('corruptionMultiplierContribution').textContent = text.multiplier DOMCacheGetOrSet('corruptionSpiritContribution').textContent = text.spiritContribution DOMCacheGetOrSet('corruptionSelectedPic').setAttribute('src', text.image) - - if (index < 10) { - DOMCacheGetOrSet(`corrCurrent${index}`).textContent = format(player.usedCorruptions[index]) - DOMCacheGetOrSet(`corrNext${index}`).textContent = format(player.prototypeCorruptions[index]) - } } export const corruptionStatsUpdate = () => { - for (let i = 2; i <= 9; i++) { + for (const corr in player.corruptions.used.getLoadout()) { + const corrKey = corr as keyof Corruptions // https://discord.com/channels/677271830838640680/706329553639047241/841749032841379901 - const a = DOMCacheGetOrSet(`corrCurrent${i}`) - const b = DOMCacheGetOrSet(`corrNext${i}`) - a.textContent = format(player.usedCorruptions[i]) - b.textContent = format(player.prototypeCorruptions[i]) + const a = DOMCacheGetOrSet(`corrCurrent${corrKey}`) + const b = DOMCacheGetOrSet(`corrNext${corrKey}`) + a.textContent = format(player.corruptions.used.getLevel(corrKey)) + b.textContent = format(player.corruptions.next.getLevel(corrKey)) } } export const corruptionButtonsAdd = () => { const rows = document.getElementsByClassName('corruptionStatRow') + const keys = Object.keys(player.corruptions.used.getLoadout()) for (let i = 0; i < rows.length; i++) { const row = rows[i] + const key = keys[i] as keyof Corruptions // Delete rows that already exist for (let i = row.children.length - 1; i >= 1; i--) { @@ -163,16 +413,16 @@ export const corruptionButtonsAdd = () => { let text = document.createTextNode(i18next.t('corruptions.current')) p.appendChild(text) let span = document.createElement('span') - span.id = `corrCurrent${i + 2}` - span.textContent = `${player.usedCorruptions[i + 2]}` + span.id = `corrCurrent${key}` + span.textContent = `${player.corruptions.used.getLevel(key)}` p.appendChild(span) text = document.createTextNode(i18next.t('corruptions.next')) p.appendChild(text) span = document.createElement('span') - span.id = `corrNext${i + 2}` - span.textContent = `${player.prototypeCorruptions[i + 2]}` + span.id = `corrNext${key}` + span.textContent = `${player.corruptions.next.getLevel(key)}` p.appendChild(span) row.appendChild(p) @@ -180,153 +430,173 @@ export const corruptionButtonsAdd = () => { btn = document.createElement('button') btn.className = 'corrBtn corruptionMax' btn.textContent = `+${i18next.t('corruptions.max')}` - btn.addEventListener('click', () => toggleCorruptionLevel(i + 2, 99)) + btn.addEventListener('click', () => toggleCorruptionLevel(key, 99)) row.appendChild(btn) btn = document.createElement('button') btn.className = 'corrBtn corruptionUp' btn.textContent = '+1' - btn.addEventListener('click', () => toggleCorruptionLevel(i + 2, 1)) + btn.addEventListener('click', () => toggleCorruptionLevel(key, 1)) row.appendChild(btn) btn = document.createElement('button') btn.className = 'corrBtn corruptionDown' btn.textContent = '-1' - btn.addEventListener('click', () => toggleCorruptionLevel(i + 2, -1)) + btn.addEventListener('click', () => toggleCorruptionLevel(key, -1)) row.appendChild(btn) btn = document.createElement('button') btn.className = 'corrBtn corruptionReset' btn.textContent = `-${i18next.t('corruptions.max')}` - btn.addEventListener('click', () => toggleCorruptionLevel(i + 2, -99)) + btn.addEventListener('click', () => toggleCorruptionLevel(key, -99)) row.appendChild(btn) - row.addEventListener('click', () => corruptionDisplay(i + 2)) + row.addEventListener('click', () => corruptionDisplay(key)) } } export const corruptionLoadoutTableCreate = () => { - const corrCount = 8 const table = getElementById('corruptionLoadoutTable') + const corrNext = player.corruptions.next.getLoadout() + const corrSaves = player.corruptions.saves.getSaves() + // Delete rows that already exist for (let i = table.rows.length - 1; i >= 1; i--) { table.deleteRow(i) } - for (let i = 0; i < Object.keys(player.corruptionLoadouts).length + 1; i++) { + // Create the 'next' row + const nextRow = table.insertRow() + + // Use the default name 'next' + const nextCell = nextRow.insertCell() + nextCell.className = `test${'Title'}` + nextCell.textContent = i18next.t('corruptions.loadoutTable.next') + nextCell.addEventListener('click', () => void corruptionLoadoutGetExport()) + nextCell.classList.add('corrLoadoutName') + nextCell.title = i18next.t('corruptions.loadoutTable.firstRowTitle') + + // Insert Prototype Corrs + for (const corr in corrNext) { + const corrKey = corr as keyof Corruptions + const cell = nextRow.insertCell() + cell.className = `test${corrKey}` + cell.textContent = corrNext[corrKey].toString() + } + + // Import and Zero buttons + // First line is special : "Import" and "Zero" buttons + const importCell = nextRow.insertCell() + const importBtn: HTMLButtonElement = document.createElement('button') + importBtn.className = 'corrImport' + importBtn.textContent = i18next.t('corruptions.loadoutTable.import') + importBtn.addEventListener('click', () => void importCorruptionsPrompt()) + importCell.appendChild(importBtn) + importCell.title = i18next.t('corruptions.importLoadoutInTextFormat') + + const zeroCell = nextRow.insertCell() + const zeroBtn = document.createElement('button') + zeroBtn.className = 'corrLoad' + zeroBtn.textContent = i18next.t('corruptions.loadoutTable.zero') + zeroBtn.addEventListener('click', () => player.corruptions.next.resetCorruptions()) + zeroCell.appendChild(zeroBtn) + zeroCell.title = i18next.t('corruptions.loadoutTable.zeroTitle') + + // Do the rest of the thing + for (let i = 0; i < corrSaves.length; i++) { + const corrSave = corrSaves[i] + const corrLoadout = corrSave?.loadout.getLoadout() const row = table.insertRow() - for (let j = 0; j <= corrCount; j++) { + // Title Cell + const titleCell = row.insertCell() + titleCell.className = `test${'Title'}` + titleCell.title = i18next.t('corruptions.loadoutTable.otherRowTitle', { value: i + 1 }) + console.log(corrLoadout) + for (const corr in corrLoadout) { + const corrKey = corr as keyof Corruptions const cell = row.insertCell() - cell.className = `test${j}` - if (j === 0) { // First column - if (i === 0) { // First row - cell.textContent = i18next.t('corruptions.loadoutTable.next') - cell.addEventListener('click', () => void corruptionLoadoutGetExport()) - cell.classList.add('corrLoadoutName') - cell.title = i18next.t('corruptions.loadoutTable.firstRowTitle') - } else { - // Custom loadout names are loaded later, via updateCorruptionLoadoutNames() - cell.title = i18next.t('corruptions.loadoutTable.otherRowTitle', { value: i }) - } - } else if (j <= corrCount) { - if (i === 0) { // Next Ascension Corruption values - cell.textContent = player.prototypeCorruptions[j + 1].toString() - } else { // Loadout Corruption values - cell.textContent = player.corruptionLoadouts[i][j + 1].toString() - } - } - } - if (i === 0) { - // First line is special : "Import" and "Zero" buttons - let cell = row.insertCell() - let btn: HTMLButtonElement = document.createElement('button') - btn.className = 'corrImport' - btn.textContent = i18next.t('corruptions.loadoutTable.import') - btn.addEventListener('click', () => void importCorruptionsPrompt()) - cell.appendChild(btn) - cell.title = i18next.t('corruptions.importLoadoutInTextFormat') - - cell = row.insertCell() - btn = document.createElement('button') - btn.className = 'corrLoad' - btn.textContent = i18next.t('corruptions.loadoutTable.zero') - btn.addEventListener('click', () => corruptionLoadoutSaveLoad(false, i)) - cell.appendChild(btn) - cell.title = i18next.t('corruptions.loadoutTable.zeroTitle') - } else { - let cell = row.insertCell() - let btn = document.createElement('button') - btn.className = 'corrSave' - btn.textContent = i18next.t('corruptions.loadoutTable.save') - btn.addEventListener('click', () => corruptionLoadoutSaveLoad(true, i)) - cell.appendChild(btn) - cell.title = i18next.t('corruptions.loadoutTable.saveTitle') - - cell = row.insertCell() - btn = document.createElement('button') - btn.className = 'corrLoad' - btn.textContent = i18next.t('corruptions.loadoutTable.load') - btn.addEventListener('click', () => corruptionLoadoutSaveLoad(false, i)) - cell.appendChild(btn) + cell.className = `test${corrKey}` + cell.textContent = corrLoadout[corrKey].toString() } + + let cell = row.insertCell() + let btn = document.createElement('button') + btn.className = 'corrSave' + btn.textContent = i18next.t('corruptions.loadoutTable.save') + btn.addEventListener('click', () => corruptionSaveLoadout(i)) + cell.appendChild(btn) + cell.title = i18next.t('corruptions.loadoutTable.saveTitle') + + cell = row.insertCell() + btn = document.createElement('button') + btn.className = 'corrLoad' + btn.textContent = i18next.t('corruptions.loadoutTable.load') + btn.addEventListener('click', () => corruptionLoadLoadout(i)) + cell.appendChild(btn) } } -export const corruptionLoadoutTableUpdate = (updateRow = 0) => { +export const corruptionLoadoutTableUpdate = (updateNext = false, updateRow = 0) => { const row = getElementById('corruptionLoadoutTable').rows[updateRow + 1].cells - for (let i = 1; i < row.length; i++) { - if (i > 8) { - break + if (updateNext) { + const corrNext = player.corruptions.next.getLoadout() + let index = 0 + for (const corr in corrNext) { + const corrKey = corr as keyof Corruptions + row[index + 1].textContent = corrNext[corrKey].toString() + index += 1 } - row[i].textContent = - ((updateRow === 0) ? player.prototypeCorruptions[i + 1] : player.corruptionLoadouts[updateRow][i + 1]).toString() - } -} - -export const corruptionLoadoutSaveLoad = (save = true, loadout = 1) => { - if (save) { - player.corruptionLoadouts[loadout] = Array.from(player.prototypeCorruptions) - corruptionLoadoutTableUpdate(loadout) } else { - if (loadout === 0) { - player.prototypeCorruptions = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - } else { - player.prototypeCorruptions = Array.from(player.corruptionLoadouts[loadout]) + const corrSaves = player.corruptions.saves.getSaves()[updateRow - 1]?.loadout.getLoadout() + let index = 0 + for (const corr in corrSaves) { + const corrKey = corr as keyof Corruptions + row[index + 1].textContent = corrSaves[corrKey].toString() + index += 1 } - corruptionLoadoutTableUpdate() - corruptionStatsUpdate() } } +export const corruptionSaveLoadout = (loadoutNum: number) => { + const buildToSave = player.corruptions.next.getLoadout() + player.corruptions.saves.getSaves()[loadoutNum].loadout.setCorruptionLevels(buildToSave) + corruptionLoadoutTableUpdate(false, loadoutNum + 1) +} + +export const corruptionLoadLoadout = (loadoutNum: number) => { + const buildToLoad = player.corruptions.saves.getSaves()[loadoutNum].loadout.getLoadout() + player.corruptions.next.setCorruptionLevels(buildToLoad) + corruptionLoadoutTableUpdate(true) + corruptionStatsUpdate() +} + export const applyCorruptions = (corruptions: string) => { - if (corruptions.includes('/') && corruptions.split('/').length === 13) { - // Converts the '/' separated string into a number[] - const newCorruptions = corruptions.split('/').map((corr) => Number(corr)) + let corr: Corruptions + if (!corruptions) { + return false + } - for (const value of newCorruptions) { - if ( - !Number.isInteger(value) - || Number.isNaN(value) - || value < 0 - || value > maxCorruptionLevel() - ) { - return false - } - } + console.log(corruptions) - player.prototypeCorruptions = newCorruptions - corruptionLoadoutTableUpdate() + if (corruptions.includes('/') && corruptions.split('/').length === 8) { + corr = convertInputToCorruption(corruptions.split('/').map(Number)) + } else { + corr = JSON.parse(corruptions) as Corruptions + } + + if (corr) { + player.corruptions.next.setCorruptionLevels(corr) + corruptionLoadoutTableUpdate(true, 0) corruptionStatsUpdate() return true } - return false } async function importCorruptionsPrompt () { const input = await Prompt(i18next.t('corruptions.importCorruptionsPrompt.import')) - if (!applyCorruptions(`0/0/${input}/0/0/0`)) { + if (!applyCorruptions(input as string)) { void Alert(i18next.t('corruptions.importCorruptionsPrompt.importError')) } } @@ -346,7 +616,7 @@ async function corruptionLoadoutGetNewName (loadout = 0) { } else if (!regex.test(renamePrompt)) { return Alert(i18next.t('corruptions.corruptionLoadoutName.errors.regexError')) } else { - player.corruptionLoadoutNames[loadout] = renamePrompt + player.corruptions.saves.getSaves()[loadout].name = renamePrompt updateCorruptionLoadoutNames() if (renamePrompt === 'crazy') { return Alert(i18next.t('corruptions.loadoutPrompt.errors.crazyJoke')) @@ -356,18 +626,18 @@ async function corruptionLoadoutGetNewName (loadout = 0) { export const updateCorruptionLoadoutNames = () => { const rows = getElementById('corruptionLoadoutTable').rows - for (let i = 0; i < Object.keys(player.corruptionLoadouts).length; i++) { + for (let i = 0; i < 8; i++) { const cells = rows[i + 2].cells // start changes on 2nd row if (cells[0].textContent!.length === 0) { // first time setup cells[0].addEventListener('click', () => void corruptionLoadoutGetNewName(i)) // get name function handles -1 for array cells[0].classList.add('corrLoadoutName') } - cells[0].textContent = `${player.corruptionLoadoutNames[i]}:` + cells[0].textContent = `${player.corruptions.saves.getSaves()[i]?.name}:` } } const corruptionLoadoutGetExport = async () => { - const str = player.prototypeCorruptions.slice(2, 10).join('/') + const str = JSON.stringify(player.corruptions.next.getLoadout()) if ('clipboard' in navigator) { await navigator.clipboard.writeText(str) .catch((e: Error) => Alert(i18next.t('corruptions.loadoutExport.saveErrorNavigator', { message: e.message }))) @@ -415,23 +685,23 @@ export const revealCorruptions = () => { } } -export function corrChallengeMinimum (index: number): number { - switch (index) { - case 2: +export function corrChallengeMinimum (corr: keyof Corruptions): number { + switch (corr) { + case 'viscosity': return 11 - case 3: + case 'dilation': return 14 - case 4: + case 'hyperchallenge': return 14 - case 5: + case 'illiteracy': return 13 - case 6: + case 'deflation': return 12 - case 7: + case 'extinction': return 12 - case 8: + case 'drought': return 11 - case 9: + case 'recession': return 13 default: return 0 diff --git a/src/DynamicUpgrade.ts b/src/DynamicUpgrade.ts index d5a218deb..1e74516e6 100644 --- a/src/DynamicUpgrade.ts +++ b/src/DynamicUpgrade.ts @@ -11,6 +11,7 @@ export interface IUpgradeData { toggleBuy?: number effect?(this: void, n: number): { bonus: number | boolean; desc: string } freeLevels?: number + cacheUpdates?: (() => void)[] } export abstract class DynamicUpgrade { @@ -22,6 +23,7 @@ export abstract class DynamicUpgrade { readonly costPerLevel: number public toggleBuy = 1 // -1 = buy MAX (or 1000 in case of infinity levels!) readonly effect: (n: number) => { bonus: number | boolean; desc: string } + readonly cacheUpdates: (() => void)[] | undefined constructor (data: IUpgradeData) { this.name = data.name @@ -32,6 +34,7 @@ export abstract class DynamicUpgrade { this.costPerLevel = data.costPerLevel this.toggleBuy = data.toggleBuy ?? 1 this.effect = data.effect ?? ((n: number) => ({ bonus: n, desc: 'WIP not implemented' })) + this.cacheUpdates = data.cacheUpdates ?? undefined } public async changeToggle (): Promise { @@ -67,6 +70,14 @@ export abstract class DynamicUpgrade { return this.effect(effectiveLevel) } + public updateCaches (): void { + if (this.cacheUpdates !== undefined) { + for (const cache of this.cacheUpdates) { + cache() + } + } + } + abstract toString (): string abstract updateUpgradeHTML (): void abstract getCostTNL (): number diff --git a/src/Event.ts b/src/Event.ts index 420012bec..6a4d7fea5 100644 --- a/src/Event.ts +++ b/src/Event.ts @@ -1,6 +1,5 @@ import i18next from 'i18next' import { DOMCacheGetOrSet } from './Cache/DOM' -import { calculateAdditiveLuckMult, calculateAmbrosiaGenerationSpeed, calculateAmbrosiaLuck } from './Calculate' import { format, getTimePinnedToLoadDate, player } from './Synergism' import { Alert, revealStuff } from './UpdateHTML' import { Globals as G } from './Variables' @@ -113,9 +112,9 @@ export const eventCheck = async () => { if (G.isEvent !== updateIsEventCheck) { revealStuff() - G.ambrosiaCurrStats.ambrosiaAdditiveLuckMult = calculateAdditiveLuckMult().value - G.ambrosiaCurrStats.ambrosiaLuck = calculateAmbrosiaLuck().value - G.ambrosiaCurrStats.ambrosiaGenerationSpeed = calculateAmbrosiaGenerationSpeed().value + player.caches.ambrosiaGeneration.updateVal('Event') + player.caches.ambrosiaLuckAdditiveMult.updateVal('Event') + player.caches.ultimatePixelAdditiveMult.updateVal('Event') } } diff --git a/src/EventListeners.ts b/src/EventListeners.ts index 0c7634fd0..445836ac0 100644 --- a/src/EventListeners.ts +++ b/src/EventListeners.ts @@ -55,12 +55,13 @@ import { resetGame, updateSaveString } from './ImportExport' +import { showBarLevelBonuses } from './PixelUpgrades' import { buyPlatonicUpgrades, createPlatonicDescription } from './Platonic' import { buyResearch, researchDescriptions } from './Research' import { resetrepeat, updateAutoCubesOpens, updateAutoReset, updateTesseractAutoBuyAmount } from './Reset' import { displayRuneInformation, redeemShards } from './Runes' import { buyShopUpgrades, resetShopUpgrades, shopData, shopDescriptions, shopUpgradeTypes, useConsumable } from './Shop' -import { buyGoldenQuarks, getLastUpgradeInfo, singularityPerks } from './singularity' +import { buyGoldenQuarks, getLastUpgradeInfo, setSingularity, singularityPerks } from './singularity' import { displayStats } from './Statistics' import { generateExportSummary } from './Summary' import { player, resetCheck, saveSynergy } from './Synergism' @@ -128,6 +129,7 @@ import { upgradedescriptions } from './Upgrades' import { Globals as G } from './Variables' +// import { SingularityChallenge } from './SingularityChallenges' /* STYLE GUIDE */ /* @@ -393,6 +395,13 @@ export const generateEventHandlers = () => { DOMCacheGetOrSet(`ach${index}`).addEventListener('mouseover', () => achievementdescriptions(index)) } + for (let index = 0; index < 2; index++) { + DOMCacheGetOrSet(`toggleAchievementSubTab${index + 1}`).addEventListener( + 'click', + () => changeSubTab(Tabs.Achievements, { page: index }) + ) + } + // RUNES TAB [And all corresponding subtabs] // Part 0: Upper UI portion // Auto sacrifice toggle button @@ -836,9 +845,12 @@ export const generateEventHandlers = () => { DOMCacheGetOrSet('corrLoadoutsBtn').addEventListener('click', () => changeSubTab(Tabs.Corruption, { page: 1 })) // Part 1: Displays - DOMCacheGetOrSet('corruptionDisplays').addEventListener('click', () => corruptionDisplay(10)) + DOMCacheGetOrSet('corruptionDisplays').addEventListener('click', () => corruptionDisplay('exit')) DOMCacheGetOrSet('corruptionCleanse').addEventListener('click', () => corruptionCleanseConfirm()) - DOMCacheGetOrSet('corruptionCleanseConfirm').addEventListener('click', () => toggleCorruptionLevel(10, 999)) + DOMCacheGetOrSet('corruptionCleanseConfirm').addEventListener( + 'click', + () => toggleCorruptionLevel('illiteracy', 999, true) + ) // Extra toggle DOMCacheGetOrSet('ascensionAutoEnable').addEventListener('click', () => toggleAutoAscend(0)) @@ -947,6 +959,9 @@ TODO: Fix this entire tab it's utter shit } DOMCacheGetOrSet('buySingularityQuarksButton').addEventListener('click', () => buyGoldenQuarks()) // SINGULARITY TAB + + DOMCacheGetOrSet('goldenQuarkResetFunction').addEventListener('click', () => setSingularity()) + const singularityUpgrades = Object.keys( player.singularityUpgrades ) as (keyof Player['singularityUpgrades'])[] @@ -1063,6 +1078,7 @@ TODO: Fix this entire tab it's utter shit const shiftedKey = i + 1 const el = blueberryLoadouts[i] el.addEventListener('mouseover', () => { + console.log(player.blueberryLoadouts[shiftedKey]) createLoadoutDescription( shiftedKey, player.blueberryLoadouts[shiftedKey] ?? { ambrosiaTutorial: 0 } @@ -1086,8 +1102,74 @@ TODO: Fix this entire tab it's utter shit // Import blueberries DOMCacheGetOrSet('importBlueberries').addEventListener('change', async (e) => importData(e, importBlueberryTree)) + // Pixel Upgrades + const icons = document.querySelectorAll('.pixelUpgrade') + // const upgradeContainer = document.querySelector('#pixelUpgradeContainer') + // const rect2 = upgradeContainer?.getBoundingClientRect(); + + icons.forEach((icon) => { + icon.addEventListener('mouseenter', () => { + // Position the textbox + const upgradeContainer = document.querySelector('#pixelUpgradeContainer') + const textBox = document.querySelector('#pixelTextBox') + const rect = icon.getBoundingClientRect() + const rect2 = upgradeContainer?.getBoundingClientRect() + if (textBox != null && rect2 != null) { + textBox.style.top = `${rect.bottom - rect2.top + 16}px` // 5px below the icon + textBox.style.left = `${rect.left - rect2.left + icon.offsetWidth / 2}px` + textBox.style.visibility = 'visible' + } + }) + + icon.addEventListener('mouseleave', () => { + const textBox = document.querySelector('#pixelTextBox') + if (textBox != null) { + textBox.style.visibility = 'hidden' + } + }) + }) + + const pixelBar = document.querySelector('#metaPixelProgressBar') + + pixelBar?.addEventListener('mouseenter', () => { + const rect = pixelBar.getBoundingClientRect() + const textBox = document.querySelector('#pixelBarLevelBonusTextBox') + void showBarLevelBonuses() + if (rect != null && textBox != null) { + textBox.style.top = `${rect.bottom - rect.top - 16}px` // 5px below the icon + textBox.style.left = `${pixelBar.offsetWidth * 13 / 32}px` + textBox.style.visibility = 'visible' + } + }) + + const singPic = document.querySelector('#ascSingularityCountStats') + + singPic?.addEventListener('click', () => { + setSingularity() + }) + + pixelBar?.addEventListener('mouseleave', () => { + const textBox = document.querySelector('#pixelBarLevelBonusTextBox') + if (textBox != null) { + textBox.style.visibility = 'hidden' + } + }) + + const pixelUpgrades = Object.keys( + player.pixelUpgrades + ) as (keyof Player['pixelUpgrades'])[] + for (const key of pixelUpgrades) { + DOMCacheGetOrSet(`${String(key)}`).addEventListener( + 'mouseover', + () => player.pixelUpgrades[`${String(key)}`].updateUpgradeHTML() + ) + DOMCacheGetOrSet(`${String(key)}`).addEventListener( + 'click', + (event) => player.pixelUpgrades[`${String(key)}`].buyLevel(event) + ) + } // Toggle subtabs of Singularity tab - for (let index = 0; index < 4; index++) { + for (let index = 0; index < 6; index++) { DOMCacheGetOrSet(`toggleSingularitySubTab${index + 1}`).addEventListener( 'click', () => changeSubTab(Tabs.Singularity, { page: index }) @@ -1127,4 +1209,6 @@ TODO: Fix this entire tab it's utter shit // Window window.addEventListener('error', imgErrorHandler, { capture: true }) + + // goldenQuarkResetFunction.addEventListener('onclick') } diff --git a/src/Helper.ts b/src/Helper.ts index ca3cc0b86..070555dd1 100644 --- a/src/Helper.ts +++ b/src/Helper.ts @@ -16,7 +16,12 @@ import { useConsumable } from './Shop' import { player } from './Synergism' import { Tabs } from './Tabs' import { buyAllTalismanResources } from './Talismans' -import { visualUpdateAmbrosia, visualUpdateOcteracts, visualUpdateResearch } from './UpdateVisuals' +import { + visualUpdateAmbrosia, + visualUpdateOcteracts, + visualUpdateProgressPixels, + visualUpdateResearch +} from './UpdateVisuals' import { Globals as G } from './Variables' type TimerInput = @@ -30,6 +35,7 @@ type TimerInput = | 'octeracts' | 'autoPotion' | 'ambrosia' + | 'pixel' /** * addTimers will add (in milliseconds) time to the reset counters, and quark export timer @@ -44,6 +50,7 @@ export const addTimers = (input: TimerInput, time = 0) => { || input === 'octeracts' || input === 'autoPotion' || input === 'ambrosia' + || input === 'pixel' ? 1 : calculateTimeAcceleration().mult @@ -192,11 +199,8 @@ export const addTimers = (input: TimerInput, time = 0) => { break } - const ambrosiaLuck = G.ambrosiaCurrStats.ambrosiaLuck - const baseBlueberryTime = G.ambrosiaCurrStats.ambrosiaGenerationSpeed - player.blueberryTime += Math.floor(8 * G.ambrosiaTimer) / 8 * baseBlueberryTime - player.ultimateProgress += Math.floor(8 * G.ambrosiaTimer) / 8 - * Math.min(baseBlueberryTime, Math.pow(1000 * baseBlueberryTime, 1 / 2)) * 0.02 + const ambrosiaLuck = player.caches.ambrosiaLuck.usedTotal + player.blueberryTime += Math.floor(8 * G.ambrosiaTimer) / 8 * compute G.ambrosiaTimer %= 0.125 let timeToAmbrosia = calculateRequiredBlueberryTime() @@ -225,14 +229,47 @@ export const addTimers = (input: TimerInput, time = 0) => { ambrosiaToGain * 0.2 * player.shopUpgrades.shopAmbrosiaAccelerator ) timeToAmbrosia = calculateRequiredBlueberryTime() + const ambrosiaTimeGain = Math.min( + timeToAmbrosia / compute * 0.9, + 0.2 * ambrosiaToGain * player.shopUpgrades.shopAmbrosiaAccelerator + ) + G.ambrosiaTimer += ambrosiaTimeGain } - if (player.ultimateProgress > 1e6) { - player.ultimatePixels += Math.floor(player.ultimateProgress / 1e6) - player.ultimateProgress -= 1e6 * Math.floor(player.ultimateProgress / 1e6) + visualUpdateAmbrosia() + break + } + case 'pixel': { + const compute = G.pixelCurrStats.pixelGenerationSpeed + if (compute === 0) { + break } - visualUpdateAmbrosia() + G.pixelTimer += time * timeMultiplier + + if (G.pixelTimer < 0.125) { + break + } + + const pixelLuck = G.pixelCurrStats.pixelLuck + player.ultimateProgress += Math.floor(8 * G.pixelTimer) / 8 * compute + G.pixelTimer %= 0.125 + + while (player.ultimateProgress > 1e6) { + const maxAllowed = player.ultimatePixels / 1e6 + const speedMult = Math.max(1, Math.min(Math.floor(maxAllowed / 25), Math.floor(player.ultimateProgress / 1e6))) + const RNG2 = Math.random() + const pixelMult = Math.floor(pixelLuck / 100) + const luckMult2 = RNG2 < pixelLuck / 100 - Math.floor(pixelLuck / 100) ? 1 : 0 + const pixelToGain = pixelMult + luckMult2 + + player.ultimatePixels += pixelToGain * speedMult + player.lifetimeUltimatePixels += pixelToGain * speedMult + player.ultimateProgress -= 1e6 * speedMult + } + + visualUpdateProgressPixels() + break } } } diff --git a/src/History.ts b/src/History.ts index 865342cb2..277c08f0c 100644 --- a/src/History.ts +++ b/src/History.ts @@ -3,7 +3,7 @@ import Decimal from 'break_infinity.js' import i18next from 'i18next' import { antSacrificePointsToMultiplier } from './Ants' import { DOMCacheGetOrSet } from './Cache/DOM' -import { applyCorruptions } from './Corruptions' +import { applyCorruptions, convertInputToCorruption, type Corruptions } from './Corruptions' import { Synergism } from './Events' import { format, formatTimeShort, player } from './Synergism' import { IconSets } from './Themes' @@ -53,7 +53,7 @@ export type ResetHistoryEntryReincarnate = ResetHistoryEntryBase & { export type ResetHistoryEntryAscend = ResetHistoryEntryBase & { c10Completions: number - usedCorruptions: number[] + usedCorruptions: Corruptions | number[] corruptionScore: number wowCubes: number wowTesseracts: number @@ -321,28 +321,46 @@ const resetHistoryTableMapping: Record = { singularity: 'historySingularityTable' } -// Images associated with the various corruptions. -const resetHistoryCorruptionImages = [ - 'CorruptViscocity.png', - 'CorruptSpatialDilation.png', - 'CorruptHyperchallenged.png', - 'CorruptScientificIlliteracy.png', - 'CorruptDeflation.png', - 'CorruptExtinction.png', - 'CorruptDrought.png', - 'CorruptFinancialCollapse.png' -] +type corruptionInfo = { + image: string + title: string +} -const resetHistoryCorruptionTitles = [ - 'Viscosity [Accelerators and Multipliers]', - 'Spacial Dilation [Time]', - 'Hyperchallenged [Challenge Requirements]', - 'Scientific Illiteracy [Obtainium]', - 'Market Deflation [Diamonds]', - 'Extinction [Ants]', - 'Drought [Offering EXP]', - 'Financial Recession [Coins]' -] +// Images associated with the various corruptions. +const resetHistoryCorruptionInfo: Record = { + viscosity: { + image: 'CorruptViscosity.png', + title: 'Viscosity [Accelerators and Multipliers]' + }, + dilation: { + image: 'CorruptDilation.png', + title: 'Spacial Dilation [Time]' + }, + hyperchallenge: { + image: 'CorruptHyperchallenge.png', + title: 'Hyperchallenge [Challenge Requirements' + }, + illiteracy: { + image: 'CorruptIlliteracy.png', + title: 'Illiteracy [Obtainium]' + }, + deflation: { + image: 'CorruptDeflation.png', + title: 'Market Deflation [Diamonds]' + }, + extinction: { + image: 'CorruptExtinction.png', + title: 'Extinction [Ants]' + }, + drought: { + image: 'CorruptDrought.png', + title: 'Drought [Offering EXP]' + }, + recession: { + image: 'CorruptRecession.png', + title: 'Financial Recession [Coins]' + } +} // A formatting aid that removes the mantissa from a formatted string. Converts "2.5e1000" to "e1000". const extractStringExponent = (str: string) => { @@ -442,7 +460,7 @@ const resetHistoryRenderRow = ( ) const corruptions = resetHistoryFormatCorruptions(data) - + console.log(corruptions) extra.push(corruptions[0]) extra.push(corruptions[1]) extra.push(corruptions[2]) @@ -525,21 +543,28 @@ const resetHistoryFormatCorruptions = (data: ResetHistoryEntryAscend): [string, let corruptions = '' let loadout = '' let corrs = 0 - for (let i = 0; i < resetHistoryCorruptionImages.length; ++i) { - const corruptionIdx = i + 2 - if (corruptionIdx in data.usedCorruptions && data.usedCorruptions[corruptionIdx] !== 0) { + let corrToLoad: Corruptions + // Support old format (which is bad) + if (Array.isArray(data.usedCorruptions)) { + corrToLoad = convertInputToCorruption(data.usedCorruptions.slice(2, 10)) + } else { + corrToLoad = data.usedCorruptions + } + + for (const corruption in corrToLoad) { + const corrKey = corruption as keyof Corruptions + if (corrToLoad[corrKey] !== 0) { corruptions += `${corrs > 0 ? '/' : ''}${data.usedCorruptions[corruptionIdx]}` - } else { - corruptions += `${corrs > 0 ? '/0' : '0'}` + resetHistoryCorruptionInfo[corrKey].image + }" title="${resetHistoryCorruptionInfo[corrKey].title}">${corrToLoad[corrKey]}` } corrs++ } + + const corr_str = JSON.stringify(corrToLoad) + if (corruptions) { - loadout += `` + loadout += `` } if (data.currentChallenge !== undefined) { score += ` / C${data.currentChallenge}` diff --git a/src/Hotkeys.ts b/src/Hotkeys.ts index d7219c2b3..e8a6ea968 100644 --- a/src/Hotkeys.ts +++ b/src/Hotkeys.ts @@ -34,7 +34,7 @@ export const defaultHotkeys = new Map unknown, /* hide du ['ARROWUP', ['Back a subtab', () => kbTabChange(-1, true), false]], ['ARROWDOWN', ['Next subtab', () => kbTabChange(1, true), false]], ['SHIFT+A', ['Reset Ascend', () => resetCheck('ascension'), false]], - ['SHIFT+C', ['Cleanse Corruptions', () => toggleCorruptionLevel(10, 999), false]], + ['SHIFT+C', ['Cleanse Corruptions', () => toggleCorruptionLevel('illiteracy', 999, true), false]], ['SHIFT+D', ['Spec. Action Add x1', () => promocodes('add', 1), false]], ['SHIFT+E', ['Exit Asc. Challenge', () => resetCheck('ascensionChallenge'), false]], // Its already checks if inside Asc. Challenge ['SHIFT+O', ['Use Off. Potion', () => useConsumable('offeringPotion'), false]], diff --git a/src/ImportExport.ts b/src/ImportExport.ts index 27b8bd7ff..904d31e74 100644 --- a/src/ImportExport.ts +++ b/src/ImportExport.ts @@ -9,6 +9,7 @@ import { testing, version } from './Config' import { Synergism } from './Events' import { addTimers } from './Helper' import { getQuarkBonus, quarkHandler } from './Quark' +import { Seed, seededBetween, seededRandom } from './RNG' import { playerJsonSchema } from './saves/PlayerJsonSchema' import { shopData } from './Shop' import { singularityData } from './singularity' @@ -245,10 +246,9 @@ export const exportSynergism = async ( ? 1 + player.highestSingularityCount / 50 : 1 if (+player.singularityUpgrades.goldenQuarks3.getEffect().bonus > 0) { - player.goldenQuarks += Math.floor( - player.goldenQuarksTimer - / (3600 / +player.singularityUpgrades.goldenQuarks3.getEffect().bonus) - ) * bonusGQMultiplier + player.goldenQuarks += + Math.floor(player.goldenQuarksTimer / (3600 / +player.singularityUpgrades.goldenQuarks3.getEffect().bonus)) + * bonusGQMultiplier player.goldenQuarksTimer = player.goldenQuarksTimer % (3600 / +player.singularityUpgrades.goldenQuarks3.getEffect().bonus) } @@ -361,8 +361,6 @@ export const importSynergism = async (input: string | null, reset = false) => { localStorage.setItem('Synergysave2', saveString) await localforage.setItem('Synergysave2', item) - localStorage.setItem('saveScumIsCheating', Date.now().toString()) - await reloadShit(reset) saveCheck.canSave = true return @@ -501,7 +499,7 @@ export const promocodes = async (input: string | null, amount?: number) => { el.textContent = i18next.t('importexport.promocodes.antismith') } else if (input === 'Khafra' && !player.codes.get(26)) { player.codes.set(26, true) - const quarks = Math.floor(Math.random() * (400 - 100 + 1) + 100) + const quarks = Math.floor(seededRandom(Seed.PromoCodes) * (400 - 100 + 1) + 100) player.worlds.add(quarks) el.textContent = i18next.t('importexport.promocodes.khafra', { x: player.worlds.applyBonus(quarks) @@ -567,6 +565,32 @@ export const promocodes = async (input: string | null, amount?: number) => { singOfferings1: { value: 1, pdf: (x: number) => 600 < x && x <= 800 }, ascensions: { value: 1, pdf: (x: number) => 800 < x && x <= 1000 } } + + const upgradeDistributionOcts = { + octeractImprovedQuarkHept: { value: 0.03, pdf: (x: number) => 0 <= x && x < 4, limit: 1 }, + octeractOneMindImprover: { value: 0.03, pdf: (x: number) => 4 <= x && x < 12, limit: 1 }, + octeractAscensionsOcteractGain: { value: 0.09, pdf: (x: number) => 12 <= x && x < 20, limit: 3 }, + octeractImprovedDaily3: { value: 0.1, pdf: (x: number) => 20 <= x && x < 40, limit: 5 }, + octeractImprovedDaily2: { value: 0.1, pdf: (x: number) => 40 <= x && x < 60, limit: 5 }, + octeractImprovedDaily: { value: 0.1, pdf: (x: number) => 60 <= x && x < 80, limit: 5 }, + octeractImprovedFree4: { value: 0.2, pdf: (x: number) => 80 <= x && x < 100, limit: 10 }, + octeractQuarkGain: { value: 20, pdf: (x: number) => 100 <= x && x < 200, limit: 2000 }, + octeractImprovedGlobalSpeed: { value: 2, pdf: (x: number) => 200 <= x && x < 300, limit: 200 }, + octeractImprovedAscensionSpeed: { value: 0.3, pdf: (x: number) => 300 <= x && x < 400, limit: 30 }, + octeractImprovedAscensionSpeed2: { value: 1, pdf: (x: number) => 400 <= x && x < 500, limit: 100 }, + octeractAmbrosiaGeneration: { value: 0.05, pdf: (x: number) => 500 <= x && x < 525, limit: 5 }, + octeractAmbrosiaGeneration2: { value: 0.05, pdf: (x: number) => 525 <= x && x < 550, limit: 5 }, + octeractAmbrosiaGeneration3: { value: 0.05, pdf: (x: number) => 550 <= x && x < 575, limit: 5 }, + octeractAmbrosiaGeneration4: { value: 0.05, pdf: (x: number) => 575 <= x && x < 600, limit: 5 }, + octeractAmbrosiaLuck: { value: 0.2, pdf: (x: number) => 600 <= x && x < 625, limit: 20 }, + octeractAmbrosiaLuck2: { value: 0.2, pdf: (x: number) => 625 <= x && x < 650, limit: 20 }, + octeractAmbrosiaLuck3: { value: 0.2, pdf: (x: number) => 650 <= x && x < 675, limit: 20 }, + octeractAmbrosiaLuck4: { value: 0.2, pdf: (x: number) => 675 <= x && x < 700, limit: 20 }, + octeractAscensions2: { value: 10, pdf: (x: number) => 700 <= x && x < 800, limit: -1 }, + octeractObtainium1: { value: 5, pdf: (x: number) => 800 <= x && x < 900, limit: -1 }, + octeractOfferings1: { value: 5, pdf: (x: number) => 900 <= x && x <= 1000, limit: -1 } + } + let rolls = 3 * Math.sqrt(player.highestSingularityCount) rolls += +player.octeractUpgrades.octeractImprovedDaily.getEffect().bonus rolls += player.shopUpgrades.shopImprovedDaily2 @@ -582,18 +606,38 @@ export const promocodes = async (input: string | null, amount?: number) => { if (player.highestSingularityCount >= 200) { rolls *= 2 } + if (player.highestSingularityCount >= 250) { + rolls *= 30 + } rolls = Math.floor(rolls) + const transfiguration = +player.pixelUpgrades.pixelFreeUpgradeImprovement.bonus.proportion + + +player.pixelUpgrades.pixelFreeUpgradeImprovement2.bonus.proportion + + +player.pixelUpgrades.pixelFreeUpgradeImprovement3.bonus.proportion + + let transfigured = 0 + for (let i = 1; i <= rolls; i++) { + if (seededRandom(Seed.PromoCodes) < transfiguration) { + transfigured += 1 + } + } + + rolls -= transfigured + const keys = Object.keys(player.singularityUpgrades).filter( (key) => key in upgradeDistribution ) as (keyof typeof upgradeDistribution)[] + const transfiguredKeys = Object.keys(player.octeractUpgrades).filter( + (key) => key in upgradeDistributionOcts + ) as (keyof typeof upgradeDistributionOcts)[] + rewardMessage = i18next.t('importexport.promocodes.daily.message2') // The same upgrade can be drawn several times, so we save the sum of the levels gained, to display them only once at the end const freeLevels: Record = {} for (let i = 0; i < rolls; i++) { - const num = 1000 * Math.random() + const num = 1000 * seededRandom(Seed.PromoCodes) for (const key of keys) { if (upgradeDistribution[key].pdf(num)) { player.singularityUpgrades[key].freeLevels += upgradeDistribution[key].value @@ -604,6 +648,33 @@ export const promocodes = async (input: string | null, amount?: number) => { } } + const transfiguredFreeLevels: Record = {} + while (transfigured > 0) { + const num = 1000 * seededRandom(Seed.PromoCodes) + for (const key of transfiguredKeys) { + if (upgradeDistributionOcts[key].pdf(num)) { + const limit = upgradeDistributionOcts[key].limit + const value = upgradeDistributionOcts[key].value + if (player.octeractUpgrades[key].freeLevels >= limit && limit !== -1) { + break + } else { + if (limit !== -1) { + player.octeractUpgrades[key].freeLevels = Math.min( + limit, + player.octeractUpgrades[key].freeLevels + value + ) + } else { + player.octeractUpgrades[key].freeLevels += value + } + transfigured -= 1 + transfiguredFreeLevels[key] + ? (freeLevels[key] += value) + : (freeLevels[key] = value) + } + } + } + } + if (player.highestSingularityCount >= 20) { player.singularityUpgrades.goldenQuarks1.freeLevels += 0.2 freeLevels.goldenQuarks1 @@ -655,6 +726,9 @@ export const promocodes = async (input: string | null, amount?: number) => { for (const key of Object.keys(freeLevels)) { rewardMessage += dailyCodeFormatFreeLevelMessage(key, freeLevels[key]) } + for (const key of Object.keys(transfiguredFreeLevels)) { + rewardMessage += dailyCodeFormatFreeLevelMessage(key, transfiguredFreeLevels[key]) + } await Alert(rewardMessage) } return @@ -852,13 +926,9 @@ export const promocodes = async (input: string | null, amount?: number) => { } else if (input === 'gamble') { if ( typeof player.skillCode === 'number' - || typeof localStorage.getItem('saveScumIsCheating') === 'string' ) { if ( - (Date.now() - player.skillCode!) / 1000 < 3600 - || (Date.now() - Number(localStorage.getItem('saveScumIsCheating'))) - / 1000 - < 3600 + (Date.now() - player.skillCode) / 1000 < 3600 ) { return (el.textContent = i18next.t( 'importexport.promocodes.gamble.wait' @@ -867,7 +937,7 @@ export const promocodes = async (input: string | null, amount?: number) => { } const confirmed = await Confirm( - i18next.t('importexport.promocodes.gamble.confirm') + i18next.t('importexport.promocodes.gamble.prompt') ) if (!confirmed) { return (el.textContent = i18next.t( @@ -890,8 +960,7 @@ export const promocodes = async (input: string | null, amount?: number) => { )) } - localStorage.setItem('saveScumIsCheating', Date.now().toString()) - const dice = (window.crypto.getRandomValues(new Uint8Array(1))[0] % 6) + 1 // [1, 6] + const dice = seededBetween(Seed.PromoCodes, 1, 6) if (dice === 1) { const won = bet * 0.25 // lmao @@ -915,7 +984,7 @@ export const promocodes = async (input: string | null, amount?: number) => { const rewardMult = timeCodeRewardMultiplier() - const random = Math.random() * 15000 // random time within 15 seconds + const random = seededRandom(Seed.PromoCodes) * 15000 // random time within 15 seconds const start = Date.now() const playerConfirmed = await Confirm( i18next.t('importexport.promocodes.time.confirm', { @@ -1102,7 +1171,7 @@ export const addCodeBonuses = () => { const sampledMult = Math.max( 0.4 + 0.02 * player.shopUpgrades.calculator3, - 2 / 5 + (window.crypto.getRandomValues(new Uint16Array(2))[0] % 128) / 640 + 2 / 5 + seededBetween(Seed.PromoCodes, 0, 127) / 640 ) // [0.4, 0.6], slightly biased in favor of 0.4. =) const minMult = 0.4 + 0.02 * player.shopUpgrades.calculator3 const maxMult = 0.6 @@ -1155,7 +1224,7 @@ const dailyCodeFormatFreeLevelMessage = ( const upgradeNiceName = upgradeKey in singularityData ? i18next.t(`singularity.data.${upgradeKey}.name`) : i18next.t(`octeract.data.${upgradeKey}.name`) - return `\n+${format(freeLevelAmount, 0, true)} extra levels of '${upgradeNiceName}'` + return `\n+${format(freeLevelAmount, 2, true)} extra levels of '${upgradeNiceName}'` } const dailyCodeReward = () => { diff --git a/src/Login.ts b/src/Login.ts index 206851a0b..c0174add2 100644 --- a/src/Login.ts +++ b/src/Login.ts @@ -1,10 +1,15 @@ +/// + import i18next from 'i18next' import localforage from 'localforage' +import { z } from 'zod' import { DOMCacheGetOrSet } from './Cache/DOM' +import { testing } from './Config' import { importSynergism } from './ImportExport' import { QuarkHandler, setQuarkBonus } from './Quark' +import { playerJsonSchema } from './saves/PlayerJsonSchema' import { player } from './Synergism' -import { Alert } from './UpdateHTML' +import { Alert, Notification } from './UpdateHTML' // Consts for Patreon Supporter Roles. const TRANSCENDED_BALLER = '756419583941804072' @@ -75,7 +80,6 @@ interface SynergismPatreonUserAPIResponse extends SynergismUserAPIResponse { type CloudSave = null | { save: string } export async function handleLogin () { - const subtabElement = document.querySelector('#accountSubTab > div.scrollbarX')! const currentBonus = DOMCacheGetOrSet('currentBonus') const response = await fetch('https://synergism.cc/api/v1/users/me') @@ -86,16 +90,59 @@ export async function handleLogin () { return } - const { globalBonus, member, personalBonus, type } = await response.json() as - | SynergismDiscordUserAPIResponse - | SynergismPatreonUserAPIResponse + setAccount(await response.json()) +} + +async function logout () { + await fetch('https://synergism.cc/api/v1/users/logout') + await Alert(i18next.t('account.logout')) + + location.reload() +} + +async function saveToCloud () { + const save = (await localforage.getItem('Synergysave2') + .then((b) => b?.text()) + .catch(() => null)) ?? localStorage.getItem('Synergysave2') + + if (typeof save !== 'string') { + console.log('Yeah, no save here.') + return + } + + const body = new FormData() + body.set('savefile', new File([save], 'file.txt'), 'file.txt') + + const response = await fetch('https://synergism.cc/api/v1/saves/upload', { + method: 'POST', + body + }) + + if (!response.ok) { + await Alert(`Received an error: ${await response.text()}`) + return + } +} + +async function getCloudSave () { + const response = await fetch('https://synergism.cc/api/v1/saves/get') + const save = await response.json() as CloudSave + + await importSynergism(save?.save ?? null) +} + +export function setAccount ( + { globalBonus, member, personalBonus, type }: SynergismDiscordUserAPIResponse | SynergismPatreonUserAPIResponse +) { + const subtabElement = document.querySelector('#accountSubTab > div.scrollbarX')! + const currentBonus = DOMCacheGetOrSet('currentBonus') setQuarkBonus(100 * (1 + globalBonus / 100) * (1 + personalBonus / 100) - 100) player.worlds = new QuarkHandler(Number(player.worlds)) currentBonus.textContent = `Generous patrons give you a bonus of ${globalBonus}% more Quarks!` - if (location.hostname !== 'synergism.cc') { + if (location.hostname !== 'synergism.cc' && !testing) { // TODO: better error, make link clickable, etc. subtabElement.textContent = 'Login is not available here, go to https://synergism.cc instead!' } else if (member !== null) { @@ -170,9 +217,38 @@ export async function handleLogin () { cloudSaveParent.appendChild(cloudSaveElement) cloudSaveParent.appendChild(loadCloudSaveElement) + const submitValuesButton = document.createElement('button') + submitValuesButton.textContent = 'Submit Achievement Scores' + submitValuesButton.addEventListener('click', () => { + if (typeof turnstile === 'undefined') { + Alert('You are blocking the captcha script.') + return + } + + const wrapper = document.getElementById('captchaHolder')! + const element = wrapper.querySelector('div.cf-turnstile')! + + wrapper.style.display = 'block' + + turnstile.execute(element, { + sitekey: '0x4AAAAAAAzaJ55G9OiCeFUV', + callback (token) { + uploadValues(token).finally( + () => wrapper.style.display = 'none' + ) + }, + 'error-callback' (error) { + // TODO: https://developers.cloudflare.com/turnstile/troubleshooting/client-side-errors/error-codes/ + Notification(`An error occurred: ${error}`) + wrapper.style.display = 'none' + } + }) + }) + subtabElement.appendChild(logoutElement) + subtabElement.appendChild(submitValuesButton) subtabElement.appendChild(cloudSaveParent) - } else { + } else if (!testing) { // User is not logged in subtabElement.innerHTML = ` @@ -196,40 +272,22 @@ export async function handleLogin () { } } -async function logout () { - await fetch('https://synergism.cc/api/v1/users/logout') - await Alert(i18next.t('account.logout')) +async function uploadValues (token: string) { + const response1 = await fetch('https://synergism.cc/api/v1/roles/upload') + const fields: (keyof z.infer)[] = await response1.json() - location.reload() -} + const p = playerJsonSchema.parse(player) -async function saveToCloud () { - const save = (await localforage.getItem('Synergysave2') - .then((b) => b?.text()) - .catch(() => null)) ?? localStorage.getItem('Synergysave2') + const fd = new FormData() + fd.set('cf-token', token) - if (typeof save !== 'string') { - console.log('Yeah, no save here.') - return + for (const field of fields) { + fd.set(field, JSON.stringify(p[field])) } - const body = new FormData() - body.set('savefile', new File([save], 'file.txt'), 'file.txt') - - const response = await fetch('https://synergism.cc/api/v1/saves/upload', { - method: 'POST', - body + const response2 = await fetch('https://synergism.cc/api/v1/roles/upload', { + method: 'POST' }) - if (!response.ok) { - await Alert(`Received an error: ${await response.text()}`) - return - } -} - -async function getCloudSave () { - const response = await fetch('https://synergism.cc/api/v1/saves/get') - const save = await response.json() as CloudSave - - await importSynergism(save?.save ?? null) + Notification(await response2.text()) } diff --git a/src/Octeracts.ts b/src/Octeracts.ts index f9a27bf7d..9d7cfca58 100644 --- a/src/Octeracts.ts +++ b/src/Octeracts.ts @@ -1,6 +1,11 @@ import i18next from 'i18next' import { DOMCacheGetOrSet } from './Cache/DOM' -import { calculateAmbrosiaGenerationSpeed, calculateAmbrosiaLuck, octeractGainPerSecond } from './Calculate' +import { + calculateAmbrosiaGenerationSpeed, + calculateAmbrosiaLuck, + calculatePixelLuck, + octeractGainPerSecond +} from './Calculate' import type { IUpgradeData } from './DynamicUpgrade' import { DynamicUpgrade } from './DynamicUpgrade' import { format, formatTimeShort, player } from './Synergism' @@ -811,5 +816,45 @@ export const octeractData: Record { G.ambrosiaCurrStats.ambrosiaGenerationSpeed = calculateAmbrosiaGenerationSpeed().value }] + }, + octeractPixelLuck: { + costFormula: (level: number, baseCost: number) => { + const useLevel = level + return baseCost * (Math.pow(1e7, useLevel) - Math.pow(1e7, useLevel - 1)) + }, + maxLevel: 10, + costPerLevel: 1e5, + effect: (n: number) => { + return { + bonus: 2 * n, + get desc () { + return i18next.t('octeract.data.octeractPixelLuck.effect', { n: format(2 * n) }) + } + } + }, + qualityOfLife: true, + cacheUpdates: [() => { + G.pixelCurrStats.pixelLuck = calculatePixelLuck().value + }] + }, + octeractPixelLuck2: { + costFormula: (level: number, baseCost: number) => { + const useLevel = level + return baseCost * (Math.pow(1e4, useLevel) - Math.pow(1e4, useLevel - 1)) + }, + maxLevel: 20, + costPerLevel: 1e52, + effect: (n: number) => { + return { + bonus: 3 * n, + get desc () { + return i18next.t('octeract.data.octeractPixelLuck2.effect', { n: format(3 * n) }) + } + } + }, + qualityOfLife: true, + cacheUpdates: [() => { + G.pixelCurrStats.pixelLuck = calculatePixelLuck().value + }] } } diff --git a/src/PixelUpgrades.ts b/src/PixelUpgrades.ts new file mode 100644 index 000000000..f1b354bf7 --- /dev/null +++ b/src/PixelUpgrades.ts @@ -0,0 +1,830 @@ +import i18next from 'i18next' +import { DOMCacheGetOrSet } from './Cache/DOM' +import { + calculateAmbrosiaGenerationSpeed, + calculateAmbrosiaLuck, + calculateBlueberryInventory, + calculatePixelBarLevelBonuses, + calculatePixelGenerationSpeed, + calculatePixelLuck +} from './Calculate' +import { DynamicUpgrade, type IUpgradeData } from './DynamicUpgrade' +import { format, player } from './Synergism' +import { IconSets } from './Themes' +import type { Player } from './types/Synergism' +import { Alert, Prompt } from './UpdateHTML' +import { visualUpdateProgressPixels } from './UpdateVisuals' +import { Globals as G } from './Variables' + +export type pixelUpgradeNames = + | 'pixelTutorial' + | 'pixelPixelLuck' + | 'pixelAmbrosiaGeneration' + | 'pixelAmbrosiaLuck' + | 'pixelCubes' + | 'pixelQuarks' + | 'pixelObtainium' + | 'pixelOfferings' + +export interface IPixelData extends Omit { + rewards(this: void, n: number): Record + costPerLevel: number + pixelsInvested?: number + qualityOfLife?: boolean + IconSrc: string +} + +export class PixelUpgrade extends DynamicUpgrade { + public pixelsInvested = 0 + readonly costPerLevel: number + public qualityOfLife: boolean + readonly cacheUpdates: (() => void)[] | undefined + readonly rewards: (n: number) => Record + public IconSrc + + constructor (data: IPixelData, key: string) { + const name = i18next.t(`ultimatePixels.data.${key}.name`) + const description = i18next.t(`ultimatePixels.data.${key}.description`) + + super({ ...data, name, description }) + this.pixelsInvested = data.pixelsInvested ?? 0 + this.rewards = data.rewards + this.costPerLevel = data.costPerLevel + this.qualityOfLife = data.qualityOfLife ?? false + this.cacheUpdates = data.cacheUpdates ?? undefined + this.IconSrc = data.IconSrc + } + + getCostTNL (): number { + if (this.level >= this.maxLevel) { + return 0 + } else { + return this.costPerLevel + } + } + + /** + * Buy levels up until togglebuy or maxed. + * @returns An alert indicating cannot afford, already maxed or purchased with how many + * levels purchased + */ + public async buyLevel (event: MouseEvent): Promise { + let maxPurchasable = 1 + let pixelBudget = player.ultimatePixels + + if (event.shiftKey) { + maxPurchasable = 100000 + const buy = Number( + await Prompt( + i18next.t('ultimatePixels.spendPrompt', { + pixels: format(player.ultimatePixels, 0, true) + }) + ) + ) + + if (isNaN(buy) || !isFinite(buy) || !Number.isInteger(buy)) { + // nan + Infinity checks + return Alert(i18next.t('general.validation.finite')) + } + + if (buy === -1) { + pixelBudget = player.ultimatePixels + } else if (buy <= 0) { + return Alert(i18next.t('general.validation.zeroOrLess')) + } else { + pixelBudget = buy + } + pixelBudget = Math.min(player.ultimatePixels, pixelBudget) + } + + if (this.maxLevel > 0) { + maxPurchasable = Math.min( + maxPurchasable, + this.maxLevel - this.level + ) + } + + if (maxPurchasable === 0) { + return Alert(i18next.t('singularity.goldenQuarks.hasUpgrade')) + } + + const toPurchase = Math.min(maxPurchasable, Math.floor(pixelBudget / this.costPerLevel)) + const totalCost = toPurchase * this.costPerLevel + + this.level += toPurchase + this.pixelsInvested += totalCost + player.ultimatePixels -= totalCost + + if (toPurchase === 0) { + return Alert(i18next.t('general.validation.moreThanPlayerHas')) + } + if (toPurchase > 1) { + void Alert( + i18next.t('singularity.goldenQuarks.multiBuyPurchased', { + levels: format(toPurchase) + }) + ) + } + + this.updateUpgradeHTML() + this.updateCaches() + visualUpdateProgressPixels() + } + + // We do not need this method! + toString (): string { + return '' + } + + public get rewardDesc (): string { + const effectiveLevel = this.level + if ('desc' in this.rewards(0)) { + return String(this.rewards(effectiveLevel).desc) + } else { + return 'Contact Platonic or Khafra if you see this (should never occur!)' + } + } + + public get bonus () { + const effectiveLevel = this.level + return this.rewards(effectiveLevel) + } + + updateUpgradeHTML (): void { + DOMCacheGetOrSet('pixelUpgradeName').textContent = this.name + DOMCacheGetOrSet('pixelUpgradeDescription').innerHTML = this.description + DOMCacheGetOrSet('pixelUpgradeCost').innerHTML = i18next.t('ultimatePixels.cost', { + pixels: format(this.getCostTNL(), 0, true) + }) + + const levelColor = (this.level === this.maxLevel) ? 'orchid' : 'white' + + DOMCacheGetOrSet('pixelUpgradeLevel').innerHTML = `${ + i18next.t('main.levelText', { level: this.level, maxLevel: this.maxLevel }) + }` + DOMCacheGetOrSet('pixelUpgradeEffect').innerHTML = this.rewardDesc + + DOMCacheGetOrSet('pixelUpgradeImage').setAttribute( + 'src', + `Pictures/${IconSets[player.iconSet][0]}/${this.IconSrc}.png` + ) + } + + refund (): void { + player.ultimatePixels += this.pixelsInvested + this.pixelsInvested = 0 + this.level = 0 + } +} + +export const pixelData: Record = { + pixelTutorial: { + maxLevel: 10, + costPerLevel: 1, + rewards: (n: number) => { + const cubeAmount = 1 + 0.05 * n + const quarkAmount = 1 + 0.01 * n + return { + cubes: cubeAmount, + quarks: quarkAmount, + get desc () { + return i18next.t('ultimatePixels.data.pixelTutorial.effect', { + cubeAmount: format(100 * (cubeAmount - 1), 0, true), + quarkAmount: format(100 * (quarkAmount - 1), 0, true) + }) + } + } + }, + IconSrc: 'PixelTutorial' + }, + pixelPixelLuck: { + maxLevel: 5, + costPerLevel: 25, + rewards: (n: number) => { + return { + pixelLuck: 4 * n, + get desc () { + return i18next.t('ultimatePixels.data.pixelPixelLuck.effect', { + pixelLuck: 4 * n + }) + } + } + }, + cacheUpdates: [ + () => { + G.pixelCurrStats.pixelLuck = calculatePixelLuck().value + } + ], + IconSrc: 'PixelPixelLuck' + }, + pixelAmbrosiaGeneration: { + maxLevel: 100, + costPerLevel: 1, + rewards: (n: number) => { + const genMult = 1 + n / 200 + return { + ambrosiaGeneration: genMult, + get desc () { + return i18next.t('ultimatePixels.data.pixelAmbrosiaGeneration.effect', { + ambrosiaGeneration: format(100 * (genMult - 1), 2, true) + }) + } + } + }, + cacheUpdates: [ + () => { + G.ambrosiaCurrStats.ambrosiaGenerationSpeed = calculateAmbrosiaGenerationSpeed().value + } + ], + IconSrc: 'PixelAmbrosiaGeneration' + }, + pixelAmbrosiaGeneration2: { + maxLevel: 100, + costPerLevel: 10, + rewards: (n: number) => { + const genMult = 1 + n / 250 + return { + ambrosiaGeneration: genMult, + get desc () { + return i18next.t('ultimatePixels.data.pixelAmbrosiaGeneration2.effect', { + ambrosiaGeneration: format(100 * (genMult - 1), 2, true) + }) + } + } + }, + cacheUpdates: [ + () => { + G.ambrosiaCurrStats.ambrosiaGenerationSpeed = calculateAmbrosiaGenerationSpeed().value + } + ], + IconSrc: 'PixelAmbrosiaGeneration2' + }, + pixelAmbrosiaGeneration3: { + maxLevel: 100, + costPerLevel: 200, + rewards: (n: number) => { + const genMult = 1 + 3 * n / 1000 + return { + ambrosiaGeneration: genMult, + get desc () { + return i18next.t('ultimatePixels.data.pixelAmbrosiaGeneration3.effect', { + ambrosiaGeneration: format(100 * (genMult - 1), 2, true) + }) + } + } + }, + cacheUpdates: [ + () => { + G.ambrosiaCurrStats.ambrosiaGenerationSpeed = calculateAmbrosiaGenerationSpeed().value + } + ], + IconSrc: 'PixelAmbrosiaGeneration3' + }, + pixelAmbrosiaLuck: { + maxLevel: 100, + costPerLevel: 1, + rewards: (n: number) => { + return { + ambrosiaLuck: 3 * n, + get desc () { + return i18next.t('ultimatePixels.data.pixelAmbrosiaLuck.effect', { + ambrosiaLuck: 3 * n + }) + } + } + }, + cacheUpdates: [ + () => { + G.ambrosiaCurrStats.ambrosiaLuck = calculateAmbrosiaLuck().value + } + ], + IconSrc: 'PixelAmbrosiaLuck' + }, + pixelAmbrosiaLuck2: { + maxLevel: 100, + costPerLevel: 10, + rewards: (n: number) => { + return { + ambrosiaLuck: 4 * n, + get desc () { + return i18next.t('ultimatePixels.data.pixelAmbrosiaLuck2.effect', { + ambrosiaLuck: 4 * n + }) + } + } + }, + cacheUpdates: [ + () => { + G.ambrosiaCurrStats.ambrosiaLuck = calculateAmbrosiaLuck().value + } + ], + IconSrc: 'PixelAmbrosiaLuck2' + }, + pixelAmbrosiaLuck3: { + maxLevel: 100, + costPerLevel: 200, + rewards: (n: number) => { + return { + ambrosiaLuck: 5 * n, + get desc () { + return i18next.t('ultimatePixels.data.pixelAmbrosiaLuck3.effect', { + ambrosiaLuck: 5 * n + }) + } + } + }, + cacheUpdates: [ + () => { + G.ambrosiaCurrStats.ambrosiaLuck = calculateAmbrosiaLuck().value + } + ], + IconSrc: 'PixelAmbrosiaLuck3' + }, + pixelCubes: { + maxLevel: 100, + costPerLevel: 1, + rewards: (n: number) => { + const cubeMult = 1 + 3 * n / 200 + return { + cubes: cubeMult, + get desc () { + return i18next.t('ultimatePixels.data.pixelCubes.effect', { + cubeAmount: format(100 * (cubeMult - 1), 2, true) + }) + } + } + }, + IconSrc: 'PixelCubes' + }, + pixelQuarks: { + maxLevel: 100, + costPerLevel: 1, + rewards: (n: number) => { + const quarkMult = 1 + n / 500 + return { + quarks: quarkMult, + get desc () { + return i18next.t('ultimatePixels.data.pixelQuarks.effect', { + quarkAmount: format(100 * (quarkMult - 1), 2, true) + }) + } + } + }, + IconSrc: 'PixelQuarks' + }, + pixelObtainium: { + maxLevel: 100, + costPerLevel: 1, + rewards: (n: number) => { + const obtainiumMult = 1 + n / 100 + return { + obtainium: obtainiumMult, + get desc () { + return i18next.t('ultimatePixels.data.pixelObtainium.effect', { + obtainiumAmount: format(100 * (obtainiumMult - 1), 2, true) + }) + } + } + }, + IconSrc: 'PixelObtainium' + }, + pixelOfferings: { + maxLevel: 100, + costPerLevel: 1, + rewards: (n: number) => { + const offeringMult = 1 + n / 100 + return { + offerings: offeringMult, + get desc () { + return i18next.t('ultimatePixels.data.pixelOfferings.effect', { + offeringAmount: format(100 * (offeringMult - 1), 2, true) + }) + } + } + }, + IconSrc: 'PixelOfferings' + }, + pixelPixelGeneration: { + maxLevel: 40, + costPerLevel: 1, + rewards: (n: number) => { + const addedGeneration = 5 * n + return { + pixelGenerationAdd: addedGeneration, + get desc () { + return i18next.t('ultimatePixels.data.pixelPixelGeneration.effect', { + pixelGeneration: format(addedGeneration, 0, true) + }) + } + } + }, + cacheUpdates: [ + () => { + G.pixelCurrStats.pixelGenerationSpeed = calculatePixelGenerationSpeed().value + } + ], + IconSrc: 'PixelPixelGeneration' + }, + pixelPixelGeneration2: { + maxLevel: 75, + costPerLevel: 10, + rewards: (n: number) => { + const addedGeneration = 8 * n + return { + pixelGenerationAdd: addedGeneration, + get desc () { + return i18next.t('ultimatePixels.data.pixelPixelGeneration2.effect', { + pixelGeneration: format(addedGeneration, 0, true) + }) + } + } + }, + cacheUpdates: [ + () => { + G.pixelCurrStats.pixelGenerationSpeed = calculatePixelGenerationSpeed().value + } + ], + IconSrc: 'PixelPixelGeneration2' + }, + pixelPixelGeneration3: { + maxLevel: 100, + costPerLevel: 200, + rewards: (n: number) => { + const addedGeneration = 12 * n + return { + pixelGenerationAdd: addedGeneration, + get desc () { + return i18next.t('ultimatePixels.data.pixelPixelGeneration3.effect', { + pixelGeneration: format(addedGeneration, 0, true) + }) + } + } + }, + cacheUpdates: [ + () => { + G.pixelCurrStats.pixelGenerationSpeed = calculatePixelGenerationSpeed().value + } + ], + IconSrc: 'PixelPixelGeneration3' + }, + pixelBlueberry: { + maxLevel: 1, + costPerLevel: 50, + rewards: (n: number) => { + const blueberry = n > 0 + return { + blueberry: blueberry, + get desc () { + return i18next.t('ultimatePixels.data.pixelBlueberry.effect', { + blueberry: blueberry ? '[✔]' : '[✖]' + }) + } + } + }, + cacheUpdates: [ + () => { + G.ambrosiaCurrStats.ambrosiaBlueberries = calculateBlueberryInventory().value + }, + () => { + G.ambrosiaCurrStats.ambrosiaGenerationSpeed = calculateAmbrosiaGenerationSpeed().value + } + ], + IconSrc: 'PixelBlueberry' + }, + pixelBlueberry2: { + maxLevel: 1, + costPerLevel: 500, + rewards: (n: number) => { + const blueberry = n > 0 + return { + blueberry: blueberry, + get desc () { + return i18next.t('ultimatePixels.data.pixelBlueberry2.effect', { + blueberry: blueberry ? '[✔]' : '[✖]' + }) + } + } + }, + cacheUpdates: [ + () => { + G.ambrosiaCurrStats.ambrosiaBlueberries = calculateBlueberryInventory().value + }, + () => { + G.ambrosiaCurrStats.ambrosiaGenerationSpeed = calculateAmbrosiaGenerationSpeed().value + } + ], + IconSrc: 'PixelBlueberry2' + }, + pixelBlueberry3: { + maxLevel: 1, + costPerLevel: 5000, + rewards: (n: number) => { + const blueberry = n > 0 + return { + blueberry: blueberry, + get desc () { + return i18next.t('ultimatePixels.data.pixelBlueberry3.effect', { + blueberry: blueberry ? '[✔]' : '[✖]' + }) + } + } + }, + cacheUpdates: [ + () => { + G.ambrosiaCurrStats.ambrosiaBlueberries = calculateBlueberryInventory().value + }, + () => { + G.ambrosiaCurrStats.ambrosiaGenerationSpeed = calculateAmbrosiaGenerationSpeed().value + } + ], + IconSrc: 'PixelBlueberry3' + }, + pixelRoleBonus: { + maxLevel: 1, + costPerLevel: 77777, + rewards: (n: number) => { + const purchased = n > 0 + return { + purchased: purchased, + get desc () { + return i18next.t('ultimatePixels.data.pixelRoleBonus.effect', { + purchased: purchased ? '[✔]' : '[✖]' + }) + } + } + }, + IconSrc: 'PixelRoleBonus' + }, + pixelPixelLuckConverter: { + maxLevel: 1, + costPerLevel: 250, + rewards (n) { + const purchased = n > 0 + const bonus = +purchased * G.ambrosiaCurrStats.ambrosiaLuck / 400 + return { + purchased: purchased, + get desc () { + return i18next.t('ultimatePixels.data.pixelPixelLuckConverter.effect', { + purchased: purchased ? '[✔]' : '[✖]', + luck: format(bonus, 2, true) + }) + } + } + }, + cacheUpdates: [ + () => { + G.pixelCurrStats.pixelLuck = calculatePixelLuck().value + } + ], + IconSrc: 'PixelPixelLuckConverter' + }, + pixelPixelLuckConverter2: { + maxLevel: 1, + costPerLevel: 10000, + rewards (n) { + const purchased = n > 0 + const bonus = +purchased * G.ambrosiaCurrStats.ambrosiaLuck / 400 + return { + purchased: purchased, + get desc () { + return i18next.t('ultimatePixels.data.pixelPixelLuckConverter2.effect', { + purchased: purchased ? '[✔]' : '[✖]', + luck: format(bonus, 2, true) + }) + } + } + }, + cacheUpdates: [ + () => { + G.pixelCurrStats.pixelLuck = calculatePixelLuck().value + } + ], + IconSrc: 'PixelPixelLuckConverter' + }, + pixelFreeUpgradeImprovement: { + maxLevel: 15, + costPerLevel: 25, + rewards (n) { + const upgrades = n + return { + proportion: upgrades, + get desc () { + return i18next.t('ultimatePixels.data.pixelFreeUpgradeImprovement.effect', { + proportion: upgrades + }) + } + } + }, + IconSrc: 'PixelFreeUpgradeImprovement' + }, + pixelFreeUpgradeImprovement2: { + maxLevel: 20, + costPerLevel: 750, + rewards (n) { + const upgrades = n + return { + proportion: upgrades, + get desc () { + return i18next.t('ultimatePixels.data.pixelFreeUpgradeImprovement2.effect', { + proportion: upgrades + }) + } + } + }, + IconSrc: 'PixelFreeUpgradeImprovement2' + }, + pixelFreeUpgradeImprovement3: { + maxLevel: 25, + costPerLevel: 10000, + rewards (n) { + const upgrades = n + return { + proportion: upgrades, + get desc () { + return i18next.t('ultimatePixels.data.pixelFreeUpgradeImprovement3.effect', { + proportion: upgrades + }) + } + } + }, + IconSrc: 'PixelFreeUpgradeImprovement3' + } +} + +export const LEVEL_REQ_ARR = [ + 0, + 1, + 2, + 3, + 4, + 5, + 10, + 15, + 20, + 25, + 30, // 1-10 + 40, + 50, + 60, + 70, + 80, + 90, + 100, + 125, + 150, + 175, // 11-20 + 200, + 250, + 300, + 350, + 400, + 450, + 500, + 550, + 600, + 650, // 21-30 + 700, + 750, + 800, + 850, + 900, + 950, + 1000, + 1100, + 1200, + 1300, // 31-40 + 1400, + 1500, + 1750, + 2000, + 2250, + 2500, + 3000, + 3500, + 4000, + 5000, // 41-50 + 6500, + 8000, + 9500, + 10000, + 12000, + 14000, + 16000, + 18000, + 20000, + 25000, // 51-60 + 30000, + 35000, + 42500, + 50000, + 60000, + 70000, + 80000, + 90000, + 100000, + 1.1e5, // 61-70 + 1.25e5, + 1.4e5, + 1.5e5, + 1.75e5, + 2e5, + 2.25e5, + 2.5e5, + 2.75e5, + 3e5, + 3.4e5, // 71-80 + 3.8e5, + 4.2e5, + 4.6e5, + 5e5, + 5.5e5, + 6e5, + 7e5, + 8e5, + 9e5, + 1e6, // 91-100 + 1.1e6, + 1.2e6, + 1.4e6, + 1.6e6, + 1.8e6, + 2e6, + 2.2e6, + 2.4e6, + 2.7e6, + 3e6, // 91-100] + 3.5e6, + 4e6, + 4.5e6, + 5e6, + 5.5e6, + 6e6, + 7e6, + 8e6, + 9e6, + 1e7, // 101 - 110 + 1.337e7 +] + +export const computeMetaBarLevel = () => { + const toCompare = player.lifetimeUltimatePixels + + let levelLow = 0 + let levelHigh = LEVEL_REQ_ARR.length - 1 + + // Extreme case: + if (player.lifetimeUltimatePixels >= LEVEL_REQ_ARR[levelHigh]) { + return levelHigh + } + + while (true) { + const i = Math.floor(1 / 2 * (levelLow + levelHigh)) + if (toCompare >= LEVEL_REQ_ARR[i]) { + const newIndex = Math.floor(1 / 2 * (i + levelHigh)) + if (i === newIndex) { + break + } + levelLow = i + } else { + const newIndex = Math.floor(1 / 2 * i) + if (i === newIndex) { + break + } + levelHigh = i + } + } + return Math.floor(1 / 2 * (levelLow + levelHigh)) +} +/* +| 'pixelTutorial' +| 'pixelPixelLuck' +| 'pixelAmbrosiaGeneration' +| 'pixelAmbrosiaLuck' +| 'pixelCubes' +| 'pixelQuarks' +| 'pixelObtainium' +| 'pixelOfferings' */ + +export const showBarLevelBonuses = () => { + const bonuses = calculatePixelBarLevelBonuses() + + DOMCacheGetOrSet('pixelBarLevelText').textContent = i18next.t('ultimatePixels.bar.level', { + level: computeMetaBarLevel() + }) + DOMCacheGetOrSet('pixelBarLuckBonus').textContent = `+${bonuses.AmbrosiaLuck} +${ + bonuses.AmbrosiaLuckMult * 100 + }% ☘ Ambrosia Luck` + DOMCacheGetOrSet('pixelBarBlueberrySpeedBonus').textContent = `${ + format(bonuses.BlueberrySpeedMult, 2, true) + }x Blueberry Second Generation` + DOMCacheGetOrSet('pixelBarPixelLuckBonus').textContent = `${bonuses.PixelLuck} +${ + bonuses.PixelLuckMult * 100 + }% ❖ Pixel Luck` + DOMCacheGetOrSet('pixelBarPixelProgressBonus').textContent = `${ + format(bonuses.PixelProgressMult, 3, true) + }x Bar Progress Speed` + DOMCacheGetOrSet('pixelBarCubeMultBonus').textContent = `${format(bonuses.CubeMult, 2, true)}x Cubes` + DOMCacheGetOrSet('pixelBarObtainiumMultBonus').textContent = `${format(bonuses.ObtainiumMult, 2, true)}x Obtainium` + DOMCacheGetOrSet('pixelBarOfferingMultBonus').textContent = `${format(bonuses.OfferingMult, 2, true)}x Offerings` + DOMCacheGetOrSet('pixelBarQuarkBonus').textContent = `${format(bonuses.QuarkMult, 3, true)}x Quarks` +} diff --git a/src/Plugins/Dashboard.ts b/src/Plugins/Dashboard.ts index 68aba3404..9d5017ba6 100644 --- a/src/Plugins/Dashboard.ts +++ b/src/Plugins/Dashboard.ts @@ -88,7 +88,7 @@ const statValues: ((el: HTMLElement) => void)[] = [ (el) => el.textContent = format(player.challenge15Exponent, 0), (el) => el.textContent = player.runeBlessingLevels.slice(1, 6).map((x) => format(x)).join(' / '), (el) => el.textContent = player.runeSpiritLevels.slice(1, 6).map((x) => format(x)).join(' / '), - (el) => el.textContent = player.usedCorruptions.slice(1, 10).join(' / '), + (el) => el.textContent = Object.values(player.corruptions.used.getLoadout()).join(' / '), (el) => el.textContent = player.challengecompletions.slice(1, 6).join(' / '), (el) => el.textContent = player.challengecompletions.slice(6, 11).join(' / '), (el) => el.textContent = player.runelevels.join(' / '), diff --git a/src/RNG.ts b/src/RNG.ts new file mode 100644 index 000000000..9a8b761ed --- /dev/null +++ b/src/RNG.ts @@ -0,0 +1,18 @@ +import { MersenneTwister } from 'fast-mersenne-twister' +import { player } from './Synergism' + +export const seededRandom = (index: SeedValues) => MersenneTwister(player.seed[index]++).random() + +/** + * Generates a random number (inclusive) between {@param min} and {@param max}. + * @param min min + * @param max max + */ +export const seededBetween = (index: SeedValues, min: number, max: number) => + Math.floor(seededRandom(index) * (max - min + 1) + min) + +export const Seed = { + PromoCodes: 0 +} as const + +export type SeedValues = typeof Seed[keyof typeof Seed] diff --git a/src/Reset.ts b/src/Reset.ts index ef0115c2a..6ab7f6293 100644 --- a/src/Reset.ts +++ b/src/Reset.ts @@ -19,7 +19,7 @@ import { calculateTalismanEffects } from './Calculate' import { challengeRequirement } from './Challenges' -import { corrChallengeMinimum, corruptionStatsUpdate, maxCorruptionLevel } from './Corruptions' +import { c15Corruptions, corruptionStatsUpdate } from './Corruptions' import { WowCubes } from './CubeExperimental' import { autoBuyCubeUpgrades, awardAutosCookieUpgrade, updateCubeUpgradeBG } from './Cubes' import { Synergism } from './Events' @@ -299,7 +299,7 @@ const resetAddHistoryEntry = (input: resetNames, from = 'unknown') => { seconds: player.ascensionCounter, date: Date.now(), c10Completions: player.challengecompletions[10], - usedCorruptions: player.usedCorruptions.slice(0), // shallow copy, + usedCorruptions: player.corruptions.used.getLoadout(), corruptionScore: corruptionMetaData[3], wowCubes: corruptionMetaData[4], wowTesseracts: corruptionMetaData[5], @@ -474,7 +474,7 @@ export const reset = (input: resetNames, fast = false, from = 'unknown') => { } if (input === 'reincarnation' || input === 'reincarnationChallenge') { - if (player.usedCorruptions[6] > 10 && player.platonicUpgrades[11] > 0) { + if (player.corruptions.used.getLevel('deflation') > 10 && player.platonicUpgrades[11] > 0) { player.prestigePoints = player.prestigePoints.add(G.reincarnationPointGain) } } @@ -730,28 +730,10 @@ export const reset = (input: resetNames, fast = false, from = 'unknown') => { } } - const maxLevel = maxCorruptionLevel() - player.usedCorruptions = player.prototypeCorruptions.map((curr: number, index: number) => { - if (index >= 2 && index <= 9) { - return Math.min( - maxLevel * (player.challengecompletions[corrChallengeMinimum(index)] > 0 - || player.singularityUpgrades.platonicTau.getEffect().bonus - ? 1 - : 0), - curr - ) - } - return curr - }) - player.usedCorruptions[1] = 0 - player.prototypeCorruptions[1] = 0 - // fix c15 ascension bug by restoring the corruptions if the player ascended instead of leaving - if (player.currentChallenge.ascension === 15 && (input === 'ascension' || input === 'ascensionChallenge')) { - player.usedCorruptions[0] = 0 - player.prototypeCorruptions[0] = 0 - for (let i = 2; i <= 9; i++) { - player.usedCorruptions[i] = 11 - } + if (player.currentChallenge.ascension !== 15) { + player.corruptions.used.setCorruptionLevelsWithChallengeRequirement(player.corruptions.next.getLoadout()) + } else { + player.corruptions.used.setCorruptionLevelsWithChallengeRequirement(c15Corruptions) } corruptionStatsUpdate() @@ -1157,8 +1139,10 @@ export const singularity = async (setSingNumber = -1): Promise => { player.goldenQuarks += calculateGoldenQuarkGain() if (setSingNumber === -1) { - const incrementSingCount = 1 + getFastForwardTotalMultiplier() - player.singularityCount += incrementSingCount + if (player.singularityCount === player.highestSingularityCount) { + const incrementSingCount = 1 + getFastForwardTotalMultiplier() + player.singularityCount += incrementSingCount + } if (player.singularityCount >= player.highestSingularityCount) { player.highestSingularityCount = player.singularityCount @@ -1229,13 +1213,25 @@ export const singularity = async (setSingNumber = -1): Promise => { }] }) ) as unknown as Player['blueberryUpgrades'] + hold.pixelUpgrades = Object.fromEntries( + Object.entries(player.pixelUpgrades).map(([key, value]) => { + return [key, { + level: value.level, + pixelsInvested: value.pixelsInvested, + toggleBuy: value.toggleBuy, + freeLevels: value.freeLevels + }] + }) + ) as unknown as Player['pixelUpgrades'] hold.spentBlueberries = player.spentBlueberries hold.autoChallengeToggles = player.autoChallengeToggles hold.autoChallengeTimer = player.autoChallengeTimer hold.saveString = player.saveString - hold.corruptionLoadouts = player.corruptionLoadouts - hold.corruptionLoadoutNames = player.corruptionLoadoutNames - hold.corruptionShowStats = player.corruptionShowStats + hold.corruptions.saves = Object.fromEntries( + player.corruptions.saves.getSaves().map((save) => { + return [save.name, save.loadout.getLoadout()] + }) + ) hold.toggles = player.toggles hold.retrychallenges = player.retrychallenges hold.resettoggle1 = player.resettoggle1 @@ -1312,6 +1308,7 @@ export const singularity = async (setSingNumber = -1): Promise => { hold.insideSingularityChallenge = player.insideSingularityChallenge hold.ultimatePixels = player.ultimatePixels hold.ultimateProgress = player.ultimateProgress + hold.lifetimeUltimatePixels = player.lifetimeUltimatePixels hold.singularityChallenges = Object.fromEntries( Object.entries(player.singularityChallenges).map(([key, value]) => { return [key, { diff --git a/src/SingularityChallenges.ts b/src/SingularityChallenges.ts index 46115ab7e..82ac86496 100644 --- a/src/SingularityChallenges.ts +++ b/src/SingularityChallenges.ts @@ -294,7 +294,7 @@ export const singularityChallengeData: Record< goldenQuarks: 1 + 0.12 * +(n > 0), blueberries: +(n > 0), shopUpgrade: n >= 20, - luckBonus: n >= 30 ? 0.04 : 0, + luckBonus: n >= 30 ? 0.06 : 0, shopUpgrade2: n >= 30 } }, @@ -330,21 +330,21 @@ export const singularityChallengeData: Record< } }, noOcteracts: { - baseReq: 75, - maxCompletions: 10, + baseReq: 55, + maxCompletions: 25, unlockSingularity: 100, HTMLTag: 'noOcteracts', singularityRequirement: (baseReq: number, completions: number) => { - return baseReq + 13 * completions + return baseReq + 7 * completions }, scalingrewardcount: 1, uniquerewardcount: 3, effect: (n: number) => { return { - octeractPow: 0.02 * n, + octeractPow: 0.01 * n, offeringBonus: n > 0, - obtainiumBonus: n >= 10, - shopUpgrade: n >= 10 + obtainiumBonus: n >= 20, + shopUpgrade: n >= 20 } } }, diff --git a/src/StatCache.ts b/src/StatCache.ts index c6835dbad..7db8372c1 100644 --- a/src/StatCache.ts +++ b/src/StatCache.ts @@ -1,5 +1,6 @@ import { calculateAdditiveLuckMult, + calculateAdditivePixelLuckMult, calculateAmbrosiaGenerationOcteractUpgrade, calculateAmbrosiaGenerationSingularityUpgrade, calculateAmbrosiaGenerationSpeed, @@ -10,6 +11,9 @@ import { calculateCashGrabBlueberryBonus, calculateDilatedFiveLeafBonus, calculateEventBuff, + calculatePixelBarLevelBonuses, + calculatePixelGenerationSpeed, + calculatePixelLuck, calculateSingularityMilestoneBlueberries } from './Calculate' import { @@ -144,6 +148,10 @@ type AmbrosialLuck = | 'BlueberryQuarkLuck1' | 'SingularityBerries' | 'BlueberryUpgrade2' + | 'BarLevel' + | 'PixelUpgrade1' + | 'PixelUpgrade2' + | 'PixelUpgrade3' | 'ShopOcteractAmbrosiaLuck' | 'TwoHundredSixtyNine' | 'OneHundredThirtyOne' @@ -157,20 +165,54 @@ type AmbrosiaGeneration = | 'Event' | 'OcteractBerries' | 'BlueberryPatreon' + | 'BarLevel' + | 'PixelUpgrade1' + | 'PixelUpgrade2' + | 'PixelUpgrade3' | 'Exalt2' | 'CashGrabUltra' | 'Exalt5' -type BlueberryInventory = 'Exalt1' | 'SingularityUpgrade' | 'SingularityPerk' | 'Exalt5' +type BlueberryInventory = + | 'Exalt1' + | 'SingularityUpgrade' + | 'SingularityPerk' + | 'Exalt5' + | 'PixelUpgrade1' + | 'PixelUpgrade2' + | 'PixelUpgrade3' type AmbrosiaLuckAdditiveMult = | 'Base' | 'Exalt1' + | 'BlueberryLuckDilator' | 'SingularityPerk' + | 'BarLevel' | 'ShopUpgrades' | 'Exalt5' | 'Event' +type UltimatePixelGeneration = + | 'Base' + | 'BarLevel' + +type UltimatePixelLuck = + | 'Base' + | 'BarLevel' + | 'PixelUpgrade1' + | 'SingularityPixelLuck1' + | 'SingularityPixelLuck2' + | 'OcteractPixelLuck1' + | 'OcteractPixelLuck2' + | 'BlueberryPixelLuck1' + | 'BlueberryPixelLuck2' + +type UltimatePixelLuckAdditiveMult = + | 'Base' + | 'BarLevel' + | 'Exalt1' + | 'Event' + export class AmbrosiaLuckAdditiveMultCache extends AdditionCache { vals!: Record totalVal!: number @@ -184,7 +226,9 @@ export class AmbrosiaLuckAdditiveMultCache extends AdditionCache { BlueberryUpgrade2: 0, BlueberryCubeLuck1: 0, BlueberryQuarkLuck1: 0, + BarLevel: 0, + PixelUpgrade1: 0, + PixelUpgrade2: 0, + PixelUpgrade3: 0, OneHundredThirtyOne: 0, TwoHundredSixtyNine: 0, ShopOcteractAmbrosiaLuck: 0, Exalt5: 0 } - this.totalVal = 0 - this.usedTotal = 0 + this.totalVal = 100 + this.usedTotal = 100 } updateVal (key: AmbrosialLuck, init = false): void { @@ -297,6 +353,22 @@ export class AmbrosiaLuckCache extends AdditionCache { this.vals[key] = +player.blueberryUpgrades.ambrosiaQuarkLuck1.bonus.ambrosiaLuck break } + case 'BarLevel': { + this.vals[key] = calculatePixelBarLevelBonuses().AmbrosiaLuck + break + } + case 'PixelUpgrade1': { + this.vals[key] = +player.pixelUpgrades.pixelAmbrosiaLuck.bonus.ambrosiaLuck + break + } + case 'PixelUpgrade2': { + this.vals[key] = +player.pixelUpgrades.pixelAmbrosiaLuck2.bonus.ambrosiaLuck + break + } + case 'PixelUpgrade3': { + this.vals[key] = +player.pixelUpgrades.pixelAmbrosiaLuck3.bonus.ambrosiaLuck + break + } case 'OneHundredThirtyOne': { this.vals[key] = player.highestSingularityCount >= 131 ? 131 : 0 break @@ -340,12 +412,16 @@ export class AmbrosiaGenerationCache extends MultiplicationCache { Exalt1: 0, SingularityUpgrade: 0, SingularityPerk: 0, + PixelUpgrade1: 0, + PixelUpgrade2: 0, + PixelUpgrade3: 0, Exalt5: 0 } this.totalVal = 0 @@ -437,6 +533,19 @@ export class BlueberryInventoryCache extends AdditionCache { } case 'Exalt5': { this.vals[key] = +player.singularityChallenges.noAmbrosiaUpgrades.rewards.blueberries + break + } + case 'PixelUpgrade1': { + this.vals[key] = +player.pixelUpgrades.pixelBlueberry.bonus.blueberry + break + } + case 'PixelUpgrade2': { + this.vals[key] = +player.pixelUpgrades.pixelBlueberry2.bonus.blueberry + break + } + case 'PixelUpgrade3': { + this.vals[key] = +player.pixelUpgrades.pixelBlueberry3.bonus.blueberry + break } } const newVal = this.vals[key] @@ -445,6 +554,170 @@ export class BlueberryInventoryCache extends AdditionCache { } } +export class UltimatePixelGenerationCache extends MultiplicationCache { + vals!: Record + public totalVal!: number + + constructor () { + super() + this.reset() + } + + reset () { + this.vals = { + Base: 1, + BarLevel: 1 + } + this.totalVal = 1 + } + + updateVal (key: UltimatePixelGeneration, init = false): void { + const oldVal = this.vals[key] + switch (key) { + case 'Base': { + if (!player.singularityChallenges.limitedAscensions.rewards.ultimateProgressBarUnlock) { + this.vals[key] = 0 + } else { + const ambrosiaGen = player.caches.ambrosiaGeneration.totalVal + const addedBase = +player.pixelUpgrades.pixelPixelGeneration.bonus.pixelGenerationAdd + const addedBase2 = +player.pixelUpgrades.pixelPixelGeneration2.bonus.pixelGenerationAdd + const addedBase3 = +player.pixelUpgrades.pixelPixelGeneration3.bonus.pixelGenerationAdd + this.vals[key] = Math.max(1, Math.min(ambrosiaGen, Math.pow(1000000 * ambrosiaGen, 1 / 3))) + addedBase + + addedBase2 + addedBase3 + } + break + } + case 'BarLevel': { + this.vals[key] = calculatePixelBarLevelBonuses().PixelProgressMult + break + } + } + const newVal = this.vals[key] + this.updateTotal(oldVal, newVal, init) + } +} + +export class UltimatePixelLuckCache extends AdditionCache { + vals!: Record + public totalVal!: number + public usedTotal!: number + + constructor () { + super() + this.reset() + } + + reset () { + this.vals = { + Base: 100, + BarLevel: 0, + PixelUpgrade1: 0, + SingularityPixelLuck1: 0, + SingularityPixelLuck2: 0, + OcteractPixelLuck1: 0, + OcteractPixelLuck2: 0, + BlueberryPixelLuck1: 0, + BlueberryPixelLuck2: 0 + } + this.totalVal = 100 + this.usedTotal = 100 + } + + updateVal (key: UltimatePixelLuck, init = false): void { + const oldVal = this.vals[key] + switch (key) { + case 'Base': { + this.vals[key] = 100 + break + } + case 'BarLevel': { + this.vals[key] = calculatePixelBarLevelBonuses().PixelLuck + break + } + case 'PixelUpgrade1': { + this.vals[key] = +player.pixelUpgrades.pixelPixelLuck.bonus.pixelLuck + break + } + case 'SingularityPixelLuck1': { + this.vals[key] = +player.singularityUpgrades.singPixelLuck.getEffect().bonus + break + } + case 'SingularityPixelLuck2': { + this.vals[key] = +player.singularityUpgrades.singPixelLuck2.getEffect().bonus + break + } + case 'OcteractPixelLuck1': { + this.vals[key] = +player.octeractUpgrades.octeractPixelLuck.getEffect().bonus + break + } + case 'OcteractPixelLuck2': { + this.vals[key] = +player.octeractUpgrades.octeractPixelLuck2.getEffect().bonus + break + } + case 'BlueberryPixelLuck1': { + this.vals[key] = +player.blueberryUpgrades.ambrosiaPixelLuck.bonus.pixelLuck + break + } + case 'BlueberryPixelLuck2': { + this.vals[key] = +player.blueberryUpgrades.ambrosiaPixelLuck2.bonus.pixelLuck + break + } + } + const newVal = this.vals[key] + this.updateTotal(oldVal, newVal, init) + this.usedTotal = Math.floor( + this.totalVal * player.caches.ultimatePixelAdditiveMult.totalVal + ) + } +} + +export class UltimatePixelLuckAdditiveMultCache extends AdditionCache { + vals!: Record + public totalVal!: number + + constructor () { + super() + this.reset() + } + + reset () { + this.vals = { + Base: 1, + BarLevel: 0, + Exalt1: 0, + Event: 0 + } + this.totalVal = 1 + } + + updateVal (key: UltimatePixelLuckAdditiveMult, init = false): void { + const oldVal = this.vals[key] + switch (key) { + case 'Base': { + this.vals[key] = 1 + break + } + case 'BarLevel': { + this.vals[key] = calculatePixelBarLevelBonuses().PixelLuckMult + break + } + case 'Exalt1': { + this.vals[key] = +player.singularityChallenges.noSingularityUpgrades.rewards.luckBonus + break + } + case 'Event': { + this.vals[key] = Globals.isEvent + ? calculateEventBuff(BuffType.AmbrosiaLuck) + : 0 + break + } + } + const newVal = this.vals[key] + this.updateTotal(oldVal, newVal, init) + player.caches.ultimatePixelLuck.updateVal('Base') // Dependant cache, though maybe need a better system than calling Base + } +} + export const cacheReinitialize = () => { // TODO: REMOVE THIS FUCKING SHIT ASS CODE // WHY THE FUCK ARE WE CACHING MATH OPERATIONS??? @@ -462,4 +735,10 @@ export const cacheReinitialize = () => { ambrosiaBlueberries: calculateBlueberryInventory().value, ambrosiaGenerationSpeed: calculateAmbrosiaGenerationSpeed().value } + + Globals.pixelCurrStats = { + pixelAdditiveLuckMult: calculateAdditivePixelLuckMult().value, + pixelLuck: calculatePixelLuck().value, + pixelGenerationSpeed: calculatePixelGenerationSpeed().value + } } diff --git a/src/Statistics.ts b/src/Statistics.ts index 91e325bd4..cb6caf195 100644 --- a/src/Statistics.ts +++ b/src/Statistics.ts @@ -18,6 +18,7 @@ import { calculateHypercubeMultiplier, calculateOcteractMultiplier, calculateOfferings, + calculatePixelLuck, calculatePlatonicMultiplier, calculatePowderConversion, calculateQuarkMultFromPowder, @@ -65,7 +66,9 @@ const associated = new Map([ ['kGQMult', 'goldenQuarkMultiplierStats'], ['kAddStats', 'addCodeStats'], ['kAmbrosiaLuck', 'ambrosiaLuckStats'], - ['kAmbrosiaGenMult', 'ambrosiaGenerationStats'] + ['kAmbrosiaGenMult', 'ambrosiaGenerationStats'], + ['kPixelLuck', 'pixelLuckStats'], + ['kPixelGenMult', 'pixelGenerationStats'] ]) export const displayStats = (btn: HTMLElement) => { @@ -128,6 +131,12 @@ export const loadStatisticsUpdate = () => { case 'ambrosiaGenerationStats': loadStatisticsAmbrosiaGeneration() break + case 'pixelLuckStats': + loadStatisticsPixelLuck() + break + case 'pixelGenerationStats': + loadStatisticsPixelGeneration() + break default: loadStatisticsCubeMultipliers() break @@ -301,11 +310,7 @@ export const loadStatisticsAccelerator = () => { }` DOMCacheGetOrSet('sA11').textContent = `^${ format( - Math.min( - 1, - (1 + player.platonicUpgrades[6] / 30) - * G.viscosityPower[player.usedCorruptions[2]] - ), + player.corruptions.used.corruptionEffects('viscosity'), 3, true ) @@ -425,11 +430,7 @@ export const loadStatisticsMultiplier = () => { }` DOMCacheGetOrSet('sM12').textContent = `^${ format( - Math.min( - 1, - (1 + player.platonicUpgrades[6] / 30) - * G.viscosityPower[player.usedCorruptions[2]] - ), + player.corruptions.used.corruptionEffects('viscosity'), 3, true ) @@ -736,20 +737,23 @@ export const loadStatisticsCubeMultipliers = () => { 18: { acc: 2, desc: 'Cookie Upgrade 8:' }, 19: { acc: 2, desc: 'Total Octeract Bonus:' }, 20: { acc: 2, desc: 'No Singularity Upgrades Challenge:' }, - 21: { acc: 2, desc: 'Citadel [GQ]' }, - 22: { acc: 2, desc: 'Citadel 2 [GQ]' }, - 23: { acc: 4, desc: 'Platonic DELTA' }, - 24: { acc: 2, desc: 'Wow Pass ∞' }, - 25: { acc: 2, desc: 'Unspent Ambrosia Bonus' }, - 26: { acc: 2, desc: 'Module- Tutorial' }, - 27: { acc: 2, desc: 'Module- Cubes 1' }, - 28: { acc: 2, desc: 'Module- Luck-Cube 1' }, - 29: { acc: 2, desc: 'Module- Quark-Cube 1' }, - 30: { acc: 2, desc: 'Module- Cubes 2' }, - 31: { acc: 2, desc: 'Module- Hyperflux' }, - 32: { acc: 2, desc: '20 Ascensions X20 Bonus [EXALT ONLY]' }, - 33: { acc: 2, desc: 'Cash Grab ULTIMATE' }, - 34: { acc: 2, desc: 'Shop EX ULTIMATE' } + 21: { acc: 2, desc: 'Pixel Tutorial:' }, + 22: { acc: 2, desc: 'Pixel Bar Level:' }, + 23: { acc: 2, desc: 'Pixel "Cubes!!!" Upgrade:' }, + 24: { acc: 2, desc: 'Citadel [GQ]' }, + 25: { acc: 2, desc: 'Citadel 2 [GQ]' }, + 26: { acc: 4, desc: 'Platonic DELTA' }, + 27: { acc: 2, desc: 'Wow Pass ∞' }, + 28: { acc: 2, desc: 'Unspent Ambrosia Bonus' }, + 29: { acc: 2, desc: 'Module- Tutorial' }, + 30: { acc: 2, desc: 'Module- Cubes 1' }, + 31: { acc: 2, desc: 'Module- Luck-Cube 1' }, + 32: { acc: 2, desc: 'Module- Quark-Cube 1' }, + 33: { acc: 2, desc: 'Module- Cubes 2' }, + 34: { acc: 2, desc: 'Module- Hyperflux' }, + 35: { acc: 2, desc: '20 Ascensions X20 Bonus [EXALT ONLY]' }, + 36: { acc: 2, desc: 'Cash Grab ULTIMATE' }, + 37: { acc: 2, desc: 'Shop EX ULTIMATE' } } for (let i = 0; i < arr0.length; i++) { const statGCMi = DOMCacheGetOrSet(`statGCM${i + 1}`) @@ -1026,9 +1030,11 @@ export const loadStatisticsOfferingMultipliers = () => { 30: { acc: 3, desc: 'Cube Upgrade Cx4:' }, 31: { acc: 3, desc: 'Offering Electrolosis [OC]:' }, 32: { acc: 3, desc: 'RNG-based Offering Booster:' }, - 33: { acc: 3, desc: '20 Ascensions X20 [EXALT ONLY]' }, - 34: { acc: 3, desc: 'Shop EX ULTIMATE' }, - 35: { acc: 3, desc: 'Event:' } + 33: { acc: 3, desc: 'Pixel Bar Level Bonus' }, + 34: { acc: 3, desc: 'Pixel Upgrade \'Offered Pixels\'' }, + 35: { acc: 3, desc: '20 Ascensions X20 [EXALT ONLY]:' }, + 36: { acc: 3, desc: 'Shop EX ULTIMATE:' }, + 37: { acc: 3, desc: 'Event:' } } for (let i = 0; i < arr.length; i++) { const statOffi = DOMCacheGetOrSet(`statOff${i + 1}`) @@ -1264,11 +1270,7 @@ export const loadObtainiumMultipliers = () => { format( Math.min( 1, - G.illiteracyPower[player.usedCorruptions[5]] - * (1 - + (9 / 100) - * player.platonicUpgrades[9] - * Math.min(100, Math.log10(player.researchPoints + 10))) + player.corruptions.used.corruptionEffects('illiteracy') ), 3 ) @@ -1423,7 +1425,7 @@ export const loadObtainiumMultipliers = () => { }` DOMCacheGetOrSet('sObt54').textContent = `^${ format( - player.usedCorruptions[5] >= 15 + player.corruptions.used.getLevel('illiteracy') >= 15 ? 1 / 4 : 1, 2 @@ -1431,7 +1433,7 @@ export const loadObtainiumMultipliers = () => { }` DOMCacheGetOrSet('sObt55').textContent = `^${ format( - player.usedCorruptions[5] >= 16 + player.corruptions.used.getLevel('illiteracy') >= 16 ? 1 / 4 : 1, 2 @@ -1701,10 +1703,14 @@ export const loadStatisticsAmbrosiaLuck = () => { 7: { acc: 1, desc: 'Ambrosia Luck Module II' }, 8: { acc: 2, desc: 'Ambrosia Cube-Luck Hybrid Module I' }, 9: { acc: 2, desc: 'Ambrosia Quark-Luck Hybrid Module I' }, - 10: { acc: 0, desc: 'Perk: One Hundred Thirty One!' }, - 11: { acc: 0, desc: 'Perk: Two Hundred Sixty Nine!' }, - 12: { acc: 0, desc: 'Shop: Octeract-Based Ambrosia Luck' }, - 13: { acc: 0, desc: 'No Ambrosia Upgrades EXALT' } + 10: { acc: 0, desc: 'Progress Bar Level Bonus' }, + 11: { acc: 0, desc: 'A Pixelated Ambrosia Luck Inducer' }, + 12: { acc: 0, desc: 'A Pixelated Ambrosia Luck Deducer' }, + 13: { acc: 0, desc: 'A Pixelated Ambrosia Luck Convector' }, + 14: { acc: 0, desc: 'Perk: One Hundred Thirty One!' }, + 15: { acc: 0, desc: 'Perk: Two Hundred Sixty Nine!' }, + 16: { acc: 0, desc: 'Shop: Octeract-Based Ambrosia Luck' }, + 17: { acc: 0, desc: 'No Ambrosia Upgrades EXALT' } } for (let i = 0; i < arr.length - 1; i++) { const statALuckMi = DOMCacheGetOrSet(`statALuckM${i + 1}`) @@ -1734,10 +1740,14 @@ export const loadStatisticsAmbrosiaGeneration = () => { 4: { acc: 4, desc: 'Singularity Ambrosia Generation Upgrades' }, 5: { acc: 4, desc: 'Octeract Ambrosia Generation Upgrades' }, 6: { acc: 4, desc: 'Patreon Bonus' }, - 7: { acc: 4, desc: 'One Ascension Challenge EXALT' }, - 8: { acc: 4, desc: 'No Ambrosia Upgrades EXALT' }, - 9: { acc: 4, desc: 'Cash-Grab ULTIMATE' }, - 10: { acc: 4, desc: 'Event Bonus' } + 7: { acc: 4, desc: 'Progress Bar Level Bonus' }, + 8: { acc: 4, desc: 'A Pixelated Ambrosia Quickener' }, + 9: { acc: 4, desc: 'A Pixelated Ambrosia Hastener' }, + 10: { acc: 4, desc: 'A Pixelated Ambrosia Rapidity' }, + 11: { acc: 4, desc: 'One Ascension Challenge EXALT' }, + 12: { acc: 4, desc: 'No Ambrosia Upgrades EXALT' }, + 13: { acc: 4, desc: 'Cash-Grab ULTIMATE' }, + 14: { acc: 4, desc: 'Event Bonus' } } for (let i = 0; i < arr.length; i++) { const statAGenMi = DOMCacheGetOrSet(`statAGenM${i + 1}`) @@ -1749,6 +1759,36 @@ export const loadStatisticsAmbrosiaGeneration = () => { DOMCacheGetOrSet('sAGenMT').textContent = `${format(totalVal, 3, true)}` } +export const loadStatisticsPixelLuck = () => { + const stats = calculatePixelLuck() + const arr = stats.array + const map: Record = { + 1: { acc: 0, desc: 'Base Luck:' }, + 2: { acc: 0, desc: 'Progress Bar Level Bonus:' }, + 3: { acc: 0, desc: 'Pixel Luck Enhancer I' }, + 4: { acc: 0, desc: 'Lucky Little Pixels' }, + 5: { acc: 0, desc: 'Lucky Big Pixels' }, + 6: { acc: 0, desc: 'Mega Pixel Luck Bonus' }, + 7: { acc: 0, desc: 'Tera Pixel Luck Bonus' }, + 8: { acc: 0, desc: 'Blueberry-Infused Pixel Luck Enhancer' }, + 9: { acc: 0, desc: 'Blueberry-Refined Pixel Luck Enhancer' }, + 10: { acc: 2, desc: 'Ambrosia2Pixel Lucks' } + } + + for (let i = 0; i < arr.length - 1; i++) { + const statPLuckMi = DOMCacheGetOrSet(`statPLuckM${i + 1}`) + statPLuckMi.childNodes[0].textContent = map[i + 1].desc + DOMCacheGetOrSet(`sPLuckM${i + 1}`).textContent = `+${format(arr[i], map[i + 1].acc, true)}` + } + + DOMCacheGetOrSet('sPLuckMult').textContent = `x${format(arr[arr.length - 1], 3, true)}` + + const totalVal = Math.floor(stats.value) + DOMCacheGetOrSet('sPLuckMT').innerHTML = `❖ ${format(totalVal, 0)}` +} + +export const loadStatisticsPixelGeneration = () => {} + export const c15RewardUpdate = () => { // dprint-ignore const exponentRequirements = [ diff --git a/src/Summary.ts b/src/Summary.ts index 0425a1e49..5baf5422f 100644 --- a/src/Summary.ts +++ b/src/Summary.ts @@ -450,7 +450,7 @@ export const generateExportSummary = async (): Promise => { } upgradeText = upgradeText + unicodeSymbol - upgradeText = `${upgradeText + octUpg.name}:` + upgradeText = `${upgradeText} ${octUpg.name}:` upgradeText = upgradeText + (octUpg.maxLevel === -1 ? ` Level ${octUpg.level}` : ` Level ${octUpg.level}/${octUpg.maxLevel}`) @@ -473,8 +473,112 @@ export const generateExportSummary = async (): Promise => { octeractUpgradeStats = octeractUpgradeStats + subCategoryDivisor } + // Create Blueberry Stuff + let blueberryUpgradeStats = '\n' + if (player.visitedAmbrosiaSubtab) { + blueberryUpgradeStats = + '===== AMBROSIA UPGRADES =====\n - [★]: Upgrade is MAXED - \n - [∞]: Upgrade is infinite - \n - [ ]: Upgrade INCOMPLETE - \n' + const bluUpgrade = Object.keys(player.blueberryUpgrades) as (keyof Player['blueberryUpgrades'])[] + let totalBluUpgradeCount = 0 + let totalBluUpgradeMax = 0 + let totalAmbrosiaSpent = 0 + + for (const key of bluUpgrade) { + let upgradeText = '' + const bluUpg = player.blueberryUpgrades[key] + + if (bluUpg.maxLevel !== -1) { + totalBluUpgradeCount += 1 + } + if (bluUpg.level === bluUpg.maxLevel) { + totalBluUpgradeMax += 1 + } + totalAmbrosiaSpent += bluUpg.ambrosiaInvested + + let unicodeSymbol = '[ ]' + if (bluUpg.maxLevel === -1) { + unicodeSymbol = '[∞]' + } else if (bluUpg.level === bluUpg.maxLevel) { + unicodeSymbol = '[★]' + } + + upgradeText = upgradeText + unicodeSymbol + upgradeText = `${upgradeText} ${bluUpg.name}:` + upgradeText = upgradeText + (bluUpg.maxLevel === -1 + ? ` Level ${bluUpg.level}` + : ` Level ${bluUpg.level}/${bluUpg.maxLevel}`) + upgradeText = upgradeText + (bluUpg.freeLevels > 0 + ? ` [+${format(bluUpg.freeLevels, 0, true)}]` + : '') + + upgradeText = upgradeText + (bluUpg.freeLevels > 0 + ? ` =+= Effective Level: ${format(bluUpg.level + bluUpg.freeLevels, 0, true)}` + : '') + + upgradeText = `${upgradeText}\n` + blueberryUpgradeStats = blueberryUpgradeStats + upgradeText + } + blueberryUpgradeStats = blueberryUpgradeStats + subCategoryDivisor + blueberryUpgradeStats = `${blueberryUpgradeStats}Upgrades MAXED: ${totalBluUpgradeMax}/${totalBluUpgradeCount}\n` + blueberryUpgradeStats = `${blueberryUpgradeStats}Ambrosia Spent on Upgrades: ${ + format(totalAmbrosiaSpent, 0, true) + }\n` + blueberryUpgradeStats = blueberryUpgradeStats + subCategoryDivisor + } + + // Create Blueberry Stuff + let pixelUpgradeStats = '\n' + if (player.singularityChallenges.limitedAscensions.rewards.ultimateProgressBarUnlock) { + pixelUpgradeStats = + '===== PIXEL UPGRADES =====\n - [★]: Upgrade is MAXED - \n - [∞]: Upgrade is infinite - \n - [ ]: Upgrade INCOMPLETE - \n' + const pixelUpgrade = Object.keys(player.pixelUpgrades) as (keyof Player['pixelUpgrades'])[] + let totalPixelUpgradeCount = 0 + let totalPixelUpgradeMax = 0 + let totalPixelsSpent = 0 + + for (const key of pixelUpgrade) { + let upgradeText = '' + const pixUpg = player.pixelUpgrades[key] + + if (pixUpg.maxLevel !== -1) { + totalPixelUpgradeCount += 1 + } + if (pixUpg.level === pixUpg.maxLevel) { + totalPixelUpgradeMax += 1 + } + totalPixelsSpent += pixUpg.pixelsInvested + + let unicodeSymbol = '[ ]' + if (pixUpg.maxLevel === -1) { + unicodeSymbol = '[∞]' + } else if (pixUpg.level === pixUpg.maxLevel) { + unicodeSymbol = '[★]' + } + + upgradeText = upgradeText + unicodeSymbol + upgradeText = `${upgradeText} ${pixUpg.name}:` + upgradeText = upgradeText + (pixUpg.maxLevel === -1 + ? ` Level ${pixUpg.level}` + : ` Level ${pixUpg.level}/${pixUpg.maxLevel}`) + upgradeText = upgradeText + (pixUpg.freeLevels > 0 + ? ` [+${format(pixUpg.freeLevels, 0, true)}]` + : '') + + upgradeText = upgradeText + (pixUpg.freeLevels > 0 + ? ` =+= Effective Level: ${format(pixUpg.level + pixUpg.freeLevels, 0, true)}` + : '') + + upgradeText = `${upgradeText}\n` + pixelUpgradeStats = pixelUpgradeStats + upgradeText + } + pixelUpgradeStats = pixelUpgradeStats + subCategoryDivisor + pixelUpgradeStats = `${pixelUpgradeStats}Upgrades MAXED: ${totalPixelUpgradeMax}/${totalPixelUpgradeCount}\n` + pixelUpgradeStats = `${pixelUpgradeStats}Ultimate Pixels Spent on Upgrades: ${format(totalPixelsSpent, 0, true)}\n` + pixelUpgradeStats = pixelUpgradeStats + subCategoryDivisor + } + const returnString = - `${titleText}\n${time}\n${ver}\n${firstPlayed}${resources}${octeract}${singularity}${ascension}${reincarnation}${transcension}${prestige}${shopUpgradeStats}${singularityUpgradeStats}${octeractUpgradeStats}` + `${titleText}\n${time}\n${ver}\n${firstPlayed}${resources}${octeract}${singularity}${ascension}${reincarnation}${transcension}${prestige}${shopUpgradeStats}${singularityUpgradeStats}${octeractUpgradeStats}${blueberryUpgradeStats}${pixelUpgradeStats}` try { await navigator.clipboard.writeText(returnString) diff --git a/src/Synergism.ts b/src/Synergism.ts index 7b06d47ef..54d41a096 100644 --- a/src/Synergism.ts +++ b/src/Synergism.ts @@ -58,13 +58,13 @@ import { exitOffline } from './Calculate' import { - corrChallengeMinimum, corruptionButtonsAdd, - corruptionLoadoutSaveLoad, + corruptionLoadLoadout, + CorruptionLoadout, corruptionLoadoutTableCreate, corruptionLoadoutTableUpdate, + CorruptionSaves, corruptionStatsUpdate, - maxCorruptionLevel, updateCorruptionLoadoutNames } from './Corruptions' import { updateCubeUpgradeBG } from './Cubes' @@ -157,10 +157,11 @@ import { disableHotkeys } from './Hotkeys' import { init as i18nInit } from './i18n' import { handleLogin } from './Login' import { octeractData, OcteractUpgrade } from './Octeracts' +import { pixelData, PixelUpgrade } from './PixelUpgrades' import { updatePlatonicUpgradeBG } from './Platonic' import { getQuarkBonus, QuarkHandler } from './Quark' import { playerJsonSchema } from './saves/PlayerJsonSchema' -import { playerSchema } from './saves/PlayerSchema' +import { playerUpdateVarSchema } from './saves/PlayerUpdateVarSchema' import { getFastForwardTotalMultiplier, singularityData, SingularityUpgrade } from './singularity' import { SingularityChallenge, singularityChallengeData } from './SingularityChallenges' import { @@ -168,9 +169,13 @@ import { AmbrosiaLuckAdditiveMultCache, AmbrosiaLuckCache, BlueberryInventoryCache, - cacheReinitialize + cacheReinitialize, + UltimatePixelGenerationCache, + UltimatePixelLuckAdditiveMultCache, + UltimatePixelLuckCache } from './StatCache' import { changeSubTab, changeTab, Tabs } from './Tabs' +import { setupTestingTab } from './Test' import { settingAnnotation, toggleIconSet, toggleTheme } from './Themes' import { clearTimeout, clearTimers, setInterval, setTimeout } from './Timers' import type { PlayerSave } from './types/LegacySynergism' @@ -468,7 +473,7 @@ export const player: Player = { rrow3: false, rrow4: false }, - achievements: Array(281).fill(0) as number[], + achievements: Array(295).fill(0) as number[], achievementPoints: 0, @@ -858,8 +863,25 @@ export const player: Player = { 6: false }, - prototypeCorruptions: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - usedCorruptions: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + corruptions: { + next: new CorruptionLoadout({}), + used: new CorruptionLoadout({}), + saves: new CorruptionSaves({ + 'Loadout 1': {}, + 'Loadout 2': {}, + 'Loadout 3': {}, + 'Loadout 4': {}, + 'Loadout 5': {}, + 'Loadout 6': {}, + 'Loadout 7': {}, + 'Loadout 8': {} + }), + showStats: true + }, + + /*prototypeCorruptions: new CorruptionLoadout({}), + usedCorruptions: new CorruptionLoadout({}), + corruptionLoadouts: { // If you add loadouts don't forget to add loadout names! 1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -880,9 +902,7 @@ export const player: Player = { 'Loadout 6', 'Loadout 7', 'Loadout 8' - ], - corruptionShowStats: true, - + ], */ constantUpgrades: [null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], history: { ants: [], ascend: [], reset: [], singularity: [] }, historyShowPerSecond: false, @@ -1212,6 +1232,14 @@ export const player: Player = { singAmbrosiaGeneration4: new SingularityUpgrade( singularityData.singAmbrosiaGeneration4, 'singAmbrosiaGeneration4' + ), + singPixelLuck: new SingularityUpgrade( + singularityData.singPixelLuck, + 'singPixelLuck' + ), + singPixelLuck2: new SingularityUpgrade( + singularityData.singPixelLuck2, + 'singPixelLuck2' ) }, @@ -1363,6 +1391,14 @@ export const player: Player = { octeractAmbrosiaGeneration4: new OcteractUpgrade( octeractData.octeractAmbrosiaGeneration4, 'octeractAmbrosiaGeneration4' + ), + octeractPixelLuck: new OcteractUpgrade( + octeractData.octeractPixelLuck, + 'octeractPixelLuck' + ), + octeractPixelLuck2: new OcteractUpgrade( + octeractData.octeractPixelLuck2, + 'octeractPixelLuck2' ) }, @@ -1468,6 +1504,18 @@ export const player: Player = { ambrosiaHyperflux: new BlueberryUpgrade( blueberryUpgradeData.ambrosiaHyperflux, 'ambrosiaHyperflux' + ), + ambrosiaPixelLuck: new BlueberryUpgrade( + blueberryUpgradeData.ambrosiaPixelLuck, + 'ambrosiaPixelLuck' + ), + ambrosiaPixelLuck2: new BlueberryUpgrade( + blueberryUpgradeData.ambrosiaPixelLuck2, + 'ambrosiaPixelLuck2' + ), + ambrosiaLuckDilator: new BlueberryUpgrade( + blueberryUpgradeData.ambrosiaLuckDilator, + 'ambrosiaLuckDilator' ) }, @@ -1485,15 +1533,54 @@ export const player: Player = { ultimateProgress: 0, ultimatePixels: 0, + lifetimeUltimatePixels: 0, + + pixelUpgrades: { + pixelTutorial: new PixelUpgrade(pixelData.pixelTutorial, 'pixelTutorial'), + pixelPixelLuck: new PixelUpgrade(pixelData.pixelPixelLuck, 'pixelPixelLuck'), + pixelPixelLuckConverter: new PixelUpgrade(pixelData.pixelPixelLuckConverter, 'pixelPixelLuckConverter'), + pixelPixelLuckConverter2: new PixelUpgrade(pixelData.pixelPixelLuckConverter2, 'pixelPixelLuckConverter2'), + pixelPixelGeneration: new PixelUpgrade(pixelData.pixelPixelGeneration, 'pixelPixelGeneration'), + pixelPixelGeneration2: new PixelUpgrade(pixelData.pixelPixelGeneration2, 'pixelPixelGeneration2'), + pixelPixelGeneration3: new PixelUpgrade(pixelData.pixelPixelGeneration3, 'pixelPixelGeneration3'), + pixelAmbrosiaGeneration: new PixelUpgrade(pixelData.pixelAmbrosiaGeneration, 'pixelAmbrosiaGeneration'), + pixelAmbrosiaGeneration2: new PixelUpgrade(pixelData.pixelAmbrosiaGeneration2, 'pixelAmbrosiaGeneration2'), + pixelAmbrosiaGeneration3: new PixelUpgrade(pixelData.pixelAmbrosiaGeneration3, 'pixelAmbrosiaGeneration3'), + pixelAmbrosiaLuck: new PixelUpgrade(pixelData.pixelAmbrosiaLuck, 'pixelAmbrosiaLuck'), + pixelAmbrosiaLuck2: new PixelUpgrade(pixelData.pixelAmbrosiaLuck2, 'pixelAmbrosiaLuck2'), + pixelAmbrosiaLuck3: new PixelUpgrade(pixelData.pixelAmbrosiaLuck3, 'pixelAmbrosiaLuck3'), + pixelCubes: new PixelUpgrade(pixelData.pixelCubes, 'pixelCubes'), + pixelQuarks: new PixelUpgrade(pixelData.pixelQuarks, 'pixelQuarks'), + pixelObtainium: new PixelUpgrade(pixelData.pixelObtainium, 'pixelObtainium'), + pixelOfferings: new PixelUpgrade(pixelData.pixelOfferings, 'pixelOfferings'), + pixelBlueberry: new PixelUpgrade(pixelData.pixelBlueberry, 'pixelBlueberry'), + pixelBlueberry2: new PixelUpgrade(pixelData.pixelBlueberry2, 'pixelBlueberry2'), + pixelBlueberry3: new PixelUpgrade(pixelData.pixelBlueberry3, 'pixelBlueberry3'), + pixelRoleBonus: new PixelUpgrade(pixelData.pixelRoleBonus, 'pixelRoleBonus'), + pixelFreeUpgradeImprovement: new PixelUpgrade(pixelData.pixelFreeUpgradeImprovement, 'pixelFreeUpgradeImprovement'), + pixelFreeUpgradeImprovement2: new PixelUpgrade( + pixelData.pixelFreeUpgradeImprovement2, + 'pixelFreeUpgradeImprovement2' + ), + pixelFreeUpgradeImprovement3: new PixelUpgrade( + pixelData.pixelFreeUpgradeImprovement3, + 'pixelFreeUpgradeImprovement3' + ) + }, caches: { ambrosiaLuckAdditiveMult: new AmbrosiaLuckAdditiveMultCache(), ambrosiaLuck: new AmbrosiaLuckCache(), ambrosiaGeneration: new AmbrosiaGenerationCache(), - blueberryInventory: new BlueberryInventoryCache() + blueberryInventory: new BlueberryInventoryCache(), + ultimatePixelAdditiveMult: new UltimatePixelLuckAdditiveMultCache(), + ultimatePixelGeneration: new UltimatePixelGenerationCache(), + ultimatePixelLuck: new UltimatePixelLuckCache() }, - lastExportedSave: 0 + lastExportedSave: 0, + + seed: Array.from({ length: 1 }, () => Date.now()) } export const blankSave = Object.assign({}, player, { @@ -1579,7 +1666,7 @@ const loadSynergy = async () => { }) } - const validatedPlayer = playerSchema.safeParse(data) + const validatedPlayer = playerUpdateVarSchema.safeParse(data) if (validatedPlayer.success) { Object.assign(player, validatedPlayer.data) @@ -1619,11 +1706,11 @@ const loadSynergy = async () => { // TODO(@KhafraDev): remove G.currentSingChallenge // fix current sing challenge blank if (player.insideSingularityChallenge) { - const challenges = Object.keys(player.singularityChallenges); + const challenges = Object.keys(player.singularityChallenges) for (let i = 0; i < challenges.length; i++) { if (player.singularityChallenges[challenges[i]].enabled) { - G.currentSingChallenge = singularityChallengeData[challenges[i]].HTMLTag; - break; + G.currentSingChallenge = singularityChallengeData[challenges[i]].HTMLTag + break } } } @@ -2059,22 +2146,6 @@ const loadSynergy = async () => { player.dayCheck.getDate() ) - const maxLevel = maxCorruptionLevel() - player.usedCorruptions = player.usedCorruptions.map( - (curr: number, index: number) => { - if (index >= 2 && index <= 9) { - return Math.min( - maxLevel - * (player.challengecompletions[corrChallengeMinimum(index)] > 0 - ? 1 - : 0), - curr - ) - } - return curr - } - ) - for (let i = 1; i <= 5; i++) { const ascendBuildingI = `ascendBuilding${i as OneToFive}` as const player[ascendBuildingI].generated = new Decimal( @@ -2238,13 +2309,18 @@ const loadSynergy = async () => { } corruptionStatsUpdate() - const corrs = Math.min(8, Object.keys(player.corruptionLoadouts).length) + 1 - for (let i = 0; i < corrs; i++) { - corruptionLoadoutTableUpdate(i) + const numSavefiles = player.corruptions.saves.getSaves().length + + corruptionLoadoutTableUpdate(true, 0) + for (let i = 0; i < numSavefiles; i++) { + corruptionLoadoutTableUpdate(false, i + 1) } showCorruptionStatsLoadouts() updateCorruptionLoadoutNames() + player.corruptions.used.setCorruptionLevelsWithChallengeRequirement(player.corruptions.used.getLoadout()) + player.corruptions.next.setCorruptionLevelsWithChallengeRequirement(player.corruptions.next.getLoadout()) + DOMCacheGetOrSet('researchrunebonus').textContent = i18next.t( 'runes.thanksResearches', { @@ -3285,21 +3361,17 @@ export const updateAllTick = (): void => { a *= G.acceleratorMultiplier a = Math.pow( a, - Math.min( - 1, - (1 + player.platonicUpgrades[6] / 30) - * G.viscosityPower[player.usedCorruptions[2]] - ) + player.corruptions.used.corruptionEffects('viscosity') ) a += 2000 * hepteractEffective('accelerator') a *= G.challenge15Rewards.accelerator a *= 1 + (3 / 10000) * hepteractEffective('accelerator') a = Math.floor(Math.min(1e100, a)) - if (player.usedCorruptions[2] >= 15) { + if (player.corruptions.used.getLevel('viscosity') >= 15) { a = Math.pow(a, 0.2) } - if (player.usedCorruptions[2] >= 16) { + if (player.corruptions.used.getLevel('viscosity') >= 16) { a = 1 } @@ -3532,21 +3604,17 @@ export const updateAllMultiplier = (): void => { } a = Math.pow( a, - Math.min( - 1, - (1 + player.platonicUpgrades[6] / 30) - * G.viscosityPower[player.usedCorruptions[2]] - ) + player.corruptions.used.corruptionEffects('viscosity') ) a += 1000 * hepteractEffective('multiplier') a *= G.challenge15Rewards.multiplier a *= 1 + (3 / 10000) * hepteractEffective('multiplier') a = Math.floor(Math.min(1e100, a)) - if (player.usedCorruptions[2] >= 15) { + if (player.corruptions.used.getLevel('viscosity') >= 15) { a = Math.pow(a, 0.2) } - if (player.usedCorruptions[2] >= 16) { + if (player.corruptions.used.getLevel('viscosity') >= 16) { a = 1 } @@ -3728,7 +3796,7 @@ export const multipliers = (): void => { lol, 1 + ((1 / 20) - * player.usedCorruptions[9] + * player.corruptions.used.getLevel('recession') * Decimal.log(player.coins.add(1), 10)) / (1e7 + Decimal.log(player.coins.add(1), 10)) ) @@ -3743,7 +3811,7 @@ export const multipliers = (): void => { G.globalCoinMultiplier = lol G.globalCoinMultiplier = Decimal.pow( G.globalCoinMultiplier, - G.financialcollapsePower[player.usedCorruptions[9]] + player.corruptions.used.corruptionEffects('recession') ) G.coinOneMulti = new Decimal(1) @@ -4549,7 +4617,7 @@ export const updateAntMultipliers = (): void => { if (player.currentChallenge.ascension !== 15) { G.globalAntMult = Decimal.pow( G.globalAntMult, - 1 - (0.9 / 90) * Math.min(99, sumContents(player.usedCorruptions)) + 1 - (0.9 / 90) * Math.min(99, player.corruptions.used.totalLevels) ) } else { // C15 used to have 9 corruptions set to 11, which above would provide a power of 0.01. Now it's hardcoded this way. @@ -4558,7 +4626,7 @@ export const updateAntMultipliers = (): void => { G.globalAntMult = Decimal.pow( G.globalAntMult, - G.extinctionMultiplier[player.usedCorruptions[7]] + player.corruptions.used.corruptionEffects('extinction') ) G.globalAntMult = G.globalAntMult.times(G.challenge15Rewards.antSpeed) // V2.5.0: Moved ant shop upgrade as 'uncorruptable' @@ -4584,13 +4652,13 @@ export const updateAntMultipliers = (): void => { G.globalAntMult = G.globalAntMult.times(4.44) } - if (player.usedCorruptions[7] >= 14) { + if (player.corruptions.used.getLevel('extinction') >= 14) { G.globalAntMult = Decimal.pow(G.globalAntMult, 0.02) } - if (player.usedCorruptions[7] >= 15) { + if (player.corruptions.used.getLevel('extinction') >= 15) { G.globalAntMult = Decimal.pow(G.globalAntMult, 0.02) } - if (player.usedCorruptions[7] >= 16) { + if (player.corruptions.used.getLevel('extinction') >= 16) { G.globalAntMult = Decimal.pow(G.globalAntMult, 0.02) } @@ -4683,7 +4751,7 @@ export const resetCurrency = (): void => { prestigePow = 1e-4 / (1 + player.challengecompletions[10]) transcendPow = 0.001 } - prestigePow *= G.deflationMultiplier[player.usedCorruptions[6]] + prestigePow *= player.corruptions.used.corruptionEffects('deflation') // Prestige Point Formulae G.prestigePointGain = Decimal.floor( Decimal.pow(player.coinsThisPrestige.dividedBy(1e12), prestigePow) @@ -4698,7 +4766,7 @@ export const resetCurrency = (): void => { Decimal.pow(10, 1e33), Decimal.pow( G.acceleratorEffect, - (1 / 3) * G.deflationMultiplier[player.usedCorruptions[6]] + (1 / 3) * player.corruptions.used.corruptionEffects('deflation') ) ) ) @@ -4973,7 +5041,7 @@ export const resetCheck = async ( } if ( (manual || leaving || player.shopUpgrades.challenge15Auto > 0) - && player.usedCorruptions.slice(2, 10).every((a) => a === 11) + && Object.values(player.corruptions.used.getLoadout()).every((a) => a === 11) ) { if ( player.coins.gte(Decimal.pow(10, player.challenge15Exponent / c15SM)) @@ -5797,7 +5865,7 @@ export const updateAll = (): void => { if ( player.shopUpgrades.challenge15Auto > 0 && player.currentChallenge.ascension === 15 - && player.usedCorruptions.slice(2, 10).every((a) => a === 11) + && Object.values(player.corruptions.used.getLoadout()).every((a) => a === 11) ) { const c15SM = challenge15ScoreMultiplier() if (player.coins.gte(Decimal.pow(10, player.challenge15Exponent / c15SM))) { @@ -5885,6 +5953,7 @@ const tack = (dt: number) => { addTimers('singularity', dt) addTimers('autoPotion', dt) addTimers('ambrosia', dt) + addTimers('pixel', dt) // Triggers automatic rune sacrifice (adds milliseconds to payload timer) if (player.shopUpgrades.offeringAuto > 0 && player.autoSacrificeToggle) { @@ -6056,22 +6125,22 @@ export const synergismHotkeys = (event: KeyboardEvent, key: string): void => { num = -1 } if (player.challengecompletions[11] > 0 && !isNaN(num)) { - if (num >= 0 && num < player.corruptionLoadoutNames.length) { + if (num >= 0 && num < player.corruptions.saves.getSaves().length) { if (player.toggles[41]) { void Notification( i18next.t('main.corruptionLoadoutApplied', { x: num + 1, - y: player.corruptionLoadoutNames[num] + y: player.corruptions.saves.getSaves()[num].name }), 5000 ) } - corruptionLoadoutSaveLoad(false, num + 1) + corruptionLoadLoadout(num) } else { if (player.toggles[41]) { void Notification(i18next.t('main.allCorruptionsZero'), 5000) } - corruptionLoadoutSaveLoad(false, 0) + player.corruptions.next.resetCorruptions() } event.preventDefault() } @@ -6350,6 +6419,10 @@ window.addEventListener('load', async () => { corruptionLoadoutTableCreate() handleLogin().catch(console.error) + + if (testing) { + setupTestingTab() + } }) window.addEventListener('unload', () => { diff --git a/src/Tabs.ts b/src/Tabs.ts index fb88814b1..6d2d4961c 100644 --- a/src/Tabs.ts +++ b/src/Tabs.ts @@ -1,9 +1,11 @@ import { DOMCacheGetOrSet } from './Cache/DOM' import { calculateAmbrosiaGenerationSpeed } from './Calculate' +import { testing } from './Config' import { pressedKeys } from './Hotkeys' import { player } from './Synergism' import { setActiveSettingScreen, + toggleAchievementScreen, toggleBuildingScreen, toggleChallengesScreen, toggleCorruptionLoadoutsStats, @@ -28,7 +30,8 @@ export enum Tabs { Singularity = 9, Settings = 10, Shop = 11, - Event = 12 + Event = 12, + Testing = 13 } /** @@ -112,7 +115,25 @@ const subtabInfo: Record = { ] }, [Tabs.Upgrades]: { subTabList: [] }, - [Tabs.Achievements]: { subTabList: [] }, + [Tabs.Achievements]: { + tabSwitcher: () => toggleAchievementScreen, + subTabList: [ + { + subTabID: '1', + get unlocked () { + return true + }, + buttonID: 'toggleAchievementSubTab1' + }, + { + subTabID: '2', + get unlocked () { + return true + }, + buttonID: 'toggleAchievementSubTab2' + } + ] + }, [Tabs.Runes]: { tabSwitcher: () => toggleRuneScreen, subTabList: [ @@ -264,10 +285,18 @@ const subtabInfo: Record = { return player.singularityChallenges.noSingularityUpgrades.completions >= 1 }, buttonID: 'toggleSingularitySubTab4' + }, + { + subTabID: '5', + get unlocked () { + return player.singularityChallenges.limitedAscensions.completions >= 1 + }, + buttonID: 'toggleSingularitySubTab5' } ] }, - [Tabs.Event]: { subTabList: [] } + [Tabs.Event]: { subTabList: [] }, + [Tabs.Testing]: { subTabList: [] } } class TabRow extends HTMLDivElement { @@ -552,6 +581,11 @@ tabRow.appendButton( .setUnlockedState(() => G.isEvent) .setType(Tabs.Event) .makeDraggable() + .makeRemoveable(), + new $Tab({ class: 'testingTab', id: 'testingtab', i18n: 'tabs.main.testing' }) + .setUnlockedState(() => testing) + .setType(Tabs.Testing) + .makeDraggable() .makeRemoveable() ) diff --git a/src/Test.ts b/src/Test.ts new file mode 100644 index 000000000..ac49fb41d --- /dev/null +++ b/src/Test.ts @@ -0,0 +1,22 @@ +import { testing } from './Config' +import { setAccount } from './Login' +import { assert } from './Utility' + +export function setupTestingTab () { + assert(testing, 'not in testing') + + const tab = document.getElementById('testing')! + const accountSelect = tab.querySelector('select#account-type-select')! + const accountOptions = Array.from(accountSelect.querySelectorAll('option')) + + for (const option of accountOptions) { + option.addEventListener('click', () => { + accountSelect.disabled = true + + fetch(`https://synergism.cc/api/test/login?${option.value}=1`) + .then((response) => response.json()) + .then((account) => setAccount(account)) + .finally(() => accountSelect.disabled = false) + }) + } +} diff --git a/src/Toggles.ts b/src/Toggles.ts index 8194e4d26..eb17f82e5 100644 --- a/src/Toggles.ts +++ b/src/Toggles.ts @@ -3,14 +3,19 @@ import { achievementaward } from './Achievements' import { DOMCacheGetOrSet } from './Cache/DOM' import { calculateRuneLevels } from './Calculate' import { getChallengeConditions } from './Challenges' -import { corruptionDisplay, corruptionLoadoutTableUpdate, maxCorruptionLevel } from './Corruptions' +import { corruptionDisplay, corruptionLoadoutTableUpdate, type Corruptions } from './Corruptions' import { autoResearchEnabled } from './Research' import { reset, resetrepeat } from './Reset' import { format, player, resetCheck } from './Synergism' import { subTabsInMainTab, Tabs } from './Tabs' import type { BuildingSubtab, Player } from './types/Synergism' import { Alert, Prompt, showCorruptionStatsLoadouts, updateChallengeDisplay } from './UpdateHTML' -import { visualUpdateAmbrosia, visualUpdateCubes, visualUpdateOcteracts } from './UpdateVisuals' +import { + visualUpdateAmbrosia, + visualUpdateCubes, + visualUpdateOcteracts, + visualUpdateProgressPixels +} from './UpdateVisuals' import { Globals as G } from './Variables' export const toggleSettings = (toggle: HTMLElement) => { @@ -398,6 +403,25 @@ export const toggleRuneScreen = (indexStr: string) => { player.subtabNumber = index - 1 } +export const toggleAchievementScreen = (indexStr: string) => { + const index = Number(indexStr) + G.achievementScreen = index + for (let i = 1; i <= 2; i++) { + const a = DOMCacheGetOrSet(`toggleAchievementSubTab${i}`) + const b = DOMCacheGetOrSet(`achievementContainer${i}`) + if (i === index) { + a.style.border = '2px solid gold' + a.style.backgroundColor = 'gold' + b.style.display = 'flex' + } else { + a.style.border = '2px solid silver' + a.style.backgroundColor = '' + b.style.display = 'none' + } + } + player.subtabNumber = index - 1 +} + export const toggleChallengesScreen = (indexStr: string) => { const index = Number(indexStr) @@ -464,7 +488,7 @@ export const toggleSaveOff = () => { export const toggleSingularityScreen = (indexStr: string) => { const index = Number(indexStr) - for (let i = 1; i <= 4; i++) { + for (let i = 1; i <= 6; i++) { const a = DOMCacheGetOrSet(`toggleSingularitySubTab${i}`) const b = DOMCacheGetOrSet(`singularityContainer${i}`) if (i === index) { @@ -485,6 +509,10 @@ export const toggleSingularityScreen = (indexStr: string) => { if (player.subtabNumber === 3) { visualUpdateAmbrosia() } + + if (player.subtabNumber === 5) { + visualUpdateProgressPixels() + } } interface ChadContributor { @@ -918,24 +946,10 @@ export const toggleAutoTesseracts = (i: number) => { player.autoTesseracts[i] = !player.autoTesseracts[i] } -export const toggleCorruptionLevel = (index: number, value: number) => { - const current = player.prototypeCorruptions[index] - const maxCorruption = maxCorruptionLevel() - if (value > 0 && current < maxCorruption && 0 < index && index <= 9) { - player.prototypeCorruptions[index] += Math.min(maxCorruption - current, value) - } - if (value < 0 && current > 0 && 0 < index && index <= 9) { - player.prototypeCorruptions[index] -= Math.min(current, -value) - } - player.prototypeCorruptions[index] = Math.min(maxCorruption, Math.max(0, player.prototypeCorruptions[index])) - if (value === 999 && player.currentChallenge.ascension !== 15) { - for (let i = 0; i <= 9; i++) { - player.usedCorruptions[i] = 0 - player.prototypeCorruptions[i] = 0 - if (i > 1) { - corruptionDisplay(i) - } - } +export const toggleCorruptionLevel = (corr: keyof Corruptions, value: number, reset = false) => { + if (reset && player.currentChallenge.ascension !== 15) { + player.corruptions.used.resetCorruptions() + player.corruptions.next.resetCorruptions() corruptionDisplay(G.corruptionTrigger) DOMCacheGetOrSet('corruptionCleanseConfirm').style.visibility = 'hidden' @@ -943,14 +957,17 @@ export const toggleCorruptionLevel = (index: number, value: number) => { if (player.currentChallenge.ascension === 15) { void resetCheck('ascensionChallenge', false, true) } + return } - corruptionDisplay(index) - corruptionLoadoutTableUpdate() + + player.corruptions.next.incrementDecrementLevel(corr, value) + corruptionDisplay(corr) + corruptionLoadoutTableUpdate(true, 0) } export const toggleCorruptionLoadoutsStats = (statsStr: string) => { const stats = statsStr === 'true' - player.corruptionShowStats = stats + player.corruptions.showStats = stats showCorruptionStatsLoadouts() } diff --git a/src/UpdateHTML.ts b/src/UpdateHTML.ts index e87eb01b5..62d53b35f 100644 --- a/src/UpdateHTML.ts +++ b/src/UpdateHTML.ts @@ -10,6 +10,7 @@ import { displayRuneInformation } from './Runes' import { updateSingularityPenalties, updateSingularityPerks } from './singularity' import { format, formatTimeShort, /*formatTimeShort*/ player } from './Synergism' import { Tabs } from './Tabs' +import { toggleAchievementScreen } from './Toggles' import type { OneToFive, ZeroToFour, ZeroToSeven } from './types/Synergism' import { visualUpdateAchievements, @@ -24,6 +25,7 @@ import { visualUpdateSettings, visualUpdateShop, visualUpdateSingularity, + visualUpdateTesting, visualUpdateUpgrades } from './UpdateVisuals' import { createDeferredPromise } from './Utility' @@ -608,6 +610,8 @@ export const hideStuff = () => { DOMCacheGetOrSet('singularitytab').style.backgroundColor = '' DOMCacheGetOrSet('event').style.display = 'none' DOMCacheGetOrSet('eventtab').style.backgroundColor = '' + DOMCacheGetOrSet('testing').style.display = 'none' + DOMCacheGetOrSet('testingtab').style.backgroundColor = '' const tab = DOMCacheGetOrSet('settingstab')! tab.style.backgroundColor = '' @@ -637,6 +641,7 @@ export const hideStuff = () => { y: format(totalachievementpoints), z: (100 * player.achievementPoints / totalachievementpoints).toPrecision(4) }) + toggleAchievementScreen(String(G.achievementScreen)) } else if (G.currentTab === Tabs.Runes) { DOMCacheGetOrSet('runes').style.display = 'block' DOMCacheGetOrSet('runestab').style.backgroundColor = 'blue' @@ -688,6 +693,11 @@ export const hideStuff = () => { DOMCacheGetOrSet('event').style.display = 'block' DOMCacheGetOrSet('eventtab').style.backgroundColor = 'gold' } + + if (G.currentTab === Tabs.Testing) { + DOMCacheGetOrSet('testing').style.display = 'block' + DOMCacheGetOrSet('testingtab').style.backgroundColor = 'red' + } } const visualTab: Record void> = { @@ -703,7 +713,8 @@ const visualTab: Record void> = { [Tabs.WowCubes]: visualUpdateCubes, [Tabs.Corruption]: visualUpdateCorruptions, [Tabs.Singularity]: visualUpdateSingularity, - [Tabs.Event]: visualUpdateEvent + [Tabs.Event]: visualUpdateEvent, + [Tabs.Testing]: visualUpdateTesting } export const htmlInserts = () => { @@ -1013,7 +1024,7 @@ export const buttoncolorchange = () => { player.antPoints.gte( Decimal.pow( G.antUpgradeCostIncreases[i - 1], - player.antUpgrades[i - 1]! * G.extinctionMultiplier[player.usedCorruptions[10]] + player.antUpgrades[i - 1]! * player.corruptions.used.corruptionEffects('extinction') ).times(G.antUpgradeBaseCost[i - 1]) ) ? DOMCacheGetOrSet(`antUpgrade${i}`).classList.add('antUpgradeBtnAvailable') @@ -1080,7 +1091,7 @@ export const updateAchievementBG = () => { } export const showCorruptionStatsLoadouts = () => { - if (player.corruptionShowStats) { + if (player.corruptions.showStats) { DOMCacheGetOrSet('corruptionStats').style.display = 'flex' DOMCacheGetOrSet('corruptionLoadouts').style.display = 'none' DOMCacheGetOrSet('corrStatsBtn').style.borderColor = 'dodgerblue' @@ -1133,7 +1144,9 @@ const tabColors: Partial> = { [Tabs.WowCubes]: 'purple', [Tabs.Corruption]: 'orange', [Tabs.Settings]: 'white', - [Tabs.Shop]: 'limegreen' + [Tabs.Shop]: 'limegreen', + [Tabs.Event]: 'gold', + [Tabs.Testing]: 'red' } export const changeTabColor = () => { diff --git a/src/UpdateVisuals.ts b/src/UpdateVisuals.ts index 4ca4f2784..ad3c6c048 100644 --- a/src/UpdateVisuals.ts +++ b/src/UpdateVisuals.ts @@ -29,6 +29,7 @@ import { version } from './Config' import type { IMultiBuy } from './Cubes' import type { hepteractTypes } from './Hepteracts' import { hepteractTypeList } from './Hepteracts' +import { computeMetaBarLevel, LEVEL_REQ_ARR } from './PixelUpgrades' import { getQuarkBonus, quarkHandler } from './Quark' import { displayRuneInformation } from './Runes' import { getShopCosts, isShopUpgradeUnlocked, shopData, shopUpgradeTypes } from './Shop' @@ -1300,8 +1301,8 @@ export const visualUpdateCorruptions = () => { 'corruptions.antExponent', { exponent: format( - (1 - (0.9 / 90) * sumContents(player.usedCorruptions)) - * G.extinctionMultiplier[player.usedCorruptions[7]], + 1 - (0.9 / 90) * Math.min(99, player.corruptions.used.totalLevels) + * player.corruptions.used.corruptionEffects('extinction'), 3 ) } @@ -1563,20 +1564,15 @@ export const visualUpdateAmbrosia = () => { const requiredTime = calculateRequiredBlueberryTime() const cubePercent = 100 * (calculateAmbrosiaCubeMult() - 1) const quarkPercent = 100 * (calculateAmbrosiaQuarkMult() - 1) - const availableBlueberries = G.ambrosiaCurrStats.ambrosiaBlueberries - player.spentBlueberries - const totalTimePerSecond = G.ambrosiaCurrStats.ambrosiaGenerationSpeed - const progressTimePerSecond = Math.min(totalTimePerSecond, Math.pow(1000 * totalTimePerSecond, 1 / 2)) + const availableBlueberries = player.caches.blueberryInventory.totalVal - player.spentBlueberries + const totalTimePerSecond = player.caches.ambrosiaGeneration.totalVal const barWidth = 100 * Math.min(1, player.blueberryTime / requiredTime) - const pixelBarWidth = 100 * Math.min(1, player.ultimateProgress / 1e6) + const pixelBarWidth = 100 * Math.min(1, player.ultimateProgress / 1000000) DOMCacheGetOrSet('ambrosiaProgress').style.width = `${barWidth}%` DOMCacheGetOrSet('ambrosiaProgressText').textContent = `${format(player.blueberryTime, 0, true)} / ${ format(requiredTime, 0, true) } [+${format(totalTimePerSecond, 0, true)}/s]` - DOMCacheGetOrSet('pixelProgress').style.width = `${pixelBarWidth}%` - DOMCacheGetOrSet('pixelProgressText').textContent = `${format(player.ultimateProgress, 0, true)} / ${ - format(1000000, 0, true) - } [+${format(progressTimePerSecond * 0.02, 2, true)}/s]` const extraLuckHTML = luckBonusPercent > 0.01 ? `[☘${ format( @@ -1591,12 +1587,7 @@ export const visualUpdateAmbrosia = () => { ambrosia: format(player.ambrosia, 0, true), lifetimeAmbrosia: format(player.lifetimeAmbrosia, 0, true) }) - /*DOMCacheGetOrSet('ambrosiaChance').innerHTML = i18next.t( - 'ambrosia.blueberryGeneration', - { - chance: format(totalTimePerSecond, 2, true) - } - )*/ + DOMCacheGetOrSet('ambrosiaAmountPerGeneration').innerHTML = i18next.t( 'ambrosia.perGen', { @@ -1606,13 +1597,6 @@ export const visualUpdateAmbrosia = () => { extra: extraLuckHTML } ) - /* DOMCacheGetOrSet('ambrosiaRNG').innerHTML = i18next.t( - 'ambrosia.blueberrySecond', - { - blueberrySecond: format(player.blueberryTime, 0, true), - thresholdTimer: format(requiredTime, 0, true) - } - )*/ DOMCacheGetOrSet('ambrosiaRewards').innerHTML = i18next.t( 'ambrosia.bonuses', { @@ -1628,6 +1612,73 @@ export const visualUpdateAmbrosia = () => { ) } +export const visualUpdateProgressPixels = () => { + if (G.currentTab !== Tabs.Singularity) { + return + } + + const luck = G.pixelCurrStats.pixelLuck + const baseLuck = luck / G.pixelCurrStats.pixelAdditiveLuckMult + const luckBonusPercent = 100 * (G.pixelCurrStats.pixelAdditiveLuckMult - 1) + const guaranteed = Math.floor(luck / 100) + const chance = luck - 100 * Math.floor(luck / 100) + const requiredTime = 1e6 + const totalTimePerSecond = G.pixelCurrStats.pixelGenerationSpeed + const pixelBarWidth = 100 * Math.min(1, player.ultimateProgress / 1e6) + + const metaBarLevel = computeMetaBarLevel() + const metaPixelBarWidth = 100 * Math.min(1, player.lifetimeUltimatePixels / LEVEL_REQ_ARR[metaBarLevel + 1]) + + DOMCacheGetOrSet('pixelProgress').style.width = `${pixelBarWidth}%` + DOMCacheGetOrSet('pixelProgressText').textContent = `${format(player.ultimateProgress, 0, true)} / ${ + format(requiredTime, 0, true) + } [+${format(totalTimePerSecond, 0, true)}/s]` + + if (metaBarLevel < 100) { + DOMCacheGetOrSet('metaPixelProgress').style.background = 'linear-gradient(to right, #ff5e0f, orange)' + DOMCacheGetOrSet('metaPixelProgressText').style.color = 'white' + } else { + DOMCacheGetOrSet('metaPixelProgress').style.background = 'linear-gradient(to right, lightgoldenrodyellow, white)' + DOMCacheGetOrSet('metaPixelProgressText').style.color = 'crimson' + } + + if (metaBarLevel < (LEVEL_REQ_ARR.length - 1)) { + DOMCacheGetOrSet('metaPixelProgress').style.width = `${metaPixelBarWidth}%` + DOMCacheGetOrSet('metaPixelProgressText').textContent = `Level: ${metaBarLevel} | Lifetime Pixels: ${ + format(player.lifetimeUltimatePixels, 0, true) + }/${format(LEVEL_REQ_ARR[metaBarLevel + 1], 0, true)}` + } else { + DOMCacheGetOrSet('metaPixelProgress').style.width = '100%' + DOMCacheGetOrSet('metaPixelProgressText').textContent = `Level: 100 | Lifetime Pixels: ${ + format(player.lifetimeUltimatePixels, 0, true) + }` + } + + const extraLuckHTML = luckBonusPercent > 0.01 + ? `[❖${ + format( + baseLuck, + 0, + true + ) + } +${format(luckBonusPercent, 2, true)}%]` + : '' + + DOMCacheGetOrSet('ultimatePixelAmount').innerHTML = i18next.t('ultimatePixels.amount', { + pixels: format(player.ultimatePixels, 0, true) + }) + + DOMCacheGetOrSet('ultimatePixelAmountPerGeneration').innerHTML = i18next.t( + 'ultimatePixels.perGen', + { + guaranteed: format(guaranteed, 0, true), + extraChance: format(chance, 0, true), + ultimatePixelLuck: format(luck, 0, true), + extra: extraLuckHTML + } + ) +} + export const visualUpdateShop = () => { if (G.currentTab !== Tabs.Shop) { return @@ -1776,3 +1827,5 @@ export const visualUpdateShop = () => { } export const visualUpdateEvent = () => {} + +export const visualUpdateTesting = () => {} diff --git a/src/Utility.ts b/src/Utility.ts index 61a828c58..2c241ad70 100644 --- a/src/Utility.ts +++ b/src/Utility.ts @@ -155,9 +155,9 @@ export const cleanString = (s: string): string => { return cleaned } -export function assert (condition: unknown): asserts condition { +export function assert (condition: unknown, message?: string): asserts condition { if (!condition) { - throw new TypeError('assertion failed') + throw new TypeError(message || 'assertion failed') } } @@ -192,3 +192,7 @@ export const deepClone = (value: unknown) => { return value }) } + +export const validateNonnegativeInteger = (n: number | string): boolean => { + return Number.isFinite(n) && !Number.isNaN(n) && Number.isInteger(n) +} diff --git a/src/Variables.ts b/src/Variables.ts index 492822538..9b997932f 100644 --- a/src/Variables.ts +++ b/src/Variables.ts @@ -293,6 +293,7 @@ export const Globals: GlobalVariables = { runescreen: 'runes', settingscreen: 'settings', + achievementScreen: 1, talismanResourceObtainiumCosts: [1e13, 1e14, 1e16, 1e18, 1e20, 1e22, 1e24], talismanResourceOfferingCosts: [100, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9], @@ -367,7 +368,7 @@ export const Globals: GlobalVariables = { researchOrderByCost: [], viscosityPower: [1, 0.87, 0.80, 0.75, 0.70, 0.6, 0.54, 0.45, 0.39, 0.33, 0.3, 0.2, 0.1, 0.05, 0, 0, 0], - lazinessMultiplier: [ + dilationMultiplier: [ 1, 1 / 3, 1 / 10, @@ -386,7 +387,7 @@ export const Globals: GlobalVariables = { 1 / 1e80, 1 / 1e100 ], - hyperchallengedMultiplier: [1, 1.2, 1.5, 1.7, 3, 5, 8, 13, 21, 34, 55, 100, 400, 1600, 7777, 18888, 88888], + hyperchallengeMultiplier: [1, 1.2, 1.5, 1.7, 3, 5, 8, 13, 21, 34, 55, 100, 400, 1600, 7777, 18888, 88888], illiteracyPower: [1, 0.8, 0.7, 0.6, 0.5, 0.3, 0.2, 0.15, 0.10, 0.06, 0.04, 0.02, 0.01, 0.005, 0, 0, 0], deflationMultiplier: [ 1, @@ -409,7 +410,7 @@ export const Globals: GlobalVariables = { ], extinctionMultiplier: [1, 0.92, 0.86, 0.8, 0.74, 0.65, 0.55, 0.5, 0.45, 0.4, 0.35, 0.3, 0.1, 0, 0, 0, 0], droughtMultiplier: [1, 5, 25, 200, 1e4, 1e7, 1e11, 1e16, 1e22, 1e30, 1e40, 1e55, 1e80, 1e120, 1e177, 1e200, 1e250], - financialcollapsePower: [ + recessionPower: [ 1, 0.9, 0.7, @@ -449,7 +450,7 @@ export const Globals: GlobalVariables = { autoTalismanTimer: 0, autoChallengeTimerIncrement: 0, - corruptionTrigger: 1, + corruptionTrigger: 'illiteracy', challenge15Rewards: { cube1: 1, @@ -505,6 +506,7 @@ export const Globals: GlobalVariables = { eventClicked: false, ambrosiaTimer: 0, + pixelTimer: 0, TIME_PER_AMBROSIA: 600, ambrosiaCurrStats: { @@ -514,6 +516,12 @@ export const Globals: GlobalVariables = { ambrosiaGenerationSpeed: 1 }, + pixelCurrStats: { + pixelAdditiveLuckMult: 1, + pixelLuck: 100, + pixelGenerationSpeed: 1 + }, + currentSingChallenge: undefined } diff --git a/src/saves/PlayerJsonSchema.ts b/src/saves/PlayerJsonSchema.ts index 850624504..dae795cc9 100644 --- a/src/saves/PlayerJsonSchema.ts +++ b/src/saves/PlayerJsonSchema.ts @@ -1,7 +1,21 @@ import { z } from 'zod' +import type { Corruptions } from '../Corruptions' import type { Player } from '../types/Synergism' import { playerSchema } from './PlayerSchema' +const convertArrayToCorruption = (array: number[]): Corruptions => { + return { + viscosity: array[2], + dilation: array[3], + hyperchallenge: array[4], + illiteracy: array[5], + deflation: array[6], + extinction: array[7], + drought: array[8], + recession: array[9] + } +} + export const playerJsonSchema = playerSchema.extend({ codes: z.any().transform((codes: Player['codes']) => Array.from(codes)), worlds: z.any().transform((worlds: Player['worlds']) => Number(worlds)), @@ -10,6 +24,18 @@ export const playerJsonSchema = playerSchema.extend({ wowHypercubes: z.any().transform((hypercubes: Player['wowHypercubes']) => Number(hypercubes)), wowPlatonicCubes: z.any().transform((cubes: Player['wowPlatonicCubes']) => Number(cubes)), + corruptions: z.any().transform((stuff: Player['corruptions']) => { + return { + used: stuff.used.getLoadout(), + next: stuff.next.getLoadout(), + saves: Object.fromEntries( + stuff.saves.getSaves().map((save) => { + return [save.name, save.loadout.getLoadout()] + }) + ), + showStats: stuff.showStats + } + }), singularityUpgrades: z.any().transform((upgrades: Player['singularityUpgrades']) => Object.fromEntries( Object.entries(upgrades).map(([key, value]) => { @@ -70,6 +96,55 @@ export const playerJsonSchema = playerSchema.extend({ }) ) ), - + pixelUpgrades: z.any().transform((upgrades: Player['pixelUpgrades']) => + Object.fromEntries( + Object.entries(upgrades).map(([key, value]) => { + return [ + key, + { + level: value.level, + pixelsInvested: value.pixelsInvested, + toggleBuy: value.toggleBuy, + freeLevels: value.freeLevels + } + ] + }) + ) + ), dayCheck: z.any().transform((dayCheck: Player['dayCheck']) => dayCheck?.toISOString() ?? null) +}).transform((player) => { + if (player.usedCorruptions !== undefined) { + const corrLoadout = convertArrayToCorruption(player.usedCorruptions) + player.corruptions.used = corrLoadout + } + + if (player.prototypeCorruptions !== undefined) { + const corrLoadout = convertArrayToCorruption(player.prototypeCorruptions) + player.corruptions.next = corrLoadout + } + + if (player.corruptionShowStats !== undefined) { + player.corruptions.showStats = player.corruptionShowStats + } + + player.corruptions.showStats = player.corruptionShowStats ?? player.corruptions.showStats + + if (player.corruptionLoadouts !== undefined && player.corruptionLoadoutNames !== undefined) { + const corruptionSaveStuff: { [key: string]: Corruptions } = player.corruptionLoadoutNames.reduce( + (map, key, index) => { + map[key] = convertArrayToCorruption(player.corruptionLoadouts![index + 1]) + return map + }, + {} as Record + ) + + player.corruptions.saves = corruptionSaveStuff + } + + player.usedCorruptions = undefined + player.prototypeCorruptions = undefined + player.corruptionLoadoutNames = undefined + player.corruptionLoadouts = undefined + + return player }) diff --git a/src/saves/PlayerSchema.ts b/src/saves/PlayerSchema.ts index bedbef91b..e5fbdc474 100644 --- a/src/saves/PlayerSchema.ts +++ b/src/saves/PlayerSchema.ts @@ -1,9 +1,11 @@ import Decimal from 'break_infinity.js' import { z, type ZodNumber, type ZodType } from 'zod' import { BlueberryUpgrade, blueberryUpgradeData } from '../BlueberryUpgrades' +import { CorruptionLoadout, CorruptionSaves } from '../Corruptions' import { WowCubes, WowHypercubes, WowPlatonicCubes, WowTesseracts } from '../CubeExperimental' import { createHepteract } from '../Hepteracts' import { octeractData, OcteractUpgrade } from '../Octeracts' +import { pixelData, PixelUpgrade } from '../PixelUpgrades' import { QuarkHandler } from '../Quark' import { singularityData, SingularityUpgrade } from '../singularity' import { SingularityChallenge, singularityChallengeData } from '../SingularityChallenges' @@ -54,6 +56,17 @@ const toggleSchema = z.record(z.string(), z.boolean()).transform((record) => { ) }) +const optionalCorruptionSchema = z.object({ + viscosity: z.number().optional(), + drought: z.number().optional(), + deflation: z.number().optional(), + extinction: z.number().optional(), + illiteracy: z.number().optional(), + recession: z.number().optional(), + dilation: z.number().optional(), + hyperchallenge: z.number().optional() +}) + const decimalStringSchema = z.string().regex(/^|-?\d+(\.\d{1,2})?$/) const integerStringSchema = z.string().regex(/^\d+$/) @@ -505,15 +518,26 @@ export const playerSchema = z.object({ roombaResearchIndex: z.number().default(() => blankSave.roombaResearchIndex), ascStatToggles: z.record(integerStringSchema, z.boolean()).default(() => ({ ...blankSave.ascStatToggles })), - prototypeCorruptions: z.number().array().default(() => [...blankSave.prototypeCorruptions]), - usedCorruptions: z.number().array().default(() => [...blankSave.usedCorruptions]), - corruptionLoadouts: z.record(integerStringSchema, z.number().array()).default(() => - deepClone(blankSave.corruptionLoadouts) - ), - corruptionLoadoutNames: z.string().array().default(() => blankSave.corruptionLoadoutNames.slice()).default( - () => [...blankSave.corruptionLoadoutNames] - ), - corruptionShowStats: z.boolean().default(() => blankSave.corruptionShowStats), + corruptions: z.object({ + used: optionalCorruptionSchema.transform((value) => { + return new CorruptionLoadout(value) + }), + next: optionalCorruptionSchema.transform((value) => { + console.log(Object.values(value)) + return new CorruptionLoadout(value) + }), + saves: z.record(z.string(), optionalCorruptionSchema).transform((value) => { + return new CorruptionSaves(value) + }), + showStats: z.boolean() + }).default(() => JSON.parse(JSON.stringify(blankSave.corruptions))), + + prototypeCorruptions: z.number().array().optional(), + usedCorruptions: z.number().array().optional(), + corruptionLoadouts: z.record(integerStringSchema, z.number().array()).optional(), + + corruptionLoadoutNames: z.string().array().optional(), + corruptionShowStats: z.boolean().optional(), constantUpgrades: arrayStartingWithNull(z.number()).default((): [ null, @@ -730,6 +754,32 @@ export const playerSchema = z.object({ ultimateProgress: z.number().default(() => blankSave.ultimateProgress), ultimatePixels: z.number().default(() => blankSave.ultimatePixels), + lifetimeUltimatePixels: z.number().default(() => blankSave.lifetimeUltimatePixels), + + pixelUpgrades: z.record(z.string(), singularityUpgradeSchema('pixelsInvested')) + .transform((upgrades) => + Object.fromEntries( + Object.keys(blankSave.pixelUpgrades).map((k) => { + const { level, pixelsInvested, toggleBuy, freeLevels } = upgrades[k] ?? blankSave.pixelUpgrades[k] + + return [ + k, + new PixelUpgrade({ + maxLevel: pixelData[k].maxLevel, + costPerLevel: pixelData[k].costPerLevel, + level: level as number, + pixelsInvested, + toggleBuy: toggleBuy as number, + rewards: pixelData[k].rewards, + freeLevels: freeLevels as number, + cacheUpdates: pixelData[k].cacheUpdates, + IconSrc: pixelData[k].IconSrc + }, k) + ] + }) + ) + ) + .default(() => JSON.parse(JSON.stringify(blankSave.pixelUpgrades))), // TODO: what type? caches: z.record(z.string(), z.any()) @@ -742,5 +792,7 @@ export const playerSchema = z.object({ return blankSave.caches }), - lastExportedSave: z.number().default(() => blankSave.lastExportedSave) + lastExportedSave: z.number().default(() => blankSave.lastExportedSave), + + seed: z.number().array().default(() => blankSave.seed).transform((value) => arrayExtend(value, 'seed')) }) diff --git a/src/saves/PlayerUpdateVarSchema.ts b/src/saves/PlayerUpdateVarSchema.ts new file mode 100644 index 000000000..5b5d89b53 --- /dev/null +++ b/src/saves/PlayerUpdateVarSchema.ts @@ -0,0 +1,50 @@ +import { CorruptionLoadout, type Corruptions, CorruptionSaves } from '../Corruptions' +import { playerSchema } from './PlayerSchema' + +const convertArrayToCorruption = (array: number[]): Corruptions => { + return { + viscosity: array[2], + dilation: array[3], + hyperchallenge: array[4], + illiteracy: array[5], + deflation: array[6], + extinction: array[7], + drought: array[8], + recession: array[9] + } +} + +export const playerUpdateVarSchema = playerSchema.transform((player) => { + if (player.usedCorruptions !== undefined) { + const corrLoadout = convertArrayToCorruption(player.usedCorruptions) + player.corruptions.used = new CorruptionLoadout(corrLoadout) + } + + if (player.prototypeCorruptions !== undefined) { + const corrLoadout = convertArrayToCorruption(player.prototypeCorruptions) + player.corruptions.next = new CorruptionLoadout(corrLoadout) + } + + if (player.corruptionShowStats !== undefined) { + player.corruptions.showStats = player.corruptionShowStats + } + + if (player.corruptionLoadouts !== undefined && player.corruptionLoadoutNames !== undefined) { + const corruptionSaveStuff: { [key: string]: Corruptions } = player.corruptionLoadoutNames.reduce( + (map, key, index) => { + map[key] = convertArrayToCorruption(player.corruptionLoadouts![index + 1]) + return map + }, + {} as Record + ) + + player.corruptions.saves = new CorruptionSaves(corruptionSaveStuff) + } + + player.usedCorruptions = undefined + player.prototypeCorruptions = undefined + player.corruptionLoadoutNames = undefined + player.corruptionLoadouts = undefined + + return player +}) diff --git a/src/singularity.ts b/src/singularity.ts index fe20d2f22..e351803fb 100644 --- a/src/singularity.ts +++ b/src/singularity.ts @@ -1,11 +1,17 @@ import i18next from 'i18next' import { DOMCacheGetOrSet } from './Cache/DOM' -import { calculateAmbrosiaGenerationSpeed, calculateAmbrosiaLuck, calculateBlueberryInventory } from './Calculate' +import { + calculateAmbrosiaGenerationSpeed, + calculateAmbrosiaLuck, + calculateBlueberryInventory, + calculatePixelLuck +} from './Calculate' import type { IUpgradeData } from './DynamicUpgrade' import { DynamicUpgrade } from './DynamicUpgrade' +import { singularity } from './Reset' import { format, player } from './Synergism' import type { Player } from './types/Synergism' -import { Alert, Prompt, revealStuff } from './UpdateHTML' +import { Alert, Confirm, Prompt, revealStuff } from './UpdateHTML' import { toOrdinal } from './Utility' import { Globals as G } from './Variables' @@ -302,7 +308,7 @@ export class SingularityUpgrade extends DynamicUpgrade { GQBudget = Math.min(player.goldenQuarks, GQBudget) } - if (this.maxLevel > 0) { + if (this.computeMaxLevel() > 0) { maxPurchasable = Math.min( maxPurchasable, this.computeMaxLevel() - this.level @@ -1578,6 +1584,51 @@ export const singularityData: Record< G.ambrosiaCurrStats.ambrosiaGenerationSpeed = calculateAmbrosiaGenerationSpeed().value } ] + }, + singPixelLuck: { + maxLevel: 0, + costPerLevel: 1e7, + minimumSingularity: 60, + canExceedCap: true, + effect: (n: number) => { + return { + bonus: 2 * n, + get desc () { + return i18next.t('singularity.data.singPixelLuck.effect', { + n: format(2 * n) + }) + } + } + }, + specialCostForm: 'Exponential2', + qualityOfLife: false, + cacheUpdates: [ + () => { + G.pixelCurrStats.pixelLuck = calculatePixelLuck().value + } + ] + }, + singPixelLuck2: { + maxLevel: 15, + costPerLevel: 1e20, + minimumSingularity: 271, + effect: (n: number) => { + return { + bonus: 3 * n, + get desc () { + return i18next.t('singularity.data.singPixelLuck2.effect', { + n: format(3 * n) + }) + } + } + }, + specialCostForm: 'Exponential2', + qualityOfLife: false, + cacheUpdates: [ + () => { + G.pixelCurrStats.pixelLuck = calculatePixelLuck().value + } + ] } } @@ -2264,7 +2315,8 @@ export const singularityPerks: SingularityPerk[] = [ // Placeholder text for Perk Info that is seen upon first load, check Line 645 EventListeners.ts for actual Perk Info code. export const updateSingularityPerks = (): void => { - const singularityCount = player.highestSingularityCount + const singularityCount = player.singularityCount + DOMCacheGetOrSet('singularityPerksHeader').innerHTML = i18next.t( 'singularity.perks.header', { @@ -2583,8 +2635,16 @@ export const calculateEffectiveSingularities = ( effectiveSingularities *= 2 } if (singularityCount > 269) { - effectiveSingularities *= 3 - effectiveSingularities *= Math.pow(3, singularityCount - 269) + effectiveSingularities *= 2 + } + if (singularityCount > 279) { + effectiveSingularities *= 2 + } + if (singularityCount > 289) { + effectiveSingularities *= 2 + } + if (singularityCount === 300) { + effectiveSingularities = 4.44e44 } return effectiveSingularities @@ -2661,3 +2721,63 @@ export const calculateSingularityDebuff = ( return Math.cbrt(effectiveSingularities + 1) } } + +export const calculateTotalCacheSeconds = () => { + const singularity = player.singularityCount + + const linearScale = (singularity >= 25) ? singularity * 8 : 0 + const quadraticFactor = (singularity > 100) ? singularity / 100 : 1 + const cubicFactor = (singularity > 200) ? singularity / 150 : 1 + const quarticFactor = (singularity > 250) ? 1 + (singularity - 250) / 25 : 1 + + return linearScale * quadraticFactor * cubicFactor * quarticFactor +} + +export const setSingularity = async () => { + // TODO: Make this i18 compatible. This function was honestly made in a hurry to get the beta out + + if (player.insideSingularityChallenge) { + return Alert('The elevator does not function properly in these EXALTs.') + } + + const c = Number( + await Prompt(`What singularity would you like to travel to? + Your highest singularity is ${player.highestSingularityCount} + Your current singularity is ${player.singularityCount} + You may only select an integer between 1 and the highest singularity, inclusive. If you select a higher number than your current singularity, the singularity resets!`) + ) + + if (isNaN(c) || !isFinite(c) || !Number.isInteger(c)) { + // nan + Infinity checks + return Alert(i18next.t('general.validation.finite')) + } + + if (c < 1) { + return Alert('You are not allowed to break the time-space continuum!') + } + + if (c > player.highestSingularityCount) { + return Alert('You have to reach this singularity before you can elevate to it!') + } + + if (c > player.singularityCount) { + const c2 = await Confirm(`Are you sure you want to go to Singularity ${c}? Your singularity will reset!`) + if (c2) { + singularity(c) + } else { + return Alert(`You remain at Singularity ${player.singularityCount}.`) + } + } + + if (c <= player.singularityCount) { + const c2 = await Confirm( + `This will take you to Singularity ${c} where your progress will not be reset, but Penalties are lighter and Perks are weaker. Proceed?` + ) + if (c2) { + player.singularityCount = c + return Alert(`You are now at Singularity ${c} and nothing has been reset. Enjoy!`) + } else { + return Alert(`You remain at Singularity ${player.singularityCount}.`) + } + } +} diff --git a/src/types/FastMersenneTwister.d.ts b/src/types/FastMersenneTwister.d.ts new file mode 100644 index 000000000..24f24b89b --- /dev/null +++ b/src/types/FastMersenneTwister.d.ts @@ -0,0 +1,24 @@ +declare module 'fast-mersenne-twister' { + interface api { + genrand_int32: () => number + // [0,0x7fffffff] + genrand_int31: () => number + // [0,1] + genrand_real1: () => number + // [0,1) + genrand_real2: () => number + // (0,1) + genrand_real3: () => number + // [0,1), 53-bit resolution + genrand_res53: () => number + + randomNumber: () => number + random31Bit: () => number + randomInclusive: () => number + random: () => number // returns values just like Math.random + randomExclusive: () => number + random53Bit: () => number + } + + export function MersenneTwister (seed?: number): api +} diff --git a/src/types/Synergism.d.ts b/src/types/Synergism.d.ts index cd3e52817..eb1519485 100644 --- a/src/types/Synergism.d.ts +++ b/src/types/Synergism.d.ts @@ -1,9 +1,11 @@ import type Decimal from 'break_infinity.js' import type { BlueberryUpgrade } from '../BlueberryUpgrades' +import type { CorruptionLoadout, Corruptions, CorruptionSaves } from '../Corruptions' import type { WowCubes, WowHypercubes, WowPlatonicCubes, WowTesseracts } from '../CubeExperimental' import type { HepteractCraft } from '../Hepteracts' import type { Category, ResetHistoryEntryUnion } from '../History' import type { OcteractUpgrade } from '../Octeracts' +import type { PixelUpgrade } from '../PixelUpgrades' import type { IPlatBaseCost } from '../Platonic' import type { QuarkHandler } from '../Quark' import type { SingularityUpgrade } from '../singularity' @@ -12,7 +14,10 @@ import type { AmbrosiaGenerationCache, AmbrosiaLuckAdditiveMultCache, AmbrosiaLuckCache, - BlueberryInventoryCache + BlueberryInventoryCache, + UltimatePixelGenerationCache, + UltimatePixelLuckAdditiveMultCache, + UltimatePixelLuckCache } from '../StatCache' import type { Tabs } from '../Tabs' @@ -531,11 +536,12 @@ export interface Player { roombaResearchIndex: number ascStatToggles: Record - prototypeCorruptions: number[] - usedCorruptions: number[] - corruptionLoadouts: Record - corruptionLoadoutNames: string[] - corruptionShowStats: boolean + corruptions: { + next: CorruptionLoadout + used: CorruptionLoadout + saves: CorruptionSaves + showStats: boolean + } constantUpgrades: ArrayStartingWithNull history: Record @@ -615,6 +621,7 @@ export interface Player { singularityUpgrades: Record octeractUpgrades: Record + pixelUpgrades: Record dailyCodeUsed: boolean hepteractAutoCraftPercentage: number octeractTimer: number @@ -640,18 +647,24 @@ export interface Player { ultimateProgress: number ultimatePixels: number + lifetimeUltimatePixels: number caches: { ambrosiaLuckAdditiveMult: AmbrosiaLuckAdditiveMultCache ambrosiaLuck: AmbrosiaLuckCache ambrosiaGeneration: AmbrosiaGenerationCache blueberryInventory: BlueberryInventoryCache + ultimatePixelGeneration: UltimatePixelGenerationCache + ultimatePixelLuck: UltimatePixelLuckCache + ultimatePixelAdditiveMult: UltimatePixelLuckAdditiveMultCache } /** * When the player last exported the save. */ lastExportedSave: number + + seed: number[] } export interface GlobalVariables { @@ -850,6 +863,7 @@ export interface GlobalVariables { runescreen: string settingscreen: string + achievementScreen: number talismanResourceObtainiumCosts: number[] talismanResourceOfferingCosts: number[] @@ -913,13 +927,13 @@ export interface GlobalVariables { researchOrderByCost: number[] viscosityPower: number[] - lazinessMultiplier: number[] - hyperchallengedMultiplier: number[] + dilationMultiplier: number[] + hyperchallengeMultiplier: number[] illiteracyPower: number[] deflationMultiplier: number[] extinctionMultiplier: number[] droughtMultiplier: number[] - financialcollapsePower: number[] + recessionPower: number[] corruptionPointMultipliers: number[] @@ -942,7 +956,7 @@ export interface GlobalVariables { autoTalismanTimer: number autoChallengeTimerIncrement: number - corruptionTrigger: number + corruptionTrigger: keyof Corruptions challenge15Rewards: { cube1: number @@ -995,6 +1009,7 @@ export interface GlobalVariables { eventClicked: boolean ambrosiaTimer: number + pixelTimer: number TIME_PER_AMBROSIA: number ambrosiaCurrStats: { @@ -1004,6 +1019,12 @@ export interface GlobalVariables { ambrosiaGenerationSpeed: number } + pixelCurrStats: { + pixelAdditiveLuckMult: number + pixelLuck: number + pixelGenerationSpeed: number + } + currentSingChallenge: keyof Player['singularityChallenges'] | undefined } diff --git a/translations/da.json b/translations/da.json index aa36b6151..30611b1c4 100644 --- a/translations/da.json +++ b/translations/da.json @@ -1290,10 +1290,10 @@ "shopImprovedDaily2": "Gain 1 additional free Singularity Upgrade and 20% more Golden Quarks per use of 'daily' per level!", "shopImprovedDaily3": "Gain 1 additional free Singularity Upgrade and 15% more Golden Quarks per use of 'daily' per level!", "shopImprovedDaily4": "Gain 1 additional free Singularity Upgrade and 100% more Golden Quarks per use of 'daily' per level!", - "offeringEX3": "Gain 2% more Offerings per level, multiplicative! (Multiplier is 1.02^level)", - "obtainiumEX3": "Gain 2% more Obtainium per level, multiplicative! (Multiplier is 1.02^level)", - "chronometerInfinity": "Gain +1% Ascension Speed per level, multiplicative! (Multiplier is 1.01^level)", - "seasonPassInfinity": "Gain +2% more cubes per level, multiplicative! (Multiplier is 1.02^level)", + "offeringEX3": "Gain 2% more Offerings per level, based on square level (value is (1 + 0.02 * level)^2...", + "obtainiumEX3": "Gain 2% more Obtainium per level, squared! (value is (1 + 0.02 * level)^2...", + "chronometerInfinity": "Gain +1% Ascension Speed per level, squared! (value is (1 + 0.01 * level)^2...)", + "seasonPassInfinity": "Gain +2% more cubes per level, squared! (value is (1 + 0.01 * level)^2...", "shopSingularityPenaltyDebuff": "Derpsmith was so proud of your performance in the first EXALT that he wants to make your singularity debuffs weaker. At a cost. A big cost.", "obtainiumEX2": "Gain +1% Obtainium per level per Singularity!!!", "improveQuarkHept5": "This is 1/50 as effective as a normal improver. Why? Because of balancing..." @@ -2283,44 +2283,44 @@ }, "corruptions": { "names": { - "1": "Corruption I: Viscosity", - "2": "Corruption II: Spacial Dilation", - "3": "Corruption III: Hyperchallenged", - "4": "Corruption IV: Scientific Illiteracy", - "5": "Corruption V: Market Deflation", - "6": "Corruption VI: Extinction", - "7": "Corruption VII: Drought", - "8": "Corruption VIII: Financial Recession" + "viscosity": "Corruption I: Viscosity", + "dilation": "Corruption II: Spacial Dilation", + "hyperchallenge": "Corruption III: Hyperchallenged", + "illiteracy": "Corruption IV: Scientific Illiteracy", + "deflation": "Corruption V: Market Deflation", + "extinction": "Corruption VI: Extinction", + "drought": "Corruption VII: Drought", + "recession": "Corruption VIII: Financial Recession" }, "descriptions": { - "1": "You feel lethargic across the universe...", - "2": "Way to go, Albert.", - "3": "What's in a challenge?", - "4": "Maybe Albert wouldn't have theorized Dilation after all.", - "5": "Diamond Mine destroyed... no more monopolies!", - "6": "It killed the dinosaurs too, ya Dingus.", - "7": "More like California, am I right?", - "8": "Yet another 2020 catastrophe." + "viscosity": "You feel lethargic across the universe...", + "dilation": "Way to go, Albert.", + "hyperchallenge": "What's in a challenge?", + "illiteracy": "Maybe Albert wouldn't have theorized Dilation after all.", + "deflation": "Diamond Mine destroyed... no more monopolies!", + "extinction": "It killed the dinosaurs too, ya Dingus.", + "drought": "More like California, am I right?", + "recession": "Yet another 2020 catastrophe." }, "currentLevel": { - "1": "On this Ascension, this corruption is level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", - "2": "On this Ascension, this corruption is level {{ level }}. Effect: Time Speed is divided by {{ effect }}", - "3": "On this Ascension, this corruption is level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", - "4": "On this Ascension, this corruption is level {{ level }}. Effect: Obtainium gain ^{{ effect }}", - "5": "On this Ascension, this corruption is level {{ level }}. Effect: Diamond gain ^{{ effect }}", - "6": "On this Ascension, this corruption is level {{ level }}. Effect: Ant Production ^{{ effect }}", - "7": "On this Ascension, this corruption is level {{ level }}. Effect: Offering EXP divided by {{ effect }}", - "8": "On this Ascension, this corruption is level {{ level }}. Effect: Coin Gain ^{{ effect }}" + "viscosity": "On this Ascension, this corruption is level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", + "dilation": "On this Ascension, this corruption is level {{ level }}. Effect: Time Speed is divided by {{ effect }}", + "hyperchallenge": "On this Ascension, this corruption is level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", + "illiteracy": "On this Ascension, this corruption is level {{ level }}. Effect: Obtainium gain ^{{ effect }}", + "deflation": "On this Ascension, this corruption is level {{ level }}. Effect: Diamond gain ^{{ effect }}", + "extinction": "On this Ascension, this corruption is level {{ level }}. Effect: Ant Production ^{{ effect }}", + "drought": "On this Ascension, this corruption is level {{ level }}. Effect: Offering EXP divided by {{ effect }}", + "recession": "On this Ascension, this corruption is level {{ level }}. Effect: Coin Gain ^{{ effect }}" }, "prototypeLevel": { - "1": "On next Ascension, this corruption will be level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", - "2": "On next Ascension, this corruption will be level {{ level }}. Effect: Time Speed is divided by {{ effect }}", - "3": "On next Ascension, this corruption will be level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", - "4": "On next Ascension, this corruption will be level {{ level }}. Effect: Obtainium gain ^{{ effect }}", - "5": "On next Ascension, this corruption will be level {{ level }}. Effect: Diamond gain ^{{ effect }}", - "6": "On next Ascension, this corruption will be level {{ level }}. Effect: Ant Production ^{{ effect }}", - "7": "On next Ascension, this corruption will be level {{ level }}. Effect: Offering EXP divided by {{ effect }}", - "8": "On next Ascension, this corruption will be level {{ level }}. Effect: Coin Gain ^{{ effect }}" + "viscosity": "On next Ascension, this corruption will be level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", + "dilation": "On next Ascension, this corruption will be level {{ level }}. Effect: Time Speed is divided by {{ effect }}", + "hyperchallenge": "On next Ascension, this corruption will be level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", + "illiteracy": "On next Ascension, this corruption will be level {{ level }}. Effect: Obtainium gain ^{{ effect }}", + "deflation": "On next Ascension, this corruption will be level {{ level }}. Effect: Diamond gain ^{{ effect }}", + "extinction": "On next Ascension, this corruption will be level {{ level }}. Effect: Ant Production ^{{ effect }}", + "drought": "On next Ascension, this corruption will be level {{ level }}. Effect: Offering EXP divided by {{ effect }}", + "recession": "On next Ascension, this corruption will be level {{ level }}. Effect: Coin Gain ^{{ effect }}" }, "scoreMultiplier": "Current Score Multiplier: {{ curr }} / Next Ascension Score Multiplier: {{ next }}", "spiritEffect": "This corruption gives Rune Spirit Effect +{{curr}}% / Next Ascension Rune Spirit Effect +{{next}}%", diff --git a/translations/en.json b/translations/en.json index f39b029f9..f3ff86aad 100644 --- a/translations/en.json +++ b/translations/en.json @@ -43,7 +43,7 @@ }, "ambrosiaLuck1": { "name": "Ambrosia Luck Module I", - "description": "Congrats on completing the tutorial module. You need to have it maxxed to buy levels of this. ☘ +2 Ambrosia Luck/lvl. Every 10 levels gives ☘ +12 more!", + "description": "Congrats on completing the tutorial module. You need to have it maxxed to buy levels of this. +2 ☘ Ambrosia Luck/lvl. Every 10 levels gives ☘ +12 more!", "effect": "This luck module increases ☘ Ambrosia Luck by {{amount}}" }, "ambrosiaCubeQuark1": { @@ -68,12 +68,12 @@ }, "ambrosiaCubeLuck1": { "name": "Ambrosia Cube-Luck Hybrid Module I", - "description": "A first generation hybrid module. Gain ☘ +0.02 Ambrosia Luck per level per digit in the values of all cube types.", + "description": "A first generation hybrid module. Gain +0.02 ☘ Ambrosia Luck per level per digit in the values of all cube types.", "effect": "This first generation hybrid module increases ☘ Ambrosia Luck by {{amount}}" }, "ambrosiaQuarkLuck1": { "name": "Ambrosia Quark-Luck Hybrid Module I", - "description": "A first generation hybrid module. Gain ☘ +0.02 Ambrosia Luck per level per digit in your Quark balance, squared.", + "description": "A first generation hybrid module. Gain +0.02 ☘ Ambrosia Luck per level per digit in your Quark balance, squared.", "effect": "This first generation hybrid module increases ☘ Ambrosia Luck by {{amount}}" }, "ambrosiaQuarks2": { @@ -88,7 +88,7 @@ }, "ambrosiaLuck2": { "name": "Ambrosia Luck Module II", - "description": "Self-Synergies! Gain ☘ +3 Ambrosia Luck/lvl, +0.3 for every 10 levels in Ambrosia Luck Module I. Every 10 levels gives ☘ +40 more!", + "description": "Self-Synergies! Gain +3 ☘ Ambrosia Luck/lvl, +0.3 for every 10 levels in Ambrosia Luck Module I. Every 10 levels gives +40 more ☘ Ambrosia Luck!", "effect": "This second generation Luck module increases ☘ Ambrosia Luck by {{amount}}" }, "ambrosiaPatreon": { @@ -110,6 +110,21 @@ "name": "Hyperfluxed Wow! Cube Industrial Production", "description": "Gain +1% cubes per level, per level of Platonic Upgrade 4x4 purchased (multiplicative!!!)", "effect": "This module increases Cubes gain by {{amount}}%!" + }, + "ambrosiaPixelLuck": { + "name": "Blueberry-Infused Pixel Luck Enhancer", + "description": "Gain +2 ❖ Pixel Luck per level!", + "effect": "This module increases ❖ Pixel Luck by {{pixelLuck}}!" + }, + "ambrosiaPixelLuck2": { + "name": "Blueberry-Refined Pixel Luck Enhancer", + "description": "Gain +3 ❖ Pixel Luck per level!", + "effect": "This module increases ❖ Pixel Luck by {{pixelLuck}}!" + }, + "ambrosiaLuckDilator": { + "name": "Ambrosia Luck Dilator", + "description": "Doubles the Blueberry Second requirement to generate Ambrosia, but adds +60% to your ☘ Ambrosia Luck multiplier! (+10% per level after level 1)", + "effect": "Your ☘ Ambrosia Luck Additive Multiplier has been increased by {{ambrosiaLuckMult}}%!" } }, "loadouts": { @@ -129,6 +144,138 @@ "exportButton": "Export" } }, + "ultimatePixels": { + "ultimatePixels": "Ultimate Pixels", + "amount": "You have <> Ultimate Pixels!", + "perGen": "Currently gaining <> Pixels with a <> chance of another. [<>] {{extra}}", + "spendPrompt": "How many Ultimate Pixels would you like to spend? You have {{pixels}} Ultimate Pixels. Type -1 to use max!", + "cost": "Cost: {{pixels}} <>!", + "bar": { + "level": "Progress Bar Level {{level}} Rewards" + }, + "data": { + "pixelTutorial": { + "name": "The 'Ultimate Progress Bar' Handbook", + "description": "The Ruby Guy (possibly not his real identity) hands you a book on how the Singularities were once united by an Ultimate Progress Bar. All that is left are pixels from the Bar. \n Every time you generate <>, you also fill up the Progress Bar! It is 1:1 until 1,000 BBS/s, but then is ^1/3 afterwards.", + "effect": "This handbook increases cube gain by <> and quarks by <>" + }, + "pixelPixelLuck": { + "name": "Pixel Luck Enhancer I", + "description": "It's questionable why different lucks exist, but they do! Gain <> per level!", + "effect": "This enhancer increases your <> by <>(!)" + }, + "pixelAmbrosiaGeneration": { + "name": "A Pixelated Ambrosia Quickener", + "description": "This hourglass is not really pixelated. +0.5% Blueberry Generation Speed per level!", + "effect": "This quickener increases your <> by <>" + }, + "pixelAmbrosiaGeneration2": { + "name": "A Pixelated Ambrosia Hastener", + "description": "This hourglass is not really pixelated. +0.4% Blueberry Generation Speed per level!", + "effect": "This hastener increases your <> by <>" + }, + "pixelAmbrosiaGeneration3": { + "name": "A Pixelated Ambrosia Rapidity", + "description": "This hourglass is not really pixelated. +0.3% Blueberry Generation Speed per level!", + "effect": "This rapid hourglass increases your <> by <>" + }, + "pixelAmbrosiaLuck": { + "name": "A pixelated Ambrosia Luck Inducer", + "description": "This Inducer is not really pixelated. <> per level!", + "effect": "This inducer adds <>!" + }, + "pixelAmbrosiaLuck2": { + "name": "A pixelated Ambrosia Luck Deducer", + "description": "This deducer is not really pixelated. <> per level!", + "effect": "This deducer adds <>!" + }, + "pixelAmbrosiaLuck3": { + "name": "A pixelated Ambrosia Luck Convector", + "description": "This convector is not really pixelated. <> per level!", + "effect": "This convector adds <>!" + }, + "pixelCubes": { + "name": "Cubes!!!!", + "description": "Gain +1.5% more cubes per level! Flavor text goes here", + "effect": "This lore-filled upgrade increases cube gain by {{cubeAmount}}%." + }, + "pixelQuarks": { + "name": "Pixel-Perfect Quarks", + "description": "By exploiting a frame-perfect respec, gain <> per level!", + "effect": "<>!" + }, + "pixelObtainium": { + "name": "Obtained Pixels", + "description": "Gain +1% Obtainium per level!", + "effect": "<>!" + }, + "pixelOfferings": { + "name": "Offered Pixels", + "description": "Gain +1% Offerings per level!", + "effect": "<>!" + }, + "pixelPixelGeneration": { + "name": "Progress Bar Enzyme", + "description": "Every <> gives you an <> Generation! Adds <> per level, before any multipliers!", + "effect": "Base <> is increased by <>!" + }, + "pixelPixelGeneration2": { + "name": "Progress Bar Catalyst", + "description": "Adds <> per level, before any multipliers!", + "effect": "Base <> is increased by <>!" + }, + "pixelPixelGeneration3": { + "name": "Progress Bar Precursor", + "description": "Adds <> per level, before any multipliers!", + "effect": "Base <> is increased by <>!" + }, + "pixelBlueberry": { + "name": "You'll want to purchase this", + "description": "Everyone wants it, you want it, Gold Guy wants it! An additional <>!", + "effect": "<> purchased: {{blueberry}}" + }, + "pixelBlueberry2": { + "name": "A blueberry!", + "description": "Everyone wants it, you want it, Gold Guy wants it! An additional <>!", + "effect": "<> purchased: {{blueberry}}" + }, + "pixelBlueberry3": { + "name": "A blue... berry??", + "description": "An additional <>, at a not too reasonable price!", + "effect": "<> purchased: {{blueberry}}" + }, + "pixelRoleBonus": { + "name": "A title of nobility", + "description": "With this upgrade, you can proclaim yourself to Platonic himself (on the Discord server) to become a Viscount of Ruby Guy, which is a cool role! You also get +1% Global Luck!", + "effect": "<> purchased: {{purchased}}" + }, + "pixelPixelLuckConverter": { + "name": "Ambrosia2Pixel Luck I", + "description": "A converter which (very inefficiently) converts ☘ Ambrosia Luck to ❖ Pixel Luck! For every 400 ☘ Ambrosia Luck you have, gain 1 ❖ Pixel Luck (rounded down!)", + "effect": "Purchased: {{purchased}} | <>" + }, + "pixelPixelLuckConverter2": { + "name": "Ambrosia2Pixel Luck II", + "description": "A converter which (very inefficiently) converts ☘ Ambrosia Luck to Pixel Luck! For every 400 ☘ Ambrosia Luck you have, gain 1 Pixel Luck (rounded down with the other upgrade!)", + "effect": "Purchased: {{purchased}} | <>" + }, + "pixelFreeUpgradeImprovement": { + "name": "Transfigured Free Upgrades I", + "description": "When you get a free upgrade from code 'daily', there is a +0.1% chance per level that you instead get a free upgrade from a pool of exclusive Octeract Upgrades! Ranges from okay to absolutely game-changing Octeract Upgrades.", + "effect": "Gain a +{{proportion}}% chance to convert a Singularity free upgrade into an Octeract free upgrade." + }, + "pixelFreeUpgradeImprovement2": { + "name": "Transfigured Free Upgrades II", + "description": "When you get a free upgrade from code 'daily', there is a +0.1% chance per level that you instead get a free upgrade from a pool of exclusive Octeract Upgrades! Ranges from okay to absolutely game-changing Octeract Upgrades.", + "effect": "Gain a +{{proportion}}% chance to convert a Singularity free upgrade into an Octeract free upgrade." + }, + "pixelFreeUpgradeImprovement3": { + "name": "Transfigured Free Upgrades III", + "description": "When you get a free upgrade from code 'daily', there is a +0.1% chance per level that you instead get a free upgrade from a pool of exclusive Octeract Upgrades! Ranges from okay to absolutely game-changing Octeract Upgrades.", + "effect": "Gain a +{{proportion}}% chance to convert a Singularity free upgrade into an Octeract free upgrade." + } + } + }, "achievements": { "descriptions": { "1": "[{{number}}] A Loyal Employee: Hire your first Worker.", @@ -410,7 +557,21 @@ "277": "[{{number}}] SingularRity: Singularity 4 times.", "278": "[{{number}}] SiINguLaRrRity: Singularity 5 times.", "279": "[{{number}}] SiIINGuLArRrIiTyY: Singularity 7 times.", - "280": "[{{number}}] Inception: Singularity 10 times." + "280": "[{{number}}] Inception: Singularity 10 times.", + "281": "[{{number}}] WIP Luck be a Lady: Obtain 300 ☘ Ambrosia Luck at once!", + "282": "[{{number}}] WIP A couple modules later: Obtain 750 ☘ Ambrosia Luck at once!", + "283": "[{{number}}] WIP A baker's 15/13 dozen: Obtain 1,500 ☘ Ambrosia Luck at once!", + "284": "[{{number}}] WIP <3(,001): Obtain 3,000 ☘ Ambrosia Luck at once!", + "285": "[{{number}}] WIP If you gaze long into an abyss: Obtain 5,000 ☘ Ambrosia Luck at once!", + "286": "[{{number}}] WIP The abyss will also gaze into thee: Obtain 10,000 ☘ Ambrosia Luck at once!", + "287": "[{{number}}] WIP 20,000 Lucks Under The Sea: Obtain 20,000 ☘ Ambrosia Luck at once!", + "288": "[{{number}}] WIP Tutorial Module Unlocked!: Obtain 50 lifetime Ambrosia.", + "289": "[{{number}}] WIP A thousanddaire: Obtain 1,000 lifetime Ambrosia", + "290": "[{{number}}] WIP Enchanted Ambrosia Block: Obtain 25,600 lifetime Ambrosia", + "291": "[{{number}}] WIP Gold Guy's Go-to: Obtain 256,000 lifetime Ambrosia", + "292": "[{{number}}] WIP Maxxed Luck Module: Obtain 1,000,000 lifetime Ambrosia", + "293": "[{{number}}] WIP Just a regular number: Obtain 3,141,592 lifetime Ambrosia", + "294": "[{{number}}] WIP The Egg of ULTRA Acceleration: Obtain 9,999,999 lifetime Ambrosia" }, "rewards": { "3": "Gain +.05% to Accelerator Power.", @@ -570,7 +731,15 @@ "266": "Quarks +{{x}}% [Max: 10% at 1Qa Ascensions]!", "267": "Ascension Score is boosted by {{x}}% [Max: 100% at 1e100,000 Const]", "270": "Hepteract Gain is boosted by {{x}}% [Max: 100% at 1e1,000,000 const], Constant Upgrade 1 boosted to 1.06 (from 1.05), Constant Upgrade 2 boosted to 1.11 (from 1.10).", - "271": "When you open a Platonic Cube, gain {{x}} Hypercubes, rounded down [Max: 1 at 1e1,000,000 Const]" + "271": "When you open a Platonic Cube, gain {{x}} Hypercubes, rounded down [Max: 1 at 1e1,000,000 Const]", + "284": "+1% Global Luck!", + "285": "Every time the Blueberry bar fills up, you get 2 additional Ambrosia for free!", + "286": "If you have under 5,000 Ambrosia Luck, you are guaranteed at least 50 Ambrosia for each time the Blueberry bar fills up", + "287": "Every 1,000,000 Blueberry seconds, gain +0.1s real-life Ascension timer! (Caps at 0.1s per tick)", + "289": "Gain +1% more Blueberry Generation Speed for every unique module activated!", + "291": "Gain 1.01x Blueberry Generation Speed for every blueberry that you have!", + "293": "Your Constant adds +1% Blueberry Generation Speed for every digit in its base-10 exponent.", + "294": "Unlocks a special shop upgrade!" }, "alerts": { "36": "Congratulations on your first Prestige. The first of many. You obtain Offerings. You can use them in the new Runes tab! [Unlocked Runes, Achievements, Diamond Buildings and some Upgrades!]", @@ -1411,10 +1580,10 @@ "shopImprovedDaily2": "Gain 1 additional free Singularity Upgrade and 20% more Golden Quarks per use of 'daily' per level!", "shopImprovedDaily3": "Gain 1 additional free Singularity Upgrade and 15% more Golden Quarks per use of 'daily' per level!", "shopImprovedDaily4": "Gain 1 additional free Singularity Upgrade and 100% more Golden Quarks per use of 'daily' per level!", - "offeringEX3": "Gain 2% more Offerings per level, multiplicative! (Multiplier is 1.02^level)", - "obtainiumEX3": "Gain 2% more Obtainium per level, multiplicative! (Multiplier is 1.02^level)", - "chronometerInfinity": "Gain +1% Ascension Speed per level, multiplicative! (Multiplier is 1.01^level)", - "seasonPassInfinity": "Gain +2% more cubes per level, multiplicative! (Multiplier is 1.02^level)", + "offeringEX3": "Gain 2% more Offerings per level, exponentially!", + "obtainiumEX3": "Gain 2% more Obtainium per level, exponentially!", + "chronometerInfinity": "Gain +1% Ascension Speed per level, exponentially!", + "seasonPassInfinity": "Gain +2% more Cubes per level, exponentially!", "shopSingularityPenaltyDebuff": "Derpsmith was so proud of your performance in the first EXALT that he wants to make your singularity debuffs weaker. At a cost. A big cost.", "obtainiumEX2": "Gain +1% Obtainium per level per Singularity!!!", "improveQuarkHept5": "This is 1/50 as effective as a normal improver. Why? Because of balancing...", @@ -1426,10 +1595,10 @@ "shopAmbrosiaLuck2": "You get a slightly larger four leaf clover, giving +2 ☘ Ambrosia luck per level, stacking additively.", "shopAmbrosiaLuck3": "You get a slightly greener four leaf clover, giving +2 ☘ Ambrosia luck per level, stacking additively.", "shopAmbrosiaLuck4": "You get a slightly 'better' four leaf clover, what ever that means, giving +0.6 ☘ Ambrosia luck per level, stacking additively.", - "shopAmbrosiaLuckMultiplier4": "Gain ☘ +1% Ambrosia Luck per level! Simple as that.", - "shopOcteractAmbrosiaLuck": "Gain ☘ +1 Ambrosia Luck per digit in your Wow! Octeract inventory per level. Simple as that.", + "shopAmbrosiaLuckMultiplier4": "Gain +1% ☘ Ambrosia Luck per level! Simple as that.", + "shopOcteractAmbrosiaLuck": "Gain +1 ☘ Ambrosia Luck per digit in your Wow! Octeract inventory per level. Simple as that.", "shopCashGrabUltra": "For a nominal price, gain up to +20% Blueberry Speed, +80% Cubes and +12% Quarks per level based on Ambrosia, scaling nonlinearly until 10,000,000 lifetime earned.", - "shopAmbrosiaAccelerator": "Each level of this 'accelerator' provides <> real-life seconds of Blueberry Generation for every <> Ambrosia gained, from any source!", + "shopAmbrosiaAccelerator": "Each level of this 'accelerator' provides <> real-life seconds of Blueberry Generation for every <> Ambrosia gained, from any source! Can only fill up the <> at most 90%.", "shopEXUltra": "With this EX Upgrade, every 1,000 owned Ambrosia adds +0.1% <>, <> and <>! This effect caps at 125,000 * (level of shop upgrade)!" }, "maxed": "Maxed!", @@ -1513,16 +1682,16 @@ "chronometerInfinity": "Ascension timer increases <> faster.", "seasonPassInfinity": "Ascensions give <> more cubes (of <> types) on Ascension.", "shopSingularityPenaltyDebuff": "At Singularity <>, your debuffs are as if you were in <>.", - "shopAmbrosiaLuckMultiplier4": "Gain <> Ambrosia Luck!", - "shopOcteractAmbrosiaLuck": "Octeracts grant <> Ambrosia Luck!", + "shopAmbrosiaLuckMultiplier4": "Gain <>!", + "shopOcteractAmbrosiaLuck": "Octeracts grant <>", "shopAmbrosiaGeneration1": "Blueberry Time is generated <> faster.", "shopAmbrosiaGeneration2": "Blueberry Time is generated <> faster.", "shopAmbrosiaGeneration3": "Blueberry Time is generated <> faster.", "shopAmbrosiaGeneration4": "Blueberry Time is generated <> faster.", - "shopAmbrosiaLuck1": "Ambrosia Luck <>", - "shopAmbrosiaLuck2": "Ambrosia Luck <>", - "shopAmbrosiaLuck3": "Ambrosia Luck <>", - "shopAmbrosiaLuck4": "Ambrosia Luck <>", + "shopAmbrosiaLuck1": "<>", + "shopAmbrosiaLuck2": "<>", + "shopAmbrosiaLuck3": "<>", + "shopAmbrosiaLuck4": "<>", "shopCashGrabUltra": "Blueberry Generation is <> faster. Also, Cubes <>! Finally, Quarks <>!", "shopAmbrosiaAccelerator": "For every <> gained, add <> seconds of Blueberry Generation (<> Blueberry Seconds)!", "shopEXUltra": "Ambrosia increases <>, <> and <> by <>!" @@ -1623,8 +1792,8 @@ "hasLevel1": "Keep all Cube Opening researches AND gain the ability to automatically open a percentage of your cubes each Ascension!", "default": "Researches related to opening cubes will no longer reset on Ascension" }, - "irishAnt": "Ants blessed with the luck of the Irish grant ☘ {{i}} Ambrosia Luck!", - "irishAnt2": "Ants blessed with more fortunate luck of the Irish grant ☘ {{i}} more Ambrosia Luck!", + "irishAnt": "Ants blessed with the luck of the Irish grant {{i}} ☘ Ambrosia Luck!", + "irishAnt2": "Ants blessed with more fortunate luck of the Irish grant {{i}} ☘ more Ambrosia Luck!", "overclocked": "Level Caps on Certain Singularity Upgrades are increased by {{i}}!", "wowCubeAutomatedShipping": { "hasLevel1": "Automatically buy Cube Upgrades with each ascension, no matter where you are!", @@ -1655,8 +1824,8 @@ }, "skrauQ": "Multiply all Quark Gain by ((Singularity - 179)/20)^2. Currently: {{amt}}... Yes, it's that good.", "derpSmithsCornucopia": "With blessing from the Derpsmith, every singularity grants +{{counter}}% more Octeracts!", - "oneHundredThirtyOne": "Gain <> Ambrosia Luck!", - "twoHundredSixtyNine": "Gain <> Ambrosia Luck!" + "oneHundredThirtyOne": "Gain <> Ambrosia Luck!", + "twoHundredSixtyNine": "Gain <> Ambrosia Luck!" }, "toString": { "noMinimum": "No minimal Singularity to purchase required", @@ -2000,22 +2169,22 @@ }, "singAmbrosiaLuck2": { "name": "Gilded Berries of Good Fortune", - "description": "Literally put some gold onto 'berries' and become lucky. ☘ +2 Ambrosia Luck per level!", + "description": "Literally put some gold onto 'berries' and become lucky. +2 ☘ Ambrosia Luck per level!", "effect": "☘ Ambrosia Luck +{{n}}(!)" }, "singAmbrosiaLuck3": { "name": "Dedicated Gold Smelting", - "description": "More gold is dipped onto each berry. ☘ +3 Ambrosia Luck per level!", + "description": "More gold is dipped onto each berry. +3 ☘ Ambrosia Luck per level!", "effect": "☘ Ambrosia Luck +{{n}}(!)" }, "singAmbrosiaLuck": { "name": "Absolute Hot", - "description": "Your gold smelters get arbitrarily close to 'Absolute Hot'. ☘ +4 Ambrosia Luck per level, infinitely levelable!", + "description": "Your gold smelters get arbitrarily close to 'Absolute Hot'. +4 ☘ Ambrosia Luck per level, infinitely levelable!", "effect": "☘ Ambrosia Luck +{{n}}(!)" }, "singAmbrosiaLuck4": { "name": "The Alchemists from the Beginning of the Game Work for your Golden Berry Needs", - "description": "Yeah, these upgrade titles can be arbitrarily long, too. ☘ +5 Ambrosia Luck per level!", + "description": "Yeah, these upgrade titles can be arbitrarily long, too. +5 ☘ Ambrosia Luck per level!", "effect": "☘ Ambrosia Luck +{{n}}(!)" }, "singAmbrosiaGeneration2": { @@ -2037,6 +2206,16 @@ "name": "Hourglass of Fantasy", "description": "An hourglass which is unimportant and 'less timely'- whatever that means. +2% Blueberry Second Generation per level.", "effect": "Blueberry Seconds Generation +{{n}}%(!)" + }, + "singPixelLuck": { + "name": "Lucky Little Pixels", + "description": "Like Ambrosia, you can be luckier when harvesting pixels from the Ultimate Progress Bar! +2 ❖ Pixel Luck per level!", + "effect": "❖ Pixel luck +{{n}}(!)" + }, + "singPixelLuck2": { + "name": "Lucky Big Pixels", + "description": "The amount you will spend for very minor stat bonuses is commendable! +3 ❖ Pixel Luck per level!", + "effect": "❖ Pixel luck +{{n}}(!)" } }, "goldenQuarkAmount": "You have {{goldenQuarks}} Golden Quarks!", @@ -2426,7 +2605,8 @@ "singularity": "Singularity", "settings": "Settings", "shop": "Shop", - "unsmith": "UNSMITH" + "unsmith": "UNSMITH", + "testing": "Testing β" }, "buildings": { "coin": "Coin Buildings", @@ -2457,7 +2637,9 @@ "singularity": { "perks-penalties": "Perks / Penalties", "octeracts": "Octeracts", - "ambrosia": "Ambrosia" + "exalt": "EXALT", + "ambrosia": "Ambrosia", + "progress": "BAR" }, "settings": { "languages": "🌐 Languages 🌐", @@ -2483,48 +2665,50 @@ "ingameAntSacTimer": "In-Game Ant Sacrifice Timer: +<> seconds", "realAntSacTimer": "Real-Life Ant Sacrifice Timer: +<> seconds", "currentAscensionTimer": "Current Ascension Timer: +<> seconds", - "exportQuarks": "Export Quarks: +<>" + "exportQuarks": "Export Quarks: +<>", + "lifetimeAmbrosia": "Ambrosia: +<>", + "pixels": "Ultimate Pixels: +<>" }, "corruptions": { "names": { - "1": "Corruption I: Viscosity", - "2": "Corruption II: Spacial Dilation", - "3": "Corruption III: Hyperchallenged", - "4": "Corruption IV: Scientific Illiteracy", - "5": "Corruption V: Market Deflation", - "6": "Corruption VI: Extinction", - "7": "Corruption VII: Drought", - "8": "Corruption VIII: Financial Recession" + "viscosity": "Corruption I: Viscosity", + "dilation": "Corruption II: Spacial Dilation", + "hyperchallenge": "Corruption III: Hyperchallenged", + "illiteracy": "Corruption IV: Scientific Illiteracy", + "deflation": "Corruption V: Market Deflation", + "extinction": "Corruption VI: Extinction", + "drought": "Corruption VII: Drought", + "recession": "Corruption VIII: Financial Recession" }, "descriptions": { - "1": "You feel lethargic across the universe...", - "2": "Way to go, Albert.", - "3": "What's in a challenge?", - "4": "Maybe Albert wouldn't have theorized Dilation after all.", - "5": "Diamond Mine destroyed... no more monopolies!", - "6": "It killed the dinosaurs too, ya Dingus.", - "7": "More like California, am I right?", - "8": "Yet another 2020 catastrophe." + "viscosity": "You feel lethargic across the universe...", + "dilation": "You feel as though seconds go by in years.", + "hyperchallenge": "You want me to get HOW Many coins??", + "illiteracy": "In the year 2505...", + "deflation": "This ascension lacks carbon...", + "extinction": "It killed the dinosaurs too, ya Dingus.", + "drought": "Where will I grow my offering trees now?", + "recession": "Yet another 2020 catastrophe." }, "currentLevel": { - "1": "On this Ascension, this corruption is level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", - "2": "On this Ascension, this corruption is level {{ level }}. Effect: Time Speed is divided by {{ effect }}", - "3": "On this Ascension, this corruption is level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", - "4": "On this Ascension, this corruption is level {{ level }}. Effect: Obtainium gain ^{{ effect }}", - "5": "On this Ascension, this corruption is level {{ level }}. Effect: Diamond gain ^{{ effect }}", - "6": "On this Ascension, this corruption is level {{ level }}. Effect: Ant Production ^{{ effect }}", - "7": "On this Ascension, this corruption is level {{ level }}. Effect: Offering EXP divided by {{ effect }}", - "8": "On this Ascension, this corruption is level {{ level }}. Effect: Coin Gain ^{{ effect }}" + "viscosity": "On this Ascension, this corruption is level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", + "dilation": "On this Ascension, this corruption is level {{ level }}. Effect: Time Speed is divided by {{ effect }}", + "hyperchallenge": "On this Ascension, this corruption is level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", + "illiteracy": "On this Ascension, this corruption is level {{ level }}. Effect: Obtainium gain ^{{ effect }}", + "deflation": "On this Ascension, this corruption is level {{ level }}. Effect: Diamond gain ^{{ effect }}", + "extinction": "On this Ascension, this corruption is level {{ level }}. Effect: Ant Production ^{{ effect }}", + "drought": "On this Ascension, this corruption is level {{ level }}. Effect: Offering EXP divided by {{ effect }}", + "recession": "On this Ascension, this corruption is level {{ level }}. Effect: Coin Gain ^{{ effect }}" }, "prototypeLevel": { - "1": "On next Ascension, this corruption will be level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", - "2": "On next Ascension, this corruption will be level {{ level }}. Effect: Time Speed is divided by {{ effect }}", - "3": "On next Ascension, this corruption will be level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", - "4": "On next Ascension, this corruption will be level {{ level }}. Effect: Obtainium gain ^{{ effect }}", - "5": "On next Ascension, this corruption will be level {{ level }}. Effect: Diamond gain ^{{ effect }}", - "6": "On next Ascension, this corruption will be level {{ level }}. Effect: Ant Production ^{{ effect }}", - "7": "On next Ascension, this corruption will be level {{ level }}. Effect: Offering EXP divided by {{ effect }}", - "8": "On next Ascension, this corruption will be level {{ level }}. Effect: Coin Gain ^{{ effect }}" + "viscosity": "On next Ascension, this corruption will be level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", + "dilation": "On next Ascension, this corruption will be level {{ level }}. Effect: Time Speed is divided by {{ effect }}", + "hyperchallenge": "On next Ascension, this corruption will be level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", + "illiteracy": "On next Ascension, this corruption will be level {{ level }}. Effect: Obtainium gain ^{{ effect }}", + "deflation": "On next Ascension, this corruption will be level {{ level }}. Effect: Diamond gain ^{{ effect }}", + "extinction": "On next Ascension, this corruption will be level {{ level }}. Effect: Ant Production ^{{ effect }}", + "drought": "On next Ascension, this corruption will be level {{ level }}. Effect: Offering EXP divided by {{ effect }}", + "recession": "On next Ascension, this corruption will be level {{ level }}. Effect: Coin Gain ^{{ effect }}" }, "scoreMultiplier": "Current Score Multiplier: {{ curr }} / Next Ascension Score Multiplier: {{ next }}", "spiritEffect": "This corruption gives Rune Spirit Effect +{{curr}}% / Next Ascension Rune Spirit Effect +{{next}}%", @@ -2859,22 +3043,22 @@ }, "octeractAmbrosiaLuck2": { "name": "Florentine Cranberries", - "description": "Totally not a reskin of the blueberry! Adds ☘ +2 Ambrosia Luck, which can increase Ambrosia drop amounts when Blueberries generate Ambrosia.", + "description": "Totally not a reskin of the blueberry! Adds +2 ☘ Ambrosia Luck, which can increase Ambrosia drop amounts when Blueberries generate Ambrosia.", "effect": "☘ Ambrosia Luck +{{n}}(!)" }, "octeractAmbrosiaLuck3": { "name": "Berries of a Four Leaf Clover", - "description": "Totally not a reskin of the blueberry! Adds ☘ +3 Ambrosia Luck per level.", + "description": "Totally not a reskin of the blueberry! Adds +3 ☘ Ambrosia Luck per level.", "effect": "☘ Ambrosia Luck +{{n}}(!)" }, "octeractAmbrosiaLuck": { "name": "Berries of an Eight Leaf Clover", - "description": "Totally not a reskin of the blueberry! Adds ☘ +4 Ambrosial Luck per level, and it is infinitely levelable!", + "description": "Totally not a reskin of the blueberry! Adds +4 ☘ Ambrosial Luck per level, and it is infinitely levelable!", "effect": "☘ Ambrosia Luck +{{n}}(!)" }, "octeractAmbrosiaLuck4": { "name": "Berries of a Ten Leaf Clover", - "description": "Totally not a reskin of the blueberry! Adds ☘ +5 Ambrosial Luck. And it's mega expensive somehow.", + "description": "Totally not a reskin of the blueberry! Adds +5 ☘ Ambrosial Luck. And it's mega expensive somehow.", "effect": "☘ Ambrosia Luck +{{n}}(!)" }, "octeractAmbrosiaGeneration2": { @@ -2896,6 +3080,16 @@ "name": "Hourglass of Reality", "description": "An hourglass which is nonprimative and 'more timely'- whatever that means. +2% Blueberry Second Generation per level.", "effect": "Blueberry Seconds Generation +{{n}}%(!)" + }, + "octeractPixelLuck": { + "name": "Mega Pixel Luck Bonus", + "description": "Pay a lot of Octeracts, get a few ❖ Pixel Luck. +2 per level, to be precise.", + "effect": "Gain +{{n}} ❖ Pixel Luck!" + }, + "octeractPixelLuck2": { + "name": "Tera Pixel Luck Bonus", + "description": "Pay a LOT of Octeracts, get a few ❖ Pixel Luck. +3 per level, to be precise.", + "effect": "Gain +{{n}} ❖ Pixel Luck!" } }, "amount": "You have {{octeracts}} Octeracts!", @@ -3113,15 +3307,8 @@ }, "noAmbrosiaUpgrades": { "name": "No Ambrosia Upgrades", - "description": "Gold Guy has lost his muster (and yes, that's his name!) and needs your help.
Clear the Singularity without any effects from Ambrosia or Ambrosia-Tier Upgrades!", - "ScalingReward1": "+15 & +0.5% <>", - "ScalingReward2": "+2% <> Speed", - "UniqueReward1": "1st - A free <>!", - "UniqueReward2": "1st - +1 <> every time <> is gained!", - "UniqueReward3": "10th - Another free <>!!!", - "UniqueReward4": "15th - A new <> upgrade!", - "UniqueReward5": "20th - A THIRD FREE <>?!?!", - "UniqueReward6": "20th - An <> upgrade!" + "description": "Gold Guy has lost his muster (and yes, that's his name!) and needs your help. Clear the Singularity without any effects from Ambrosia or Ambrosia-Tier Upgrades!", + "rewardDescription": "Each completion grants <>, <>! First completion awards a blueberry and +1 Ambrosia every time Ambrosia is gained! 10th completion awards a blueberry. 15th completion awards a <>! The final completion awards, you guessed it, a blueberry AND an <>!" } }, "intro": "Do you have what it takes to earn EXALT from Ant God?", @@ -3501,7 +3688,8 @@ "insideSingularityChallenge": "Derpsmith thinks you are in a Singularity Challenge. You may exit it by clicking on the challenge icon in the Exalt tab.", "gameBeat": "Well. It seems you've reached the eye of the Singularity. I'm pleased. This also means there is nowhere to go from here. At least, not until higher powers expand your journey.", "exitAscensionChallenge": "Are you absolutely sure that you want to exit the Ascension Challenge? You will need to clear challenge 10 again before you can attempt the challenge again!", - "buyResearch3x11": "[LOCKED - Buy Research 3x11]" + "buyResearch3x11": "[LOCKED - Buy Research 3x11]", + "levelText": "Level {{level}}/{{maxLevel}}" }, "history": { "perSecondOn": "Per second: ON", @@ -3517,4 +3705,4 @@ "account": { "logout": "The page will now reload. You are logged out! Goodbye!!" } -} +} diff --git a/translations/source.json b/translations/source.json index bd87a0733..c4cf85b9a 100644 --- a/translations/source.json +++ b/translations/source.json @@ -110,6 +110,21 @@ "name": "Hyperfluxed Wow! Cube Industrial Production", "description": "Gain +1% cubes per level, per level of Platonic Upgrade 4x4 purchased (multiplicative!!!)", "effect": "This module increases Cubes gain by {{amount}}%!" + }, + "ambrosiaPixelLuck": { + "name": "Blueberry-Infused Pixel Luck Enhancer", + "description": "Gain +1 ❖ Pixel Luck per level!", + "effect": "This module increases ❖ Pixel Luck by {{pixelLuck}}!" + }, + "ambrosiaPixelLuck2": { + "name": "Blueberry-Refined Pixel Luck Enhancer", + "description": "Gain +1 ❖ Pixel Luck per level!", + "effect": "This module increases ❖ Pixel Luck by {{pixelLuck}}!" + }, + "ambrosiaLuckDilator": { + "name": "Ambrosia Luck Dilator", + "description": "Doubles the Blueberry Second requirement to generate Ambrosia, but adds +100% to your ☘ Ambrosia Luck multiplier! (+4%/lv after level 1!)", + "effect": "Your ☘ Ambrosia Luck Additive Multiplier has been increased by {{ambrosiaLuckMult}}%!" } }, "loadouts": { @@ -129,6 +144,138 @@ "exportButton": "Export" } }, + "ultimatePixels": { + "ultimatePixels": "Ultimate Pixels", + "amount": "You have <> Ultimate Pixels!", + "perGen": "Currently gaining <> Pixels with a <> chance of another. [<>] {{extra}}", + "spendPrompt": "How many Ultimate Pixels would you like to spend? You have {{pixels}} Ultimate Pixels. Type -1 to use max!", + "cost": "Cost: {{pixels}} <>!", + "bar": { + "level": "Progress Bar Level {{level}} Rewards" + }, + "data": { + "pixelTutorial": { + "name": "The 'Ultimate Progress Bar' Handbook", + "description": "The Ruby Guy (possibly not his real identity) hands you a book on how the Singularities were once united by an Ultimate Progress Bar. All that is left are pixels from the Bar. \n Every time you generate <>, you also fill up the Progress Bar! It is 1:1 until 1,000 BBS/s, but then is ^1/3 afterwards.", + "effect": "This handbook increases cube gain by <> and quarks by <>" + }, + "pixelPixelLuck": { + "name": "Pixel Luck Enhancer I", + "description": "It's questionable why different lucks exist, but they do! Gain <> per level!", + "effect": "This enhancer increases your <> by <>(!)" + }, + "pixelAmbrosiaGeneration": { + "name": "A Pixelated Ambrosia Quickener", + "description": "This hourglass is not really pixelated. +0.5% Blueberry Generation Speed per level!", + "effect": "This quickener increases your <> by <>" + }, + "pixelAmbrosiaGeneration2": { + "name": "A Pixelated Ambrosia Hastener", + "description": "This hourglass is not really pixelated. +0.4% Blueberry Generation Speed per level!", + "effect": "This hastener increases your <> by <>" + }, + "pixelAmbrosiaGeneration3": { + "name": "A Pixelated Ambrosia Rapidity", + "description": "This hourglass is not really pixelated. +0.3% Blueberry Generation Speed per level!", + "effect": "This rapid hourglass increases your <> by <>" + }, + "pixelAmbrosiaLuck": { + "name": "A pixelated Ambrosia Luck Inducer", + "description": "This Inducer is not really pixelated. <> per level!", + "effect": "This inducer adds <>!" + }, + "pixelAmbrosiaLuck2": { + "name": "A pixelated Ambrosia Luck Deducer", + "description": "This deducer is not really pixelated. <> per level!", + "effect": "This deducer adds <>!" + }, + "pixelAmbrosiaLuck3": { + "name": "A pixelated Ambrosia Luck Convector", + "description": "This convector is not really pixelated. <> per level!", + "effect": "This convector adds <>!" + }, + "pixelCubes": { + "name": "Cubes!!!!", + "description": "Gain +1.5% more cubes per level! Flavor text goes here", + "effect": "This lore-filled upgrade increases cube gain by {{cubeAmount}}%." + }, + "pixelQuarks": { + "name": "Pixel-Perfect Quarks", + "description": "By exploiting a frame-perfect respec, gain <> per level!", + "effect": "<>!" + }, + "pixelObtainium": { + "name": "Obtained Pixels", + "description": "Gain +1% Obtainium per level!", + "effect": "<>!" + }, + "pixelOfferings": { + "name": "Offered Pixels", + "description": "Gain +1% Offerings per level!", + "effect": "<>!" + }, + "pixelPixelGeneration": { + "name": "Progress Bar Enzyme", + "description": "Every <> gives you an <> Generation! Adds <> per level, before any multipliers!", + "effect": "Base <> is increased by <>!" + }, + "pixelPixelGeneration2": { + "name": "Progress Bar Catalyst", + "description": "Adds <> per level, before any multipliers!", + "effect": "Base <> is increased by <>!" + }, + "pixelPixelGeneration3": { + "name": "Progress Bar Precursor", + "description": "Adds <> per level, before any multipliers!", + "effect": "Base <> is increased by <>!" + }, + "pixelBlueberry": { + "name": "You'll want to purchase this", + "description": "Everyone wants it, you want it, Gold Guy wants it! An additional <>!", + "effect": "<> purchased: {{blueberry}}" + }, + "pixelBlueberry2": { + "name": "A blueberry!", + "description": "Everyone wants it, you want it, Gold Guy wants it! An additional <>!", + "effect": "<> purchased: {{blueberry}}" + }, + "pixelBlueberry3": { + "name": "A blue... berry??", + "description": "An additional <>, at a not too reasonable price!", + "effect": "<> purchased: {{blueberry}}" + }, + "pixelRoleBonus": { + "name": "A title of nobility", + "description": "With this upgrade, you can proclaim yourself to Platonic himself (on the Discord server) to become a Viscount of Ruby Guy, which is a cool role! You also get +1% Global Luck!", + "effect": "<> purchased: {{purchased}}" + }, + "pixelPixelLuckConverter": { + "name": "Ambrosia2Pixel Luck I", + "description": "A converter which (very inefficiently) converts ☘ Ambrosia Luck to ❖ Pixel Luck! For every 1,000 ☘ Ambrosia Luck you have, gain 1 ❖ Pixel Luck (rounded down!)", + "effect": "Purchased: {{purchased}} | <>" + }, + "pixelPixelLuckConverter2": { + "name": "Ambrosia2Pixel Luck II", + "description": "A converter which (very inefficiently) converts ☘ Ambrosia Luck to Pixel Luck! For every 1,000 ☘ Ambrosia Luck you have, gain 1 Pixel Luck (rounded down!)", + "effect": "Purchased: {{purchased}} | <>" + }, + "pixelFreeUpgradeImprovement": { + "name": "Transfigured Free Upgrades I", + "description": "When you get a free upgrade from code 'daily', there is a +0.1% chance per level that you instead get a free upgrade from a pool of exclusive Octeract Upgrades! Ranges from okay to absolutely game-changing Octeract Upgrades.", + "effect": "Gain a +{{proportion}}% chance to convert a Singularity free upgrade into an Octeract free upgrade." + }, + "pixelFreeUpgradeImprovement2": { + "name": "Transfigured Free Upgrades II", + "description": "When you get a free upgrade from code 'daily', there is a +0.1% chance per level that you instead get a free upgrade from a pool of exclusive Octeract Upgrades! Ranges from okay to absolutely game-changing Octeract Upgrades.", + "effect": "Gain a +{{proportion}}% chance to convert a Singularity free upgrade into an Octeract free upgrade." + }, + "pixelFreeUpgradeImprovement3": { + "name": "Transfigured Free Upgrades III", + "description": "When you get a free upgrade from code 'daily', there is a +0.1% chance per level that you instead get a free upgrade from a pool of exclusive Octeract Upgrades! Ranges from okay to absolutely game-changing Octeract Upgrades.", + "effect": "Gain a +{{proportion}}% chance to convert a Singularity free upgrade into an Octeract free upgrade." + } + } + }, "achievements": { "descriptions": { "1": "[{{number}}] A Loyal Employee: Hire your first Worker.", @@ -410,7 +557,21 @@ "277": "[{{number}}] SingularRity: Singularity 4 times.", "278": "[{{number}}] SiINguLaRrRity: Singularity 5 times.", "279": "[{{number}}] SiIINGuLArRrIiTyY: Singularity 7 times.", - "280": "[{{number}}] Inception: Singularity 10 times." + "280": "[{{number}}] Inception: Singularity 10 times.", + "281": "[{{number}}] WIP Luck be a Lady: Obtain 300 ☘ Ambrosia Luck at once!", + "282": "[{{number}}] WIP A couple modules later: Obtain 750 ☘ Ambrosia Luck at once!", + "283": "[{{number}}] WIP A baker's 15/13 dozen: Obtain 1,500 ☘ Ambrosia Luck at once!", + "284": "[{{number}}] WIP <3(,001): Obtain 3,000 ☘ Ambrosia Luck at once!", + "285": "[{{number}}] WIP If you gaze long into an abyss: Obtain 5,000 ☘ Ambrosia Luck at once!", + "286": "[{{number}}] WIP The abyss will also gaze into thee: Obtain 10,000 ☘ Ambrosia Luck at once!", + "287": "[{{number}}] WIP 20,000 Lucks Under The Sea: Obtain 20,000 ☘ Ambrosia Luck at once!", + "288": "[{{number}}] WIP Tutorial Module Unlocked!: Obtain 50 lifetime Ambrosia.", + "289": "[{{number}}] WIP A thousanddaire: Obtain 1,000 lifetime Ambrosia", + "290": "[{{number}}] WIP Enchanted Ambrosia Block: Obtain 25,600 lifetime Ambrosia", + "291": "[{{number}}] WIP Gold Guy's Go-to: Obtain 256,000 lifetime Ambrosia", + "292": "[{{number}}] WIP Maxxed Luck Module: Obtain 1,000,000 lifetime Ambrosia", + "293": "[{{number}}] WIP Just a regular number: Obtain 3,141,592 lifetime Ambrosia", + "294": "[{{number}}] WIP The Egg of ULTRA Acceleration: Obtain 9,999,999 lifetime Ambrosia" }, "rewards": { "3": "Gain +.05% to Accelerator Power.", @@ -570,7 +731,15 @@ "266": "Quarks +{{x}}% [Max: 10% at 1Qa Ascensions]!", "267": "Ascension Score is boosted by {{x}}% [Max: 100% at 1e100,000 Const]", "270": "Hepteract Gain is boosted by {{x}}% [Max: 100% at 1e1,000,000 const], Constant Upgrade 1 boosted to 1.06 (from 1.05), Constant Upgrade 2 boosted to 1.11 (from 1.10).", - "271": "When you open a Platonic Cube, gain {{x}} Hypercubes, rounded down [Max: 1 at 1e1,000,000 Const]" + "271": "When you open a Platonic Cube, gain {{x}} Hypercubes, rounded down [Max: 1 at 1e1,000,000 Const]", + "284": "+1% Global Luck!", + "285": "Every time the Blueberry bar fills up, you get 2 additional Ambrosia for free!", + "286": "If you have under 5,000 Ambrosia Luck, you are guaranteed at least 50 Ambrosia for each time the Blueberry bar fills up", + "287": "Every 1,000,000 Blueberry seconds, gain +0.1s real-life Ascension timer! (Caps at 0.1s per tick)", + "289": "Gain +1% more Blueberry Generation Speed for every unique module activated!", + "291": "Gain 1.01x Blueberry Generation Speed for every blueberry that you have!", + "293": "Your Constant adds +1% Blueberry Generation Speed for every digit in its base-10 exponent.", + "294": "Unlocks a special shop upgrade!" }, "alerts": { "36": "Congratulations on your first Prestige. The first of many. You obtain Offerings. You can use them in the new Runes tab! [Unlocked Runes, Achievements, Diamond Buildings and some Upgrades!]", @@ -1411,10 +1580,10 @@ "shopImprovedDaily2": "Gain 1 additional free Singularity Upgrade and 20% more Golden Quarks per use of 'daily' per level!", "shopImprovedDaily3": "Gain 1 additional free Singularity Upgrade and 15% more Golden Quarks per use of 'daily' per level!", "shopImprovedDaily4": "Gain 1 additional free Singularity Upgrade and 100% more Golden Quarks per use of 'daily' per level!", - "offeringEX3": "Gain 2% more Offerings per level, multiplicative! (Multiplier is 1.02^level)", - "obtainiumEX3": "Gain 2% more Obtainium per level, multiplicative! (Multiplier is 1.02^level)", - "chronometerInfinity": "Gain +1% Ascension Speed per level, multiplicative! (Multiplier is 1.01^level)", - "seasonPassInfinity": "Gain +2% more cubes per level, multiplicative! (Multiplier is 1.02^level)", + "offeringEX3": "Gain 2% more Offerings per level, exponentially!", + "obtainiumEX3": "Gain 2% more Obtainium per level, exponentially!", + "chronometerInfinity": "Gain +1% Ascension Speed per level, exponentially!", + "seasonPassInfinity": "Gain +2% more Cubes per level, exponentially!", "shopSingularityPenaltyDebuff": "Derpsmith was so proud of your performance in the first EXALT that he wants to make your singularity debuffs weaker. At a cost. A big cost.", "obtainiumEX2": "Gain +1% Obtainium per level per Singularity!!!", "improveQuarkHept5": "This is 1/50 as effective as a normal improver. Why? Because of balancing...", @@ -2037,6 +2206,16 @@ "name": "Hourglass of Fantasy", "description": "An hourglass which is unimportant and 'less timely'- whatever that means. +2% Blueberry Second Generation per level.", "effect": "Blueberry Seconds Generation +{{n}}%(!)" + }, + "singPixelLuck": { + "name": "Lucky Little Pixels", + "description": "Like Ambrosia, you can be luckier when harvesting pixels from the Ultimate Progress Bar! +1 ❖ Pixel Luck per level!", + "effect": "❖ Pixel luck +{{n}}(!)" + }, + "singPixelLuck2": { + "name": "Lucky Big Pixels", + "description": "The amount you will spend for very minor stat bonuses is commendable! +1 ❖ Pixel Luck per level!", + "effect": "❖ Pixel luck +{{n}}(!)" } }, "goldenQuarkAmount": "You have {{goldenQuarks}} Golden Quarks!", @@ -2426,7 +2605,8 @@ "singularity": "Singularity", "settings": "Settings", "shop": "Shop", - "unsmith": "UNSMITH" + "unsmith": "UNSMITH", + "testing": "Testing β" }, "buildings": { "coin": "Coin Buildings", @@ -2455,9 +2635,11 @@ "hepteract": "Hepteract Forge" }, "singularity": { - "perks-penalties": "Perks / Penalties", - "octeracts": "Octeracts", - "ambrosia": "Ambrosia" + "perks-penalties": "Perks / Penalties", + "octeracts": "Octeracts", + "exalt": "EXALT", + "ambrosia": "Ambrosia", + "progress": "BAR" }, "settings": { "languages": "🌐 Languages 🌐", @@ -2483,115 +2665,117 @@ "ingameAntSacTimer": "In-Game Ant Sacrifice Timer: +<> seconds", "realAntSacTimer": "Real-Life Ant Sacrifice Timer: +<> seconds", "currentAscensionTimer": "Current Ascension Timer: +<> seconds", - "exportQuarks": "Export Quarks: +<>" + "exportQuarks": "Export Quarks: +<>", + "lifetimeAmbrosia": "Ambrosia: +<>", + "pixels": "Ultimate Pixels: +<>" }, "corruptions": { "names": { - "1": "Corruption I: Viscosity", - "2": "Corruption II: Spacial Dilation", - "3": "Corruption III: Hyperchallenged", - "4": "Corruption IV: Scientific Illiteracy", - "5": "Corruption V: Market Deflation", - "6": "Corruption VI: Extinction", - "7": "Corruption VII: Drought", - "8": "Corruption VIII: Financial Recession" - }, - "descriptions": { - "1": "You feel lethargic across the universe...", - "2": "Way to go, Albert.", - "3": "What's in a challenge?", - "4": "Maybe Albert wouldn't have theorized Dilation after all.", - "5": "Diamond Mine destroyed... no more monopolies!", - "6": "It killed the dinosaurs too, ya Dingus.", - "7": "More like California, am I right?", - "8": "Yet another 2020 catastrophe." - }, - "currentLevel": { - "1": "On this Ascension, this corruption is level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", - "2": "On this Ascension, this corruption is level {{ level }}. Effect: Time Speed is divided by {{ effect }}", - "3": "On this Ascension, this corruption is level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", - "4": "On this Ascension, this corruption is level {{ level }}. Effect: Obtainium gain ^{{ effect }}", - "5": "On this Ascension, this corruption is level {{ level }}. Effect: Diamond gain ^{{ effect }}", - "6": "On this Ascension, this corruption is level {{ level }}. Effect: Ant Production ^{{ effect }}", - "7": "On this Ascension, this corruption is level {{ level }}. Effect: Offering EXP divided by {{ effect }}", - "8": "On this Ascension, this corruption is level {{ level }}. Effect: Coin Gain ^{{ effect }}" - }, - "prototypeLevel": { - "1": "On next Ascension, this corruption will be level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", - "2": "On next Ascension, this corruption will be level {{ level }}. Effect: Time Speed is divided by {{ effect }}", - "3": "On next Ascension, this corruption will be level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", - "4": "On next Ascension, this corruption will be level {{ level }}. Effect: Obtainium gain ^{{ effect }}", - "5": "On next Ascension, this corruption will be level {{ level }}. Effect: Diamond gain ^{{ effect }}", - "6": "On next Ascension, this corruption will be level {{ level }}. Effect: Ant Production ^{{ effect }}", - "7": "On next Ascension, this corruption will be level {{ level }}. Effect: Offering EXP divided by {{ effect }}", - "8": "On next Ascension, this corruption will be level {{ level }}. Effect: Coin Gain ^{{ effect }}" - }, - "scoreMultiplier": "Current Score Multiplier: {{ curr }} / Next Ascension Score Multiplier: {{ next }}", - "spiritEffect": "This corruption gives Rune Spirit Effect +{{curr}}% / Next Ascension Rune Spirit Effect +{{next}}%", - "exitCorruption": { - "name": "CLEANSE THE CORRUPTION", - "description": "Free this world of sin.", - "current": "Reset all Corruptions to level 0 for your current ascension. Does not reset your current ascension.", - "planned": "Push that big 'Reset Corruptions' button to confirm your decision.", - "multiplier": "Note: if you need to do this, you may have bitten off more than you can chew." - }, - "max": "MAX", - "current": "Current: ", - "next": " / Next: ", - "loadoutTable": { - "next": "Next:", - "firstRowTitle": "Click to copy the next Corruptions to the clipboard. This is the format that can be imported", - "otherRowTitle": "Click to rename. Hotkey: SHIFT+{{ value }}", - "import": "Import", - "importTitle": "Import Corruption Loadout in text format", - "zero": "Zero", - "zeroTitle": "Reset Corruptions to zero on your next Ascension. Hotkey: SHIFT+9", - "save": "Save", - "saveTitle": "Save current Corruptions to this Loadout", - "load": "Load" - }, - "importCorruptionsPrompt": { - "import": "Enter a Corruption Loadout to import for next Ascension. It must be in the following text format: 1/2/3/4/5/6/7/8", - "importError": "Your input was not in the correct format, try again." - }, - "corruptionLoadoutName": { - "loadoutPrompt": "What would you like to name Loadout {{ loadNum }}? Names cannot be longer than {{ maxChars }} characters. Nothing crazy!", - "errors": { - "noName": "Okay, maybe next time.", - "exceedsCharacterLimit": "The name you provided is too long! Try again.", - "regexError": "The Loadout Renamer didn't like a character in your name! Try something else.", - "crazyJoke": "Ant God approves of your joke!" - } - }, - "loadoutExport": { - "saveErrorNavigator": "Unable to write the save to clipboard: {{ message }}" - }, - "corrStatsBtn": "Corruption Stats", - "corrLoadoutsBtn": "Corruption Loadouts", - "cleanse": "Cleanse", - "confirm": "Confirm", - "intro": "The most rewarding ventures are those few would dare to embark.", - "traitInfo": "Select the trait levels you wish to run with. Choose wisely! <>", - "antExponent": "This Ascension's climate raises Ant production to the power of <>.", - "spiritBonus": "However, it also multiplies Rune Spirit Effects by <>.", - "corruptionBank": "You have <> Wow! Cubes in the Ascension bank. Gain more by finishing Challenges! Ascend to redeem them.", - "corruptionScore": "Your Ascension Score is <>
(base) * <> (Corruption mult) * <> (Bonus mult) = <>", - "ascensionCount": "If you Ascend now, <> will be added to your ascension count.", - "corruptionCubes": "If you Ascend now, you will gain <> Wow! Cubes.", - "corruptionTesseracts": "If you Ascend now, you will gain <> Wow! Tesseracts. [<100,000>>]", - "corruptionHypercubes": "If you Ascend now, you will gain <> Wow! Hypercubes. [<1,000,000,000>>]", - "corruptionPlatonics": "If you Ascend now, you will gain <> PLATONIC CUBES. [<2,666,000,000,000>>]", - "corruptionHepteracts": "If you Ascend now, you will gain <> HEPTERACTS. [<1.666e17>>]", - "autoAscend": { - "c10Completions": "Ascend when you've completed Sadistic Challenge I a total of <> times, Currently <>", - "realTime": "Ascend when the timer is at least <> seconds (Real-time), Currently <>", - "on": "Auto Ascend [ON]", - "off": "Auto Ascend [OFF]", - "modeCompletions": "Mode: C10 Completions", - "modeRealTime": "Mode: Real time" - }, - "importLoadoutInTextFormat": "Import Corruption Loadout in text format", - "loadoutApplied": "Corruption Loadout from previous run has been applied. This will take effect on the next Ascension." + "viscosity": "Corruption I: Viscosity", + "dilation": "Corruption II: Spacial Dilation", + "hyperchallenge": "Corruption III: Hyperchallenged", + "illiteracy": "Corruption IV: Scientific Illiteracy", + "deflation": "Corruption V: Market Deflation", + "extinction": "Corruption VI: Extinction", + "drought": "Corruption VII: Drought", + "recession": "Corruption VIII: Financial Recession" + }, + "descriptions": { + "viscosity": "You feel lethargic across the universe...", + "dilation": "You feel as though seconds go by in years.", + "hyperchallenge": "You want me to get HOW Many coins??", + "illiteracy": "In the year 2505...", + "deflation": "This ascension lacks carbon...", + "extinction": "It killed the dinosaurs too, ya Dingus.", + "drought": "Where will I grow my offering trees now?", + "recession": "Yet another 2020 catastrophe." + }, + "currentLevel": { + "viscosity": "On this Ascension, this corruption is level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", + "dilation": "On this Ascension, this corruption is level {{ level }}. Effect: Time Speed is divided by {{ effect }}", + "hyperchallenge": "On this Ascension, this corruption is level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", + "illiteracy": "On this Ascension, this corruption is level {{ level }}. Effect: Obtainium gain ^{{ effect }}", + "deflation": "On this Ascension, this corruption is level {{ level }}. Effect: Diamond gain ^{{ effect }}", + "extinction": "On this Ascension, this corruption is level {{ level }}. Effect: Ant Production ^{{ effect }}", + "drought": "On this Ascension, this corruption is level {{ level }}. Effect: Offering EXP divided by {{ effect }}", + "recession": "On this Ascension, this corruption is level {{ level }}. Effect: Coin Gain ^{{ effect }}" + }, + "prototypeLevel": { + "viscosity": "On next Ascension, this corruption will be level {{ level }}. Effect: Free Accel. and Multipliers Exponent ^{{ effect }}", + "dilation": "On next Ascension, this corruption will be level {{ level }}. Effect: Time Speed is divided by {{ effect }}", + "hyperchallenge": "On next Ascension, this corruption will be level {{ level }}. Effect: Challenge Exponent Reqs. x{{ effect }}", + "illiteracy": "On next Ascension, this corruption will be level {{ level }}. Effect: Obtainium gain ^{{ effect }}", + "deflation": "On next Ascension, this corruption will be level {{ level }}. Effect: Diamond gain ^{{ effect }}", + "extinction": "On next Ascension, this corruption will be level {{ level }}. Effect: Ant Production ^{{ effect }}", + "drought": "On next Ascension, this corruption will be level {{ level }}. Effect: Offering EXP divided by {{ effect }}", + "recession": "On next Ascension, this corruption will be level {{ level }}. Effect: Coin Gain ^{{ effect }}" + }, + "scoreMultiplier": "Current Score Multiplier: {{ curr }} / Next Ascension Score Multiplier: {{ next }}", + "spiritEffect": "This corruption gives Rune Spirit Effect +{{curr}}% / Next Ascension Rune Spirit Effect +{{next}}%", + "exitCorruption": { + "name": "CLEANSE THE CORRUPTION", + "description": "Free this world of sin.", + "current": "Reset all Corruptions to level 0 for your current ascension. Does not reset your current ascension.", + "planned": "Push that big 'Reset Corruptions' button to confirm your decision.", + "multiplier": "Note: if you need to do this, you may have bitten off more than you can chew." + }, + "max": "MAX", + "current": "Current: ", + "next": " / Next: ", + "loadoutTable": { + "next": "Next:", + "firstRowTitle": "Click to copy the next Corruptions to the clipboard. This is the format that can be imported", + "otherRowTitle": "Click to rename. Hotkey: SHIFT+{{ value }}", + "import": "Import", + "importTitle": "Import Corruption Loadout in text format", + "zero": "Zero", + "zeroTitle": "Reset Corruptions to zero on your next Ascension. Hotkey: SHIFT+9", + "save": "Save", + "saveTitle": "Save current Corruptions to this Loadout", + "load": "Load" + }, + "importCorruptionsPrompt": { + "import": "Enter a Corruption Loadout to import for next Ascension. It must be in the following text format: 1/2/3/4/5/6/7/8", + "importError": "Your input was not in the correct format, try again." + }, + "corruptionLoadoutName": { + "loadoutPrompt": "What would you like to name Loadout {{ loadNum }}? Names cannot be longer than {{ maxChars }} characters. Nothing crazy!", + "errors": { + "noName": "Okay, maybe next time.", + "exceedsCharacterLimit": "The name you provided is too long! Try again.", + "regexError": "The Loadout Renamer didn't like a character in your name! Try something else.", + "crazyJoke": "Ant God approves of your joke!" + } + }, + "loadoutExport": { + "saveErrorNavigator": "Unable to write the save to clipboard: {{ message }}" + }, + "corrStatsBtn": "Corruption Stats", + "corrLoadoutsBtn": "Corruption Loadouts", + "cleanse": "Cleanse", + "confirm": "Confirm", + "intro": "The most rewarding ventures are those few would dare to embark.", + "traitInfo": "Select the trait levels you wish to run with. Choose wisely! <>", + "antExponent": "This Ascension's climate raises Ant production to the power of <>.", + "spiritBonus": "However, it also multiplies Rune Spirit Effects by <>.", + "corruptionBank": "You have <> Wow! Cubes in the Ascension bank. Gain more by finishing Challenges! Ascend to redeem them.", + "corruptionScore": "Your Ascension Score is <> (base) * <> (Corruption mult) * <> (Bonus mult) = <>", + "ascensionCount": "If you Ascend now, <> will be added to your ascension count.", + "corruptionCubes": "If you Ascend now, you will gain <> Wow! Cubes.", + "corruptionTesseracts": "If you Ascend now, you will gain <> Wow! Tesseracts. [<100,000>>]", + "corruptionHypercubes": "If you Ascend now, you will gain <> Wow! Hypercubes. [<1,000,000,000>>]", + "corruptionPlatonics": "If you Ascend now, you will gain <> PLATONIC CUBES. [<2,666,000,000,000>>]", + "corruptionHepteracts": "If you Ascend now, you will gain <> HEPTERACTS. [<1.666e17>>]", + "autoAscend": { + "c10Completions": "Ascend when you've completed Sadistic Challenge I a total of <> times, Currently <>", + "realTime": "Ascend when the timer is at least <> seconds (Real-time), Currently <>", + "on": "Auto Ascend [ON]", + "off": "Auto Ascend [OFF]", + "modeCompletions": "Mode: C10 Completions", + "modeRealTime": "Mode: Real time" + }, + "importLoadoutInTextFormat": "Import Corruption Loadout in text format", + "loadoutApplied": "Corruption Loadout from previous run has been applied. This will take effect on the next Ascension." }, "footnotes": { "buildings": "Press [1], [2], [3], [4], or [5] to buy the corresponding tier starting from the top. Press [A] to buy Accelerator, [M] to buy Multiplier, or [B] to buy Accelerator Boost.", @@ -2896,6 +3080,16 @@ "name": "Hourglass of Reality", "description": "An hourglass which is nonprimative and 'more timely'- whatever that means. +2% Blueberry Second Generation per level.", "effect": "Blueberry Seconds Generation +{{n}}%(!)" + }, + "octeractPixelLuck": { + "name": "Mega Pixel Luck Bonus", + "description": "Pay a lot of Octeracts, get a few ❖ Pixel Luck. +1 per level, to be precise.", + "effect": "Gain +{{n}} ❖ Pixel Luck!" + }, + "octeractPixelLuck2": { + "name": "Tera Pixel Luck Bonus", + "description": "Pay a LOT of Octeracts, get a few ❖ Pixel Luck. +1 per level, to be precise.", + "effect": "Gain +{{n}} ❖ Pixel Luck!" } }, "amount": "You have {{octeracts}} Octeracts!", @@ -3501,7 +3695,8 @@ "insideSingularityChallenge": "Derpsmith thinks you are in a Singularity Challenge. You may exit it by clicking on the challenge icon in the Exalt tab.", "gameBeat": "Well. It seems you've reached the eye of the Singularity. I'm pleased. This also means there is nowhere to go from here. At least, not until higher powers expand your journey.", "exitAscensionChallenge": "Are you absolutely sure that you want to exit the Ascension Challenge? You will need to clear challenge 10 again before you can attempt the challenge again!", - "buyResearch3x11": "[LOCKED - Buy Research 3x11]" + "buyResearch3x11": "[LOCKED - Buy Research 3x11]", + "levelText": "Level {{level}}/{{maxLevel}}" }, "history": { "perSecondOn": "Per second: ON",