From 99ba5083af989283ecf81e2da72ade2220eb757e Mon Sep 17 00:00:00 2001 From: Pseudonian Date: Wed, 12 Jun 2024 21:31:43 -0400 Subject: [PATCH 1/3] Partial implementation of next update! Removed a rude Alert from a testing feature Port image stuffs Fix remaining port issues Remove references to caches in pixel update Elevator! Translations Translations 2 Update things to consider current sing instead of max sing fix a potentially huge exploit with EXALTs Remove large multiplier to Pixel Generation fixup fixup August 5 Patch seeded rng (#610) * seeded rng * fixup! fixup! Config.ts Campaigns kinda Corruptions Campaign Part 2 Corruptions Campaign Part 2 Actually stage the changes Fix 1: some corruption bug stomping Fix importing corruptions fix NOIMG issues Fix History Change prototype name, fix loading live saves --- Pictures/Default/BlueberryLuckDilator.png | Bin 0 -> 944 bytes Pictures/Default/BlueberryPixelLuck.png | Bin 0 -> 585 bytes ...patialDilation.png => CorruptDilation.png} | Bin ...allenged.png => CorruptHyperchallenge.png} | Bin ...icIlliteracy.png => CorruptIlliteracy.png} | Bin ...ncialCollapse.png => CorruptRecession.png} | Bin ...ruptViscocity.png => CorruptViscosity.png} | Bin Pictures/Default/OcteractPixelLuck.png | Bin 0 -> 1617 bytes Pictures/Default/OcteractPixelLuck2.png | Bin 0 -> 1641 bytes Pictures/Default/PixelAmbrosiaGeneration.png | Bin 0 -> 783 bytes Pictures/Default/PixelAmbrosiaGeneration2.png | Bin 0 -> 796 bytes Pictures/Default/PixelAmbrosiaGeneration3.png | Bin 0 -> 791 bytes Pictures/Default/PixelAmbrosiaLuck.png | Bin 0 -> 817 bytes Pictures/Default/PixelAmbrosiaLuck2.png | Bin 0 -> 829 bytes Pictures/Default/PixelAmbrosiaLuck3.png | Bin 0 -> 831 bytes Pictures/Default/PixelBlueberry.png | Bin 0 -> 789 bytes Pictures/Default/PixelBlueberry2.png | Bin 0 -> 810 bytes Pictures/Default/PixelBlueberry3.png | Bin 0 -> 809 bytes Pictures/Default/PixelCubes.png | Bin 0 -> 761 bytes .../Default/PixelFreeUpgradeImprovement.png | Bin 0 -> 559 bytes .../Default/PixelFreeUpgradeImprovement2.png | Bin 0 -> 624 bytes .../Default/PixelFreeUpgradeImprovement3.png | Bin 0 -> 673 bytes Pictures/Default/PixelObtainium.png | Bin 0 -> 529 bytes Pictures/Default/PixelOfferings.png | Bin 0 -> 615 bytes Pictures/Default/PixelPixelGeneration.png | Bin 0 -> 802 bytes Pictures/Default/PixelPixelGeneration2.png | Bin 0 -> 816 bytes Pictures/Default/PixelPixelGeneration3.png | Bin 0 -> 811 bytes Pictures/Default/PixelPixelLuck.png | Bin 0 -> 576 bytes Pictures/Default/PixelPixelLuckConverter.png | Bin 0 -> 982 bytes Pictures/Default/PixelPixelLuckConverter2.png | Bin 0 -> 982 bytes Pictures/Default/PixelQuarks.png | Bin 0 -> 744 bytes Pictures/Default/PixelRoleBonus.png | Bin 0 -> 593 bytes Pictures/Default/PixelTutorial.png | Bin 0 -> 627 bytes Pictures/Default/PixelTwoMind.png | Bin 0 -> 898 bytes Pictures/Default/SingularityPixelLuck.png | Bin 0 -> 851 bytes Pictures/Default/SingularityPixelLuck2.png | Bin 0 -> 872 bytes Pictures/Default/UltimatePixel.png | Bin 0 -> 497 bytes Pictures/Default/ach414.png | Bin 0 -> 558 bytes Pictures/Default/ach415.png | Bin 0 -> 558 bytes Pictures/Default/ach416.png | Bin 0 -> 558 bytes Pictures/Default/ach417.png | Bin 0 -> 558 bytes Pictures/Default/ach418.png | Bin 0 -> 558 bytes Pictures/Default/ach419.png | Bin 0 -> 558 bytes Pictures/Default/ach420.png | Bin 0 -> 558 bytes Pictures/Default/ach421.png | Bin 0 -> 550 bytes Pictures/Default/ach422.png | Bin 0 -> 550 bytes Pictures/Default/ach423.png | Bin 0 -> 550 bytes Pictures/Default/ach424.png | Bin 0 -> 550 bytes Pictures/Default/ach425.png | Bin 0 -> 550 bytes Pictures/Default/ach426.png | Bin 0 -> 550 bytes Pictures/Default/ach427.png | Bin 0 -> 550 bytes Pictures/Default/ach428.png | Bin 0 -> 386 bytes Pictures/Default/ach429.png | Bin 0 -> 386 bytes Pictures/Default/ach430.png | Bin 0 -> 386 bytes Pictures/Default/ach431.png | Bin 0 -> 464 bytes Pictures/Default/ach432.png | Bin 0 -> 464 bytes Pictures/Default/ach433.png | Bin 0 -> 464 bytes Pictures/Default/ach434.png | Bin 0 -> 482 bytes Pictures/Default/ach435.png | Bin 0 -> 482 bytes Pictures/Default/ach436.png | Bin 0 -> 482 bytes Pictures/Default/ach437.png | Bin 0 -> 265 bytes Pictures/Default/ach438.png | Bin 0 -> 265 bytes Pictures/Default/ach439.png | Bin 0 -> 265 bytes Pictures/Default/patchnotes.png | Bin 996 -> 3690 bytes Pictures/Legacy/BlueberryLuckDilator.png | Bin 0 -> 944 bytes Pictures/Legacy/BlueberryPixelLuck.png | Bin 0 -> 585 bytes ...patialDilation.png => CorruptDilation.png} | Bin ...allenged.png => CorruptHyperchallenge.png} | Bin ...icIlliteracy.png => CorruptIlliteracy.png} | Bin ...ncialCollapse.png => CorruptRecession.png} | Bin ...ruptViscocity.png => CorruptViscosity.png} | Bin Pictures/Legacy/OcteractPixelLuck.png | Bin 0 -> 1617 bytes Pictures/Legacy/OcteractPixelLuck2.png | Bin 0 -> 1641 bytes Pictures/Legacy/PixelAmbrosiaGeneration.png | Bin 0 -> 783 bytes Pictures/Legacy/PixelAmbrosiaGeneration2.png | Bin 0 -> 796 bytes Pictures/Legacy/PixelAmbrosiaGeneration3.png | Bin 0 -> 791 bytes Pictures/Legacy/PixelAmbrosiaLuck.png | Bin 0 -> 817 bytes Pictures/Legacy/PixelAmbrosiaLuck2.png | Bin 0 -> 829 bytes Pictures/Legacy/PixelAmbrosiaLuck3.png | Bin 0 -> 831 bytes Pictures/Legacy/PixelBlueberry.png | Bin 0 -> 789 bytes Pictures/Legacy/PixelBlueberry2.png | Bin 0 -> 810 bytes Pictures/Legacy/PixelBlueberry3.png | Bin 0 -> 809 bytes Pictures/Legacy/PixelCubes.png | Bin 0 -> 761 bytes .../Legacy/PixelFreeUpgradeImprovement.png | Bin 0 -> 559 bytes .../Legacy/PixelFreeUpgradeImprovement2.png | Bin 0 -> 624 bytes .../Legacy/PixelFreeUpgradeImprovement3.png | Bin 0 -> 673 bytes Pictures/Legacy/PixelObtainium.png | Bin 0 -> 529 bytes Pictures/Legacy/PixelOfferings.png | Bin 0 -> 615 bytes Pictures/Legacy/PixelPixelGeneration.png | Bin 0 -> 802 bytes Pictures/Legacy/PixelPixelGeneration2.png | Bin 0 -> 816 bytes Pictures/Legacy/PixelPixelGeneration3.png | Bin 0 -> 811 bytes Pictures/Legacy/PixelPixelLuck.png | Bin 0 -> 576 bytes Pictures/Legacy/PixelPixelLuckConverter.png | Bin 0 -> 982 bytes Pictures/Legacy/PixelPixelLuckConverter2.png | Bin 0 -> 982 bytes Pictures/Legacy/PixelQuarks.png | Bin 0 -> 744 bytes Pictures/Legacy/PixelRoleBonus.png | Bin 0 -> 593 bytes Pictures/Legacy/PixelTutorial.png | Bin 0 -> 627 bytes Pictures/Legacy/PixelTwoMind.png | Bin 0 -> 898 bytes Pictures/Legacy/SingularityPixelLuck.png | Bin 0 -> 851 bytes Pictures/Legacy/SingularityPixelLuck2.png | Bin 0 -> 872 bytes Pictures/Legacy/UltimatePixel.png | Bin 0 -> 497 bytes ...patialDilation.png => CorruptDilation.png} | Bin ...allenged.png => CorruptHyperchallenge.png} | Bin ...icIlliteracy.png => CorruptIlliteracy.png} | Bin ...ncialCollapse.png => CorruptRecession.png} | Bin ...ruptViscocity.png => CorruptViscosity.png} | Bin .../Monotonous/PixelAmbrosiaGeneration.png | Bin 0 -> 783 bytes .../Monotonous/PixelAmbrosiaGeneration2.png | Bin 0 -> 796 bytes .../Monotonous/PixelAmbrosiaGeneration3.png | Bin 0 -> 791 bytes Pictures/Monotonous/PixelAmbrosiaLuck.png | Bin 0 -> 817 bytes Pictures/Monotonous/PixelAmbrosiaLuck2.png | Bin 0 -> 829 bytes Pictures/Monotonous/PixelAmbrosiaLuck3.png | Bin 0 -> 831 bytes Pictures/Monotonous/PixelBlueberry.png | Bin 0 -> 789 bytes Pictures/Monotonous/PixelBlueberry2.png | Bin 0 -> 810 bytes Pictures/Monotonous/PixelBlueberry3.png | Bin 0 -> 809 bytes Pictures/Monotonous/PixelCubes.png | Bin 0 -> 761 bytes .../PixelFreeUpgradeImprovement.png | Bin 0 -> 559 bytes .../PixelFreeUpgradeImprovement2.png | Bin 0 -> 624 bytes .../PixelFreeUpgradeImprovement3.png | Bin 0 -> 673 bytes Pictures/Monotonous/PixelObtainium.png | Bin 0 -> 529 bytes Pictures/Monotonous/PixelOfferings.png | Bin 0 -> 615 bytes Pictures/Monotonous/PixelPixelGeneration.png | Bin 0 -> 802 bytes Pictures/Monotonous/PixelPixelGeneration2.png | Bin 0 -> 816 bytes Pictures/Monotonous/PixelPixelGeneration3.png | Bin 0 -> 811 bytes Pictures/Monotonous/PixelPixelLuck.png | Bin 0 -> 576 bytes .../Monotonous/PixelPixelLuckConverter.png | Bin 0 -> 982 bytes .../Monotonous/PixelPixelLuckConverter2.png | Bin 0 -> 982 bytes Pictures/Monotonous/PixelQuarks.png | Bin 0 -> 744 bytes Pictures/Monotonous/PixelRoleBonus.png | Bin 0 -> 593 bytes Pictures/Monotonous/PixelTutorial.png | Bin 0 -> 627 bytes Pictures/Monotonous/PixelTwoMind.png | Bin 0 -> 898 bytes ...patialDilation.png => CorruptDilation.png} | Bin ...allenged.png => CorruptHyperchallenge.png} | Bin ...icIlliteracy.png => CorruptIlliteracy.png} | Bin ...ncialCollapse.png => CorruptRecession.png} | Bin ...ruptViscocity.png => CorruptViscosity.png} | Bin .../Simplified/PixelAmbrosiaGeneration.png | Bin 0 -> 783 bytes .../Simplified/PixelAmbrosiaGeneration2.png | Bin 0 -> 796 bytes .../Simplified/PixelAmbrosiaGeneration3.png | Bin 0 -> 791 bytes Pictures/Simplified/PixelAmbrosiaLuck.png | Bin 0 -> 817 bytes Pictures/Simplified/PixelAmbrosiaLuck2.png | Bin 0 -> 829 bytes Pictures/Simplified/PixelAmbrosiaLuck3.png | Bin 0 -> 831 bytes Pictures/Simplified/PixelBlueberry.png | Bin 0 -> 789 bytes Pictures/Simplified/PixelBlueberry2.png | Bin 0 -> 810 bytes Pictures/Simplified/PixelBlueberry3.png | Bin 0 -> 809 bytes Pictures/Simplified/PixelCubes.png | Bin 0 -> 761 bytes .../PixelFreeUpgradeImprovement.png | Bin 0 -> 559 bytes .../PixelFreeUpgradeImprovement2.png | Bin 0 -> 624 bytes .../PixelFreeUpgradeImprovement3.png | Bin 0 -> 673 bytes Pictures/Simplified/PixelObtainium.png | Bin 0 -> 529 bytes Pictures/Simplified/PixelOfferings.png | Bin 0 -> 615 bytes Pictures/Simplified/PixelPixelGeneration.png | Bin 0 -> 802 bytes Pictures/Simplified/PixelPixelGeneration2.png | Bin 0 -> 816 bytes Pictures/Simplified/PixelPixelGeneration3.png | Bin 0 -> 811 bytes Pictures/Simplified/PixelPixelLuck.png | Bin 0 -> 576 bytes .../Simplified/PixelPixelLuckConverter.png | Bin 0 -> 982 bytes .../Simplified/PixelPixelLuckConverter2.png | Bin 0 -> 982 bytes Pictures/Simplified/PixelQuarks.png | Bin 0 -> 744 bytes Pictures/Simplified/PixelRoleBonus.png | Bin 0 -> 593 bytes Pictures/Simplified/PixelTutorial.png | Bin 0 -> 627 bytes Pictures/Simplified/PixelTwoMind.png | Bin 0 -> 898 bytes Synergism.css | 142 ++- index.html | 503 ++++++++--- package.json | 1 + src/Achievements.ts | 9 +- src/Ants.ts | 2 +- src/BlueberryUpgrades.ts | 94 +- src/Calculate.ts | 284 ++++-- src/Campaign.ts | 138 +++ src/Challenges.ts | 11 +- src/Config.ts | 4 +- src/Corruptions.ts | 640 ++++++++++---- src/DynamicUpgrade.ts | 11 + src/Event.ts | 7 +- src/EventListeners.ts | 89 +- src/Helper.ts | 57 +- src/History.ts | 96 +- src/Hotkeys.ts | 2 +- src/ImportExport.ts | 107 ++- src/Octeracts.ts | 47 +- src/PixelUpgrades.ts | 830 ++++++++++++++++++ src/Plugins/Dashboard.ts | 2 +- src/RNG.ts | 18 + src/Reset.ts | 58 +- src/SingularityChallenges.ts | 14 +- src/StatCache.ts | 287 +++++- src/Statistics.ts | 126 ++- src/Summary.ts | 108 ++- src/Synergism.ts | 268 ++++-- src/Tabs.ts | 39 +- src/Toggles.ts | 66 +- src/UpdateHTML.ts | 22 +- src/UpdateVisuals.ts | 99 ++- src/Utility.ts | 5 + src/Variables.ts | 16 +- src/saves/PlayerJsonSchema.ts | 76 +- src/saves/PlayerSchema.ts | 74 +- src/saves/PlayerUpdateVarSchema.ts | 47 + src/singularity.ts | 132 ++- src/types/FastMersenneTwister.d.ts | 24 + src/types/Synergism.d.ts | 41 +- translations/da.json | 72 +- translations/en.json | 342 ++++++-- translations/source.json | 429 ++++++--- 204 files changed, 4497 insertions(+), 942 deletions(-) create mode 100644 Pictures/Default/BlueberryLuckDilator.png create mode 100644 Pictures/Default/BlueberryPixelLuck.png rename Pictures/Default/{CorruptSpatialDilation.png => CorruptDilation.png} (100%) rename Pictures/Default/{CorruptHyperchallenged.png => CorruptHyperchallenge.png} (100%) rename Pictures/Default/{CorruptScientificIlliteracy.png => CorruptIlliteracy.png} (100%) rename Pictures/Default/{CorruptFinancialCollapse.png => CorruptRecession.png} (100%) rename Pictures/Default/{CorruptViscocity.png => CorruptViscosity.png} (100%) create mode 100644 Pictures/Default/OcteractPixelLuck.png create mode 100644 Pictures/Default/OcteractPixelLuck2.png create mode 100644 Pictures/Default/PixelAmbrosiaGeneration.png create mode 100644 Pictures/Default/PixelAmbrosiaGeneration2.png create mode 100644 Pictures/Default/PixelAmbrosiaGeneration3.png create mode 100644 Pictures/Default/PixelAmbrosiaLuck.png create mode 100644 Pictures/Default/PixelAmbrosiaLuck2.png create mode 100644 Pictures/Default/PixelAmbrosiaLuck3.png create mode 100644 Pictures/Default/PixelBlueberry.png create mode 100644 Pictures/Default/PixelBlueberry2.png create mode 100644 Pictures/Default/PixelBlueberry3.png create mode 100644 Pictures/Default/PixelCubes.png create mode 100644 Pictures/Default/PixelFreeUpgradeImprovement.png create mode 100644 Pictures/Default/PixelFreeUpgradeImprovement2.png create mode 100644 Pictures/Default/PixelFreeUpgradeImprovement3.png create mode 100644 Pictures/Default/PixelObtainium.png create mode 100644 Pictures/Default/PixelOfferings.png create mode 100644 Pictures/Default/PixelPixelGeneration.png create mode 100644 Pictures/Default/PixelPixelGeneration2.png create mode 100644 Pictures/Default/PixelPixelGeneration3.png create mode 100644 Pictures/Default/PixelPixelLuck.png create mode 100644 Pictures/Default/PixelPixelLuckConverter.png create mode 100644 Pictures/Default/PixelPixelLuckConverter2.png create mode 100644 Pictures/Default/PixelQuarks.png create mode 100644 Pictures/Default/PixelRoleBonus.png create mode 100644 Pictures/Default/PixelTutorial.png create mode 100644 Pictures/Default/PixelTwoMind.png create mode 100644 Pictures/Default/SingularityPixelLuck.png create mode 100644 Pictures/Default/SingularityPixelLuck2.png create mode 100644 Pictures/Default/UltimatePixel.png create mode 100644 Pictures/Default/ach414.png create mode 100644 Pictures/Default/ach415.png create mode 100644 Pictures/Default/ach416.png create mode 100644 Pictures/Default/ach417.png create mode 100644 Pictures/Default/ach418.png create mode 100644 Pictures/Default/ach419.png create mode 100644 Pictures/Default/ach420.png create mode 100644 Pictures/Default/ach421.png create mode 100644 Pictures/Default/ach422.png create mode 100644 Pictures/Default/ach423.png create mode 100644 Pictures/Default/ach424.png create mode 100644 Pictures/Default/ach425.png create mode 100644 Pictures/Default/ach426.png create mode 100644 Pictures/Default/ach427.png create mode 100644 Pictures/Default/ach428.png create mode 100644 Pictures/Default/ach429.png create mode 100644 Pictures/Default/ach430.png create mode 100644 Pictures/Default/ach431.png create mode 100644 Pictures/Default/ach432.png create mode 100644 Pictures/Default/ach433.png create mode 100644 Pictures/Default/ach434.png create mode 100644 Pictures/Default/ach435.png create mode 100644 Pictures/Default/ach436.png create mode 100644 Pictures/Default/ach437.png create mode 100644 Pictures/Default/ach438.png create mode 100644 Pictures/Default/ach439.png create mode 100644 Pictures/Legacy/BlueberryLuckDilator.png create mode 100644 Pictures/Legacy/BlueberryPixelLuck.png rename Pictures/Legacy/{CorruptSpatialDilation.png => CorruptDilation.png} (100%) rename Pictures/Legacy/{CorruptHyperchallenged.png => CorruptHyperchallenge.png} (100%) rename Pictures/Legacy/{CorruptScientificIlliteracy.png => CorruptIlliteracy.png} (100%) rename Pictures/Legacy/{CorruptFinancialCollapse.png => CorruptRecession.png} (100%) rename Pictures/Legacy/{CorruptViscocity.png => CorruptViscosity.png} (100%) create mode 100644 Pictures/Legacy/OcteractPixelLuck.png create mode 100644 Pictures/Legacy/OcteractPixelLuck2.png create mode 100644 Pictures/Legacy/PixelAmbrosiaGeneration.png create mode 100644 Pictures/Legacy/PixelAmbrosiaGeneration2.png create mode 100644 Pictures/Legacy/PixelAmbrosiaGeneration3.png create mode 100644 Pictures/Legacy/PixelAmbrosiaLuck.png create mode 100644 Pictures/Legacy/PixelAmbrosiaLuck2.png create mode 100644 Pictures/Legacy/PixelAmbrosiaLuck3.png create mode 100644 Pictures/Legacy/PixelBlueberry.png create mode 100644 Pictures/Legacy/PixelBlueberry2.png create mode 100644 Pictures/Legacy/PixelBlueberry3.png create mode 100644 Pictures/Legacy/PixelCubes.png create mode 100644 Pictures/Legacy/PixelFreeUpgradeImprovement.png create mode 100644 Pictures/Legacy/PixelFreeUpgradeImprovement2.png create mode 100644 Pictures/Legacy/PixelFreeUpgradeImprovement3.png create mode 100644 Pictures/Legacy/PixelObtainium.png create mode 100644 Pictures/Legacy/PixelOfferings.png create mode 100644 Pictures/Legacy/PixelPixelGeneration.png create mode 100644 Pictures/Legacy/PixelPixelGeneration2.png create mode 100644 Pictures/Legacy/PixelPixelGeneration3.png create mode 100644 Pictures/Legacy/PixelPixelLuck.png create mode 100644 Pictures/Legacy/PixelPixelLuckConverter.png create mode 100644 Pictures/Legacy/PixelPixelLuckConverter2.png create mode 100644 Pictures/Legacy/PixelQuarks.png create mode 100644 Pictures/Legacy/PixelRoleBonus.png create mode 100644 Pictures/Legacy/PixelTutorial.png create mode 100644 Pictures/Legacy/PixelTwoMind.png create mode 100644 Pictures/Legacy/SingularityPixelLuck.png create mode 100644 Pictures/Legacy/SingularityPixelLuck2.png create mode 100644 Pictures/Legacy/UltimatePixel.png rename Pictures/Monotonous/{CorruptSpatialDilation.png => CorruptDilation.png} (100%) rename Pictures/Monotonous/{CorruptHyperchallenged.png => CorruptHyperchallenge.png} (100%) rename Pictures/Monotonous/{CorruptScientificIlliteracy.png => CorruptIlliteracy.png} (100%) rename Pictures/Monotonous/{CorruptFinancialCollapse.png => CorruptRecession.png} (100%) rename Pictures/Monotonous/{CorruptViscocity.png => CorruptViscosity.png} (100%) create mode 100644 Pictures/Monotonous/PixelAmbrosiaGeneration.png create mode 100644 Pictures/Monotonous/PixelAmbrosiaGeneration2.png create mode 100644 Pictures/Monotonous/PixelAmbrosiaGeneration3.png create mode 100644 Pictures/Monotonous/PixelAmbrosiaLuck.png create mode 100644 Pictures/Monotonous/PixelAmbrosiaLuck2.png create mode 100644 Pictures/Monotonous/PixelAmbrosiaLuck3.png create mode 100644 Pictures/Monotonous/PixelBlueberry.png create mode 100644 Pictures/Monotonous/PixelBlueberry2.png create mode 100644 Pictures/Monotonous/PixelBlueberry3.png create mode 100644 Pictures/Monotonous/PixelCubes.png create mode 100644 Pictures/Monotonous/PixelFreeUpgradeImprovement.png create mode 100644 Pictures/Monotonous/PixelFreeUpgradeImprovement2.png create mode 100644 Pictures/Monotonous/PixelFreeUpgradeImprovement3.png create mode 100644 Pictures/Monotonous/PixelObtainium.png create mode 100644 Pictures/Monotonous/PixelOfferings.png create mode 100644 Pictures/Monotonous/PixelPixelGeneration.png create mode 100644 Pictures/Monotonous/PixelPixelGeneration2.png create mode 100644 Pictures/Monotonous/PixelPixelGeneration3.png create mode 100644 Pictures/Monotonous/PixelPixelLuck.png create mode 100644 Pictures/Monotonous/PixelPixelLuckConverter.png create mode 100644 Pictures/Monotonous/PixelPixelLuckConverter2.png create mode 100644 Pictures/Monotonous/PixelQuarks.png create mode 100644 Pictures/Monotonous/PixelRoleBonus.png create mode 100644 Pictures/Monotonous/PixelTutorial.png create mode 100644 Pictures/Monotonous/PixelTwoMind.png rename Pictures/Simplified/{CorruptSpatialDilation.png => CorruptDilation.png} (100%) rename Pictures/Simplified/{CorruptHyperchallenged.png => CorruptHyperchallenge.png} (100%) rename Pictures/Simplified/{CorruptScientificIlliteracy.png => CorruptIlliteracy.png} (100%) rename Pictures/Simplified/{CorruptFinancialCollapse.png => CorruptRecession.png} (100%) rename Pictures/Simplified/{CorruptViscocity.png => CorruptViscosity.png} (100%) create mode 100644 Pictures/Simplified/PixelAmbrosiaGeneration.png create mode 100644 Pictures/Simplified/PixelAmbrosiaGeneration2.png create mode 100644 Pictures/Simplified/PixelAmbrosiaGeneration3.png create mode 100644 Pictures/Simplified/PixelAmbrosiaLuck.png create mode 100644 Pictures/Simplified/PixelAmbrosiaLuck2.png create mode 100644 Pictures/Simplified/PixelAmbrosiaLuck3.png create mode 100644 Pictures/Simplified/PixelBlueberry.png create mode 100644 Pictures/Simplified/PixelBlueberry2.png create mode 100644 Pictures/Simplified/PixelBlueberry3.png create mode 100644 Pictures/Simplified/PixelCubes.png create mode 100644 Pictures/Simplified/PixelFreeUpgradeImprovement.png create mode 100644 Pictures/Simplified/PixelFreeUpgradeImprovement2.png create mode 100644 Pictures/Simplified/PixelFreeUpgradeImprovement3.png create mode 100644 Pictures/Simplified/PixelObtainium.png create mode 100644 Pictures/Simplified/PixelOfferings.png create mode 100644 Pictures/Simplified/PixelPixelGeneration.png create mode 100644 Pictures/Simplified/PixelPixelGeneration2.png create mode 100644 Pictures/Simplified/PixelPixelGeneration3.png create mode 100644 Pictures/Simplified/PixelPixelLuck.png create mode 100644 Pictures/Simplified/PixelPixelLuckConverter.png create mode 100644 Pictures/Simplified/PixelPixelLuckConverter2.png create mode 100644 Pictures/Simplified/PixelQuarks.png create mode 100644 Pictures/Simplified/PixelRoleBonus.png create mode 100644 Pictures/Simplified/PixelTutorial.png create mode 100644 Pictures/Simplified/PixelTwoMind.png create mode 100644 src/Campaign.ts create mode 100644 src/PixelUpgrades.ts create mode 100644 src/RNG.ts create mode 100644 src/saves/PlayerUpdateVarSchema.ts create mode 100644 src/types/FastMersenneTwister.d.ts diff --git a/Pictures/Default/BlueberryLuckDilator.png b/Pictures/Default/BlueberryLuckDilator.png new file mode 100644 index 0000000000000000000000000000000000000000..f10ea35bf9fd046abac983f9fbb74f84651a1aee GIT binary patch literal 944 zcmV;h15f;kP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ9414T(hK~z{r#ga>mZTgsR#w3tb;`1DWrQ)ffp&Lh@ilrL!{85L){|qkf*Lnhv?72 zgV{ka!Voev5L(4Dv(&J4+V9(WtpQoxe^g?$y}hU+Nk*Y-?;^(15sL0!R{9)AyBK zbhjaC-1a%T)Md0XOFtHAt8M_Fc&=+ew@RQds=LCDlEwx2uAQDRebCP6y1_QEncefA z#y{lgXv0ZvLr_+V`q`GZ+<$MXhQCDZ`s?=z%Fcibdv&dCr>Lgh&R02o)Izy^&0Mzw z4B-s`lSO=R@s)85LO}r7@*EvRC=h1=B1{kNa_X`2)yWk-T4Hr~!~y{6$La;xVh(~B zzjW1^jkMaq-_+v5H?FwAp3BNzt444LG7fAJgq#;2&<>t~M{TvbwoW_~KvpkfwoOtH zWdXRZAe>17vbyPdoJuH&V@v;sWeIT-akW4+XyB zZ-P+q4hWcF9~?Pw0DF&>3#iX`j!`auK=%}FilTx~9HbWJzVZ)45^yNRM>RG!(Dr7) zTt$t%bf8x?@ror2H#_HOr#eU-{dc$xuzdo2#j}uED_uip03vRS+V`Ajg#{4=Kpm9X z=qk>IyaTSSC_99%HycjlkBqztyyus1P)Ge}RW|^{HG=QJ`VUJ95%&p6U^cj}A%Xz_ z+;I>R@11PYwGv_@b3>$-^K<517O+=*l8fm@ng^dhtq?EF6wGPIUAMFSh{7u{f2?D&Hc*)-oV&hwNoQeSOR!h-c%;D^D zE=WDf_ny;yy-*+~&n{MuV&n4(BHI5}v|?yq8Qf!CHRSqV5DhPzvtVPd z-sSIDWXeRBUH@l8M`ATEznHGA#z1?`B^ zPt=i2f!l9>oe4S;?CnSrcY*ZdJEWG%0|3Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940p3YOK~z{r#gxBJ z!!QuWFAjyOC1UK{2SALKcoYVh8JUnkVqjq99T*Th?|{UJc!16o5^9t-Dhf^LnR9US z$Mrd-{Yg>mHebFk_W8V{^Y09{hzyWE+|YEhh|}A0fcNR0N5g;NuzMv}Tx4B2 zSAuJvUSt_wG_?Xfq&blXa4{c-L%@q0;w`?;y+k~TXlRczAH^eixr9K_dua=7(9LJ_ z8AM6cCP0kO6aw|;qL_Qmxq9hM}I z&ee!_EQ%(1BI3UifSVJt!vn#{4XO{b$yufskC zy17fAQ26se-dO>P=G;C}g-AaZ&4Bvyrjgz>wgUGPiwY~-rB77Bu7P5RCgun`0HTLz zVvghi278aZ;-L^O=EpnFxt9mtQ#RO5X$tWAb>j3Tw&>@00000NkvXXu0mjf{lNda literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d94d5b9ae87a84bec5a20ab19744e8c4256a1376 GIT binary patch literal 1617 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 literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelAmbrosiaGeneration.png b/Pictures/Default/PixelAmbrosiaGeneration.png new file mode 100644 index 0000000000000000000000000000000000000000..216e2cd247bc20728eb1de0f4d04c94fab63d0fc GIT binary patch literal 783 zcmV+q1MvKbP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0;EYqK~z{ry_daf z6hRoqXBI-j`B=5UczNg0T@BB}8n3X~f3HN`!!gkVY(QER=vm(kUS}!6p$* zn<|Bf_<D1yL&UUJ4-G1@{yaIZLLQ z>@=IAL4!-9B6O9w*d=8&DjlU6I;Bz<+M&Jv*$T7^Wq@H55Sf@g5CkLVsSrz_TJ2g< zK7ncUF3>qdzQ1Y3ER5JkoOQi2z_1CxMtn!klrjL=#E);Xv^cV0H6SB&)d-eZBuaIZ zh$---R0fjbJPFI1@HUVX2Y3Zc853Rxvf=>CF^R8Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0Qvejc09stXK;p{cpq z)=esdccbI_!PajI4w~E5TGqhhzng)nc7^Nx)i~ofhYzVlp1Lg#(i(9F^28Ufof6l| z*IzrPmgLUz7jaBv0vX6Pz`~LU^Kr9BO;mTOWDoCon3fOsly zo}V*Oai-_y)y1=yo#W0_hG-2a7(ig!oxs4$U5!44FZ9QKt-2FvLfgMz8l+j|QRKdG ztJzcynw+0=Jwec#m5Gv!9M_2p{m|e1ECOw32DF7~BG?2(CTI5q!RQ$()Y7MRzjl;Q z=$d_CFku1=4w3J#+A#|wE+fvm-VB&91DgPBr0mQYaS@s%hy${TAK!wG#gPTkfJuUw z1-xc0QL3XvOhHMU2F&CM)0Ds#=SA452{8i_wm85eU^+2T%0OBi;B~YqYa-lkZ3abf ziGz*BY+D%J{9pSG5eVldpjV* z8xr?pGk2%Qy(YXFVDZN5=Zbeeh6O>|3_yR}2V6%oPEPQsc0{j6b@ifA&#b2OnQ-#P zJ=J&m64jA~Gz(AKf?(s}Eh?o`(S^PNeZDf_HvrfKW1C51i!#!YEH-ezdRV_{MARsm z0KSv0gme~!ILg?->c2Yu0M>UR(Zqf*)mw=ta;1MLYv3S>4IuEnvc6Y!IOlJ;?<+kR ahU!0l%AldPAg0g&0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0<1|yK~z{ry_daf z6hRoqXBI-jFTqX@ZT7l?VX~A&sO+W1$2jlFkrf6KoPe zTdNcz;s;t-X+F%kUI^TH&wKN3W_M?1caL0tu*|%3v-3Rj?(FQG{C#dzi8jz11iEHt zU)8CU9|lL%!rl%AC(VO$C2io@-(9JzZQ)LLIm-CG{!=2Br*?~jq(+p1Eb*n8i_W$3 zefvPy;yhga<{T55Kn5}mu&_&n`Mld9M$3m(GKhiA2pgbB5b70~B(FGNF_e5Ux5qCy zvlqC;kBi|-r>@0;E-vrOI=%RjQinnK%7fW|<7-{K*!<*N3-bNhVOj&r;U8zGwT+i* zb#7Ki`I(%Z6W1qhTF0F#_0bv-Fn~a}TY-VshYEdiU+9nf8g(nsgtmXb)VOAmMV|YD zy?R~LXmWn8bV%8lm5$;J45`?Ke(0}%b^>i{29$wrBG?2(#-@)1!Qf>o#PXMBzh;z8 zV4JxXPv99d{70|2jC zLzL<$5mQhQZw7#FieZZLB5c)!)qoFE9N-Z!t(YieASn*;I+_$U5$rcMgFM*8!PZi` zt%wQAK*6kGa4LBtGB>0mVDh;hfo=9lL2O87Tiz_tx4;LVig=co{nYuR9gyJ-iTkmc zN0TF76W$E4c!~!+mVcuBcE2zsP(WaUe&6p)s#FFj@^AMx-Q+I zIf05-vxW|EkqjO$1i8JI7hR_|&dHM&dy-^td6 z>nsRyl#zk;e^vScY#xM86UV`LXDOPPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0>(*1K~z{ry_dgh z6hRcnXO{%eoO^rziX=oNk|tnbbzCJ9NM#{nz{W3 zj?4RvP4RrI8Av-`#C~!Z1!b0;Q#ViNnUYWF{1kc zNE}7R_q?(ibo~D9YxO)ce@;CC-n&-)q_-0@@*v1533Ep{|5!PH2gctqi397|kxBWq)ex^bt;mG%o{mko`;FvPZ?;;hv)5cI vmU;o8Lsc1v>8QGWKEp?o|H1Y?;cf8`mf-bwzZ&?800000NkvXXu0mjfWqWXe literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelAmbrosiaLuck2.png b/Pictures/Default/PixelAmbrosiaLuck2.png new file mode 100644 index 0000000000000000000000000000000000000000..8f5f049f204e8d77fe2cee37a55a84cc733d7991 GIT binary patch literal 829 zcmV-D1H$}?P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0@6uDK~z{ry_dgh z6hRcnXO{%eoO^rziX=oNk|tnbbzCJ9NM#{nz{WXnPaW>i7Bmez_D#=Mbp$> z^RzyXPwIR1-=;HYZk7*)16XKpSk%mg`C{42_;vT7^5rRSaS+t-0^lFC!2FN{GKf&6 zSOj$=sa>!&jJlzI7EAzts3HMvKGqq8D$ZF2V`15+X{oWLI73MYWr4+RO*f3OFxvB@ zYng(8E-dn}QWAWQr1)KT%oq!!{m`1o90Z810YF1Oe!5?&r95Fqw$l=sfkBcO08+_D zLm`GI3)J$HW-YLmjvd$c8yo7`X498)EX4bid}uD4cU-6zY2+VUs~xrdecPKO!PxYR zuFwDFk&?dRxN3;{K3E(@Cf|8w#qaptn^)#}X7-$U0<61M{YX8fj@D18N)3g%tb;*- zp-$k)OK}vLQm`I{YVX-uY5TIkyJz9YiY5YA?fBX`9f2TN_rHn|;@JK3x2KG~|FUGn zA?y=RK_~!3h^VtK59}R3V9^C-S38s&4AoJ8v|z-XFgF+nKs7a<|h$b0}DUK)K&eBMth*r z`K$v7b08Sw-zD$?Ur{vx>}EIoZzzLcrz|WT;rwIgat%zbNfHOv(<9^hNvok=c3Pnc z!FR?^F#cfnu&I392|H?mgx+dOT|(z0Cc!2qewccZlBNa;e?MY$F|j9@emD$TU~v#00000NkvXX Hu0mjfEV_4# literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelAmbrosiaLuck3.png b/Pictures/Default/PixelAmbrosiaLuck3.png new file mode 100644 index 0000000000000000000000000000000000000000..f397639a56d685ed8276c45e157af56224dee51d GIT binary patch literal 831 zcmV-F1Hk-=P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0@O)FK~z{ry_dgh z6hRcnXO{%eoO^rziX=oNk|tnbbzCJ9NM#{nz{WwgXQY)Ie zZkwm`d3;jetNu2fL36Ws$PQqkx#3VV6Xx^9ZpN?s2UQ?XS&M_PMmGTdK?}?e86bnO zD#anF8%gDYt6|i&`u$)6_(K&5Xz{VmAXM_sDi{mPK21xFE5!jNATk3ic5Aw3jD^vj zA6@G!25n@q9Hz{QxYEB9nVwS_wLS_vV#(o|!#oo&fJ%D}SV(Qb(&NRH=f(T-M**Q(y&v2(f3kD+P66nWFavFzt)>3y)XuCUOj_0#=`Sp@R5WS zfUJSVlT+rH@llfkQOG07?Or!zYzE}&*%&yxIP-~m%Cs>SH$REk8d&%-rmpI5G}-}` z&SxD!m;=EW|1N6l;MUv0e?uUHV5clB9pU_AnDwxdf94N z6T*AOPB8vp_OPjZ+zDZUxc4M;`#n9E_mTq$!;X{0)4~C`)rc*Kf>({S?^axrcn^em zw0hbI?}hkQzgIEDaOFaHFIEna{k}2)Q8pUdHQi%)K6k*nrLsb5nGE1V5jL}LB=aDk z!Fs^CQykT=HyfriXfEXoodD3`s*ED(sQNuV!-o?-vOL#Se*qC64Tc`8%I*LF002ov JPDHLkV1fl9bwdCE literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelBlueberry.png b/Pictures/Default/PixelBlueberry.png new file mode 100644 index 0000000000000000000000000000000000000000..82caf946ef082189d574d63eab707d3c91771c19 GIT binary patch literal 789 zcmV+w1M2*VP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0;)+wK~z{r#h1@( z6G0TmXV(PNrkljoRt>@5=t=CM`Uga*r=miNUcFSjc`W!3c<8}vbMa^o1(jk!Q4fL_ z>BWoSK~V%flt%NzB#@Xf-?uyKWV5rgk#79JV|FIf{l53+y-8#26i#s#1D0vJPr=lA zk4EEt{y4v1{Xvs)vz)Vs9Vq|$X}FKEu$0bu8NZX=#|H8gw>a=?cn*jUcpqAb5!s3G zN*M#>K+~$(Ps2+@&Fg95DL0j|0pt>~LZ3 zl1EU)5XacvZqi(ZHUmQR^E;c(9&t?N2$(7sSn90p&h$h&g4)-=FZ}kMF*pN*6LRzr z_eY$Vo@5^{K2qK=ef!$ZVHsv@extl-b(Y9~w0%O<4SPCKv92s?tSfYST+J${aiAc&c*(4&1b|>KcH! zsCL;vP}HI>#Ga@GIv~Ww*~`dI;PVS}G-Zk8D=N@YQD(sI>!9rrnTSph6eWuDU(mK8 zB7^yz0P?+n&M@}eqi0bgQ84TM%fOHP0z`%vFD}k|=|*<22cry*#J{G4GSCUR3*?^9 zA08Cwekjvi*y}gW+NahnZ5sjvZ>$~2^M{QZd(v(U{LzVtRh~FA+-48}LInG0!6m9V z+OU+in6YXf;+xIJkORQ~au8KOhj4(wfh(yg^%=wjG?9I67sScP--dDEwc$9ALDr%S z;D;itxOXykC!itpfU%OB;hU`nO~%djbjEQ2ld#JO#iAms`5B%J{wJHTOq2ZqPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0>4Q_K~z{ry_e5x z6G0TmXV(PNrupI8Rt=&4L{DN5)juFgJrxyF^eRY2ym&11AMoJ8Yjg2v4+WKCK~WEa z7wN@|;6YIYJ(NcC!z7THvER2dak9I!lN2@|c+9@p$$sB^^Jc?ZJNZ+bML^27#Z@ph z-lfs{m^;oNR(_E)YL>H(KY-Go-1=oax=xps zsZK4?sB-L_8>uM>1aLEz(f0tvWw)yag0hxT|s zMOy)9R|m%qnaS)VL0O_X_k!^lA~Tpb2%x?fa5AiY_vu>p$ROCY-IswE^#RBX4_;iH z@0APx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0=`K^K~z{ry_e5x z6G0TmXV(PNrupI8Rt=&4L{DN5)juFgJrxyF^eRY2ym&11AMoJ8Yjg2v4+WKCK~WEa z7wN@|;6YIYJ(NcC!z7THvER2daWcEJn-n%5c+9@p$$sB^^Jc?ZJNZ+bML^27#g#ub z-lfs{m^;oNR(_E)YL>H(H-OTg-F61gJrH zI>izQH*zR|hUiEjl8-EV9a|L#q5ylYz@e4%941^N(1m%nKonr;3it^hUAxRrzP?5# zraTyX0EnqR<`#B55A(|y;ut&I4f0KR0?>gVY;uP4TX#91opE||Vo4tpg*;1~b%YmA zXaJ!4{r>}h{ABFw2ZsznsM$kY&p0+U&OTp!V(clq((SUAVap)^@p9SqpKdVre#^bq zLDpgA)`9jw6_D`1%Vh1=OY+OF)@d}AJS=-)o3aN|;OYVmtkW)##S`=HgaAT1-)_9H zg2bh+^?W+dAJr;sy;<{Je0tVhDYrqA-Y(JTTq@G2vbAwAFl$g8OYuADY;XXkPM4Lb zPA$=>a_pQNX;=^l;ASdg?g5C)ZdVQXWi9(ct{D{H0HnCwdlfYZ+`lkKE{nzAP=gMO zu>#Jn4vrl%li5l9vP5(4h0tS&%wT#DKz%RZWLW#|)3xl8L9lDPF9RL*0muvwUR<2- zl^fN;8jLE~5`8WVsz5v7U7()%+>w5P&ZiRj(%!yv=e{&=haN+KytJIyznb#g|{^<>%&08Y@$ n2+d+56Y?1z5BS7L**5zJ0^e#KMBw?P00000NkvXXu0mjfC*5vW literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelCubes.png b/Pictures/Default/PixelCubes.png new file mode 100644 index 0000000000000000000000000000000000000000..4080f4e0c46b2bc08bf8b5d844dc390035f25b95 GIT binary patch literal 761 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0**;UK~z{r#g|WO z6G0fpXGf(rX_K^4DK#L1g;p;;2vNa{M=w%A3Ly z**fb}r^M6dmK+>34@=`w121-eI;xuqck-p6;`fSUtfx*{h=*TsSR*iymH1+#8EYbb zrxIgi$7TV&1@zDum^7D3iclr5NPKa8DRqud(0+;SStvz&18$Q zX##rz+Ptlf0|g#_@)f=2-LC2=%*@&Bwm<2$;YvUk5&H^I<}~6n)02M3<5=UfbGuw* z)yk0PzTi)KEykF~@BXCEVbw-}INQ3!hHt2e5VggZsuu+!$h2BPC1`PwdK2yyvl5gz z7>I%Tr?0Bli#9=t1KxC9))BFXU|+O}zSglOa|%yOE%XHBkS)#MoFZ5^~-{XN4BR6d%65RlQzN1=4`d?&HNTk?7uX zWdMlBWvIo?%gTf_fCp<48}Hxv?RvS(rYp=EROTjD18KzvLBs&WXP#YWXD=*R!xX2= zYJ)mee8;;C{wJ~me~i0eFIlDK(cF3KWrgI)O_+u>mlY+hk^cq#aBd^ndy+Wls{#<$ z4?fd4B;(rfiJrh*oVb4N&hzm}vD$92l}<}8)~A4?es?J`t2A6aIwG#*M(hUU3J-Hb z>i0beaS#}IQaUbbowl6RCb9Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0mMl}K~z{r#g|V? z!$1_qCj;W2S{p@Nlx_si-~qgVAc8k=t-BsV(6uLU<n!FAUjB0_d*7k^JVzODAJoWd@&G>EBSv13Rr*7c(^F6VL zt#IB+i;7?LwpFQ4ZHt4dMqwaUJi9ce8unC>k`|`GEsKOEu^1E3g!ZfgQ@bK1Ktx|B zY_*V&F#+_v#0jYh=py`^)j=Xo#8g6LAV!>!nh;l@EtYR!oMq}eP^sAR6QOa?u297-ayg{SuK|gP!~7bA3&tT_xST`tA`F?J zvbu0N52%8F7m#yi?%2|Dxd46xxEuT+S3<6|TrNPf0iSp?1KWz>4M@bf`5vj~S}uT| zH$DX1?IceRqMbk96|eb}y2k3Unf`~PsXx>1Oq xb++mT7D-_M9a@zfzOC8|{0(36%t%*j^#|1iDtCfz@&5n-002ovPDHLkV1hz#^Oyht literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelFreeUpgradeImprovement2.png b/Pictures/Default/PixelFreeUpgradeImprovement2.png new file mode 100644 index 0000000000000000000000000000000000000000..b8df10430ed6b358e7328234653a670331a56030 GIT binary patch literal 624 zcmV-$0+0QPP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0tHD#K~z{ry_da8 z13?hS_ZCD=%!eX^As~X!-~(9N2qM^6TWjY-2wM9DR)USCja{(z1+*0ni7_JNy#Km$ zZ1!e9PLup#xV_oAng7o1Wl8ed-b%$3s7a|uJiTj$vla=)u$inLP zMIv6ZD;_8do`aciz6`3%?|~Q*+gS|E1kb@tIG=%g6NW@kTTM8h2Xw*z6_9e~-Lb9Z zd;$Cduo@)fTFAAQ^967V@D+E{*4Jow0Wrn7_uUcC1z!N!%YF>Th+R2i$Oz6C;(E1} z?ky~pQauR{7HcVL`!}J+b<)|Ur*b%-jXDd;g2d)2NETDjCaMEwaw@JSEMnupx7HdZ z08nyYQV<&l_|wnatX^X6LmFdV3x+hLzoZLi3e+>YZqL0{c&W$9PI-Dh7- zfcvjOuyy}oXTFk)Kdjb^0%l1r05`NNIeedLBk(tT&a)S5Qi>mtZioPnoPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0yarRK~z{ry_e5Q z12GWBvk~!6TU$j0OD{^F!J8l+MG-_0U%<28dNHBDxdtXh9Cba#@?eEBxJ*+!4Gx?p{v#JM`6X^U9?M%UFDanO2_C;!cEWx^J4 z`1%~F!@jUpsHBc>m&aL;PyH?qm^D%XuHx~Iu+|CW%ur1!R1VN zi1GQ}u=*s|snblPfR0*`E>Hv(XZNZ>qrR|`IulYH;338P0n~*Ex&;8vN;+|rI9*c> zirIl>c5`(mokF)%lan9;rllw%ZhQw8S6!@ilSQxtCQ!f()s%}L3-~K|D~?&$Kpxuh7$a{^gIlv-W08Eu;ex!tb>{nl$|Yc3dJTk#m`nOV=)iRl zI#f<0dlC9XpshMo&H=dKehN@IaqmcLshkJ50GJI7NLff(OXWOd3vdso6(2T8YBQf5n06%6cMt6(z{^> zI4FDx-AnmbUX6owEIG;HfQ7--0Vj=fluAiXz@$H#oLQ)050D< zUh96t;?QU+exopE3;0h`0dRt=lEU?>tdE00000NkvXX Hu0mjfM;s=B literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelObtainium.png b/Pictures/Default/PixelObtainium.png new file mode 100644 index 0000000000000000000000000000000000000000..efb8ffcf321e64706dd9ddef71a76eafbf7bc1af GIT binary patch literal 529 zcmV+s0`C2ZP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0j5brK~z{ry_Y{r z#4s3#lYl6m=hYKL#6`G8KZQ68j(!7YadPtui0G)B;NmVWI=DDGxSWfhKse6h)Dwh8 ze`yojYtz4P?tzy!S)O0sCN1T?)sAEiXbKVDr8AViy7KPInmir!)nL*bdhKL@i_do+ z-a28g;hB!_w-#8ePp;))++hMtLavFrvUf^7&}v;)RDiE=M-n2BE+x~2v6@XmxRO6T zGj@N+)HN*xyeR5NVC4O`U;mmhCxbyY^R;Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0sKisK~z{ry_dgB z!$25@F9&LAt*s7<#YO4hqDx)6iMWfCgOiImDlYyJijLy$>>xNfxOK6Mf}@iZ9Hf?N zEfsS1{mjLrO)i&s?E^}K+A#rJcQ%vYyDhlAb>S3oly_WzzU-YoS@@gv0b4nsqqt{8v>TF#7A zK;fXZ)G;c-b;4_>W$LuoOLQ~=a?zrOfWl{sixh6ZR-DV`Pzfl*O$|esfHEBO0GN;n z5)k)?C1u(9Oxc(OZ`d|#i{Rg;AUmi6*2+nhRqr0CHLjjn`f=3x=#O3r zXQjlJ;30QU5@>~kiYwBKR{}#8M?&VRRspt4Y7nWtbc{;?m4KIlNT3S30w7WX1W3ph zNE`v6l#qBO(6Fq#1WLpe06qznJ_tzUHW%3B-Zm?(E{94a5df}4{roai0)*`)65i}? z1__CjkoyOgF}~ZS?@td^;5%d|)W9dS2l002ovPDHLkV1g?# B2zdYi literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelPixelGeneration.png b/Pictures/Default/PixelPixelGeneration.png new file mode 100644 index 0000000000000000000000000000000000000000..0e8992bb702ab5eeb503010f9a508e57b91fa3fc GIT binary patch literal 802 zcmV+-1Ks?IP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGiy#N3Xy#Yu2kgWg!0=G#-K~z{ry_dgh z6hRcnXBI=k<=1(Fs0iUCij|%JKx{+{H6Uq38?h15N&*23Aqc@jkrax}iJcO)FxVu8 zDYZ%=qK84SHD1iQ*$}vOzK?m!?%vMq?2^j|=4RgB?0moTZgzG~{ysV$iXJfRdAgO& zX4s)xemPPPA8q`hV6U03*18Qm``41X*%NLIR-=sH8Qm`udFr(|NNYqH$P;f|KWSVm zKi9W)E6KfuHRG7b1Tv6ofQ3yWOtaM|#;ZG2Gl)T!5jH?Sfv;C&8dq_^VyL+=S0_#w zv*($_cZ;!FziuUgE{gSGz4rVor4EB|aUtG+=|@MrSpH^Q3-a^fFzTm7hn*08oD2HnKGn_yn$WiImm1S7@^HD& z+vs#eK$A-nDs+=L+b5-(m5!3A_er9lANuRBjX>Ke0}PvhNO1_p=7`kVI@voPW!;;dUJ0}Pu0Y^3PSnNkJ-n>g^RSy~)fFdC2w-OL1!nG&To zYQz*2q*Mmt;#iEJtck(~;^II)d8}LIOcXMZ76<$oGDS^zn`$#~Axj)!5vD0(f-+Dr zYZ#nr-iYEGQV}qDr=P$j_1KW&*Icte?*bcqD&kpU_NVK|qaBdp4T<})nfsG>ST^JY&&sBzmd{{jg zt^__^G?@UlldTEUSrFo=BLjPx#1ZP1_K>z@;j|==^1poj532;bRa{vGiy#N3Xy#Yu2kgWg!0>w#0K~z{ry_dgh z6hRcnXBI=k<=1(Fs0iUCij|%JKx{+{H6Uq38?h15N&*23Aqc@jkrax}iJcO)FxVu8 zDYZ%=qK84SHD1iQ*$}vKzmIv#?%vGY?2*d{=4RgB?0moTZgzG~{ysXcL=PAa0^KsR zsajOaFGs5C(Z(MN_L}K(rQN`@e+{XdJ>kY+Im!5)(fuNmr(TPLyhf6NPU5xeC#`Gc z=lZs8Wx2PoW*rlmKn6M*U}2jGQ*ZQ%@$wGU3}Rq1!UpIk2=$80<0}qW3^f<#>ck0a z_5z#uZZTHr*R3qjMR7i?*Pef+)L{@VKBW6E{b-37%ipYPL4H0wMr+_@_}AL$?b0i? zFgv3oeo{?Sd`kR5mQhQqX9j6LSM>|7RO=)-I}mwz(!ge$S03=t2+~g4CKWDKZZhWX; zWOzg3er)FcWYuZHnE@7$KE9^SCJhUMycvN0xDS|)WSpFR^x1*c`MW~IC92JdfjGwC z$O6M=R%#EZ2CGxYsK%+N-Y{nw*_Tf%hty)&6z`&D`x1}IAIJHCdg|sJ)oI9RO#0|% zJCa=(7*gj-Lqa|*A5<$*NEdA;fa_#y!*&*gIO@c};#QNs0L$B<)x>Tv(O*g?GBr5T uZeTA-3?OhlvaUyUw8P(U*IRlx2*iI%)v1>npK`7M0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGiy#N3Xy#Yu2kgWg!0>DW`K~z{ry_dgh z6hRcnXBI=k<=1(Fs0iUCij|%JKx{+{H6Uq38?h15N&*23Aqc@jkrax}iJcO)FxVu8 zDYZ%=qK84SHD1iQ*$}vKzmIv#?%vGY?2*d{=4RgB?0moTZgzG~{ysXcL=PAa0^KsR zsajOaFGs5C(Z(MN_L}K(rQN`@e+{XdJ>kY+Im!5)(fuNmr(TPLyhf6NPU5xeC#`Gc z=lZs8Wx2PoW*rlmKn6M*U}2jGQ*ZQ%@$wGU3}Rq1!UpIk2=$80<0}qW3^f<#>ck0a z_5z#uZZTHr*R3qjMR7i?*Pef+)L{@VKBW6E{b-37%ipYPL4H0wMr+_@_}AL$?b0i? zFgv3oeaiiEulZ(y-UTlBRK&By>`zyZCp#d+8xr?p zGxsN}P7}@yuz2+GHElL&SPpG%?83m1 zI#(JJ@?rU)T8TosXfpv^CtDk~vmnG#Ck7U`n)C%&-VUuMc7uujQZkXL!I5?Ydr4vd pf$NcVJ*uM}{)W5W(!)U@{sU^&sh1WfbSVG;002ovPDHLkV1iKdXQ==H literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelPixelLuck.png b/Pictures/Default/PixelPixelLuck.png new file mode 100644 index 0000000000000000000000000000000000000000..03f421a6c6eb06f0f5c1786503616b148ce7d97a GIT binary patch literal 576 zcmV-G0>AxPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0o6%FK~z{r#aBU2 z!!QtZj3TO*(87UAh)X11!Us6=1I}>c5lC?6Av}d^&pjZB0wq#J0%PLJb?r^oY0F4f zlQxr??9MuB^m=w)i!C6LvN>`iuPgN#y_}}?WA>&_c8$Bq@w$Ph&-bV~+zPHolV!zk z#z$hMPF(Towyv?7(@wB8mIgw^XW2|(^)W#w#RDxqU(D4CF`=OhESf}ifhk^m7a}k7 zUM6H8@vz`hB0&bfSN3(T8PWc1UOiLQLW zn*n_jN*tl`1+$H>A@kqOzy}a1aU`3X4jyPGg9Bc88WSPnrk1Jz{wQKy z><`%{xZ=>zdO&nPIjNt&KGeysaWy*pGk_CnGonUy-10X(CJK~DDSiMb`2A(r=#Aq5 O0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz18Ye{K~z{ry_e5R zR8bVi?|V3Dj-!*Lg}7+UMbx687PD4YL9`JhvOpI?WMo9qU(lk0j3m&7EgYzzO^bxY z+_W)Js72<&w5@^FIR2QLoZEcQ-1EG?ci){U&<`Bu-gkd|&pG$p=hInfZk1veh`Fw6 znaRjJ{W^0^2|1YlL7lzkPP{(oz{vVfM>ThazG&Rb_(0tOu_I5rEe`w|o&)}Y{0+II zHsq?1x~az=wsHSnx|Xq0OyZ6G9YQx%81_o3s!RF{~p7!j%U+ah{Oj9y4k4KNTtT6or*N~dbr9D#GGnLZ%GNt_-V| znUWcpo_R#SHu2G=Q>s;j=kQt^Zl>@u@Po6$nY9eIh~%F>k$QVAAilM{xD!PJkDSx9Haf&#^_V;|$jy zmg5_1;#GFdo6Mh2{1t<1S=--+rpM~gl=pUonEuWHx&!|G0Ip$YG$sTbIA2v0I0Msn zq2C&woRbZgI|9#PY8her9)#xegH1B@2>jo0e3l&5%~V67%r|Ka=;J(x3Hu%l{cC6g z(LtPFPUW6;7|w%uqkNa$ppIS#HuMz#k2oLs+3K2N2Jnv}tgW&-a8@S5Qe6(vU_C$? z7~fo@&R)|MEkpnZ&@sJ?7!*qwbtV1{kC^L^h`Fx#3;Z)alqvWNbpQYW07*qoM6N<$ Ef|9P!PXGV_ literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelPixelLuckConverter2.png b/Pictures/Default/PixelPixelLuckConverter2.png new file mode 100644 index 0000000000000000000000000000000000000000..e06876055202367ee879f45be5c9ade90d35b1e4 GIT binary patch literal 982 zcmV;{11bE8P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz18Ye{K~z{ry_e5R zR8bVi?|V3Dj-!*Lg}7+UMbx687PD4YL9`JhvOpI?WMo9qU(lk0j3m&7EgYzzO^bxY z+_W)Js72<&w5@^FIR2QLoZEcQ-1EG?ci){U&<`Bu-gkd|&pG$p=hInfZk1veh`Fw6 znaRjJ{W^0^2|1YlL7lzkPP{(oz{vVfM>ThazG&Rb_(0tOu_I5rEe`w|o&)}Y{0+II zHsq?1x~az=wsHSnx|Xq0OyZ6G9YQx%81_o3s!RF{~p7!j%U+ah{Oj9y4k4KNTtT6or*N~dbr9D#GGnLZ%GNt_-V| znUWcpo_R#SHu2G=Q>s;j=kQt^Zl>@u@Po6$nY9eIh~%F>k$QVAAilM{xD!PJkDSx9Haf&#^_V;|$jy zmg5_1;#GFdo6Mh2{1t<1S=--+rpM~gl=pUonEuWHx&!|G0Ip$YG$sTbIA2v0I0Msn zq2C&woRbZgI|9#PY8her9)#xegH1B@2>jo0e3l&5%~V67%r|Ka=;J(x3Hu%l{cC6g z(LtPFPUW6;7|w%uqkNa$ppIS#HuMz#k2oLs+3K2N2Jnv}tgW&-a8@S5Qe6(vU_C$? z7~fo@&R)|MEkpnZ&@sJ?7!*qwbtV1{kC^L^h`Fx#3;Z)alqvWNbpQYW07*qoM6N<$ Ef|9P!PXGV_ literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelQuarks.png b/Pictures/Default/PixelQuarks.png new file mode 100644 index 0000000000000000000000000000000000000000..ade3b8857a063d769d42ab51540799aabdb2e200 GIT binary patch literal 744 zcmVP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0)0tDK~z{ry_d~v z6Hye!-#lz$l1`I0Vx@HB*FuEuyA@o!upr{zZoBLs;iB8R7gsLabmJf3Rs`)rDhN_2 z7-~$Kv{5ql+|GTxOy0+hIQ_w8zB2Eecix>Dl5|$@WU2&Gt@AxMy=+X|kGh|?pcccIk zIvixmReT*gQnXNfLfFSFMxcw5EWwoUt5JvQ!~QoaK4uC=g2W7vIKx5@hc&7n_u6#+ z{z0F%E+gjzO^BP&7G{n{XU4>@?;~@~HW4Faz|7t^plt@cs|}4wz9*J~?vBUmGz+Fg zU{DCy#k{Xp)ayn)KavA&UjkFJf79tw%)7@|r~pi08C>Gh6traaXtMRQ5!KU^0i9zb zY-V%u4{fEeZnO!x!_jQ0ySGxW821E{`Pdwrdqaqx0th4OwXUY}0a4U)rK+y&$DahG z5H;}W_B@H&vvYx^`0}+!!Yqz^V~7$cVy`CWJ>_M`-bR*jv^wrzbe&~l35x<^e zSf;&WZq(9jqmhc65Cc&f#YAkZ>-2l<_~2!q^(mMzQY^lX9SNbYVGI^3*36j4@X^(I z*#iFuY%NLve-u#Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0p>|WK~z{r#h1NK z!!Q(uogf6Xq$%Z3RFx1vFTudV3$P%uFu(vaV;_Nmff*JC28PbO07xv%Ou#~=3L&5& zv_&9lI3_nrTQ`lZCjF$V*j3bXeDAfb7%zoo&SJnaO>ZQ}?CxTkxoss~;K;7%eL15g>&5I^HtG~CD z;DAkQZO2B59H3;K6vsi& z+b{`C*Xw~KcS2B0WB?zEh_#Va>?WW=dcZi$&hU%IhnOVIW;*k402As;8DU%1?(rEu fY;->uEz@MbY@{T{tRS{E00000NkvXXu0mjfgHZBY literal 0 HcmV?d00001 diff --git a/Pictures/Default/PixelTutorial.png b/Pictures/Default/PixelTutorial.png new file mode 100644 index 0000000000000000000000000000000000000000..f36eb7c596908284740a4c99ca3a72b5c041bcb0 GIT binary patch literal 627 zcmV-(0*w8MP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0tiV&K~z{ry_d^M z!$25?Cj(;X#onNZ)P&%;zQf1n} zxw1Y(AA)#meTTK11&h@p+HZYU!-&cRH$W|SJE%~JgGRl`3Jj~J z1iC2F&B~+K5%+`fIwpYpw3q`z197A0=w?AH1C`fjR?>j>$75nUVv{<;++c95DhtpK z&A_bbj{=oN@8@H6(`_XK*Hx|o2@JXTQ+sz?auBh<=we({mYt3@B-i$E$|1iKaF|2|kpofm`}lktjeIh*A#&d)d6&07rDCico!&dIru)HRs;`yLMG3k^N zUCbuG9|J&x>j9R5&i9aY=FLHFvIt=S9obPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0~bj|K~z{ry_Y>` z6j2bz->#91_ic)xa&ia?7J_BKPHp50twbam(Za^U6oP^lDMSdQh=qj~il?cp6ueS9 zAz~8|@uL#$BzTv*Z0-hn&Axs6aZ2t7%e?pQz5UOdH?zBEtycECY6~dXHnq&O z-9B3DrIQATf*gB*^l^aX{QRrDM@@~`Ojl&Mv^oqqyZ6- zUL_GHkj6m)&W z?d>O1XlEXd*X4TMp>x?HMj$c=U;!*-aTaD|pT!yILsWRZE-pz-LR}no&bybu&UyC$ zJ3-w@hN=Q^gfATsyU0Lb7fs2Y7-We!Qml;vAC`APzL=U;9TO zj{$x&RYPJDa`@p2aODLxl-e>sP(De8t zfO8Lpp1F6D8cJ;}y`feRI0DFnI6@A{3XtMhf|PuIG74aq03@Rnm3d&QuCccFFkobv zcx~077myDffhj5=)SRb|3O<(OUQ8H)-&B*PGT{o)MKL0T9%ilpxqC)xz~&=!04Bow zo`vu^AVj4@QV5)3hrr6+o4|KL9PET1g{TPd&RLv>BeCvJ>~b4UM?LR$Qhksx{58br zuim5&l2hY(_iVmscEGd%#;BPJ(|S1u4%D)FrN9B`(0C$ojtt`@Xo9xQWjKrz|BKYJ z7Rr-uW1~Y|?<2G4r20JnSB_<}zWAA(mjk*3qr`UrI{Yv)5m&0Egumh22k)H_1>07C Y0p~FFp;yMMO8@`>07*qoM6N<$g825BF#rGn literal 0 HcmV?d00001 diff --git a/Pictures/Default/SingularityPixelLuck.png b/Pictures/Default/SingularityPixelLuck.png new file mode 100644 index 0000000000000000000000000000000000000000..573534a1f5b20fe1715cef9e6d89b582640e7718 GIT binary patch literal 851 zcmV-Z1FZasP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940_aIZK~z{ry;s3< z(=ZTS%XVTrjgy|jg+t-Ufv?~z_zJ#+kKxA0&>2o-hG8a634yc~@2%ycIEi9;Xy43c zWykA%)~;5oL_S$7=aB3~%pYio+5VIC7i5F+Pfz=DBa*G0tlc&BEric+Ln!JN9lCr1`u#cMm(sO+JuBDfQ40{2!Du!>`dI(?J5b;U3J#B)OVh$)Z|F zkrw*(oP}vV)qDJp&$!3Wppr}c8m(|FGCk2HG0ZuTT*#&7K!UP#I0*{I^H@xM5+UcO z>=o%$=1@k`;{<5Pq&k&YEs2oxkiDd}Ora106lhi^53MmXJCxmY9C9AC&uW=KfdF<4 zZVnE<@sM@i+diAgM00=y+zfP$W7m0f;O?*B^JBRqwGfr z0d2H%@n)d=lGt_L+nynSY6!4%@!-ECUEu39yelk^}8aLe7~~rxNp= zJy$_Ppc4WgGz>XsW`|bCDSO3eDg{(C1Dz0r;5#2uCmw;^7=xOT9IbLs0$t~^bz%?c zM8;4E0eW_?5x-`!aiD>jkuudIFZrP&eDnCPM52|>qhDDpXj zvmY<4ef_QJif~#{VULKu9fv0f>lL;Q^l)O(!=RB+K`oaIO%*m39aA{g|L`0ogB=CA z(#CubN?=u6c10PQQy!Hn2pa_+8YpuJUaJixPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940{uxuK~z{ry;n<) z(?Ad{{}S8z&MItJ3@ll23QoZ(I0=VgH-}*)RzyNbnG7M2nQ7iDw?oIVJ8nxePpXvN zak-wWs=KQr`C^P*LUa&`|3X9J{eMY*Lw30SJXHQz0T%%my{4wrW7L%Tx!R83^KE=iAo_^0XM|aasXt=0Mi8pu3Zc%QJ{d!? zx4jUp;e%0l5Xs^FNWgWDm>gk;&Opbvn_Hm-lemX35GY&%E+PwidxqNidbd^?LV`6l zg@;xG_TyV$=sMp&?qz$}4kKX_nRgK&Y!FVO&~$!yI!G3014$Gz?@9q-gAf+hAQZB| zZ>)<<1NP$;c1RI_j-uj-zY7#!@K6^>#GJ`@2ut0NV za!?zyvVGM}$3Ev?`*bc7C=kGo!Og+KH6Ak0d)ucAnP?4=fQ>-YICP!|*=GwWafKSd zzRYd%rI9VqQ&1OHJ;g%jd64}GDWHvZE=~lRFA1IJz3rI-sEPnP7YFW3e9oEAwwmZ= zKbm7PCIR+wEj3WT#OItv)m506>^Tc60*w^7prOw>E890ay6hFBndDGa1R5#u!F4`l zoj3xuF$T3*GPKG)2{fIDt`jFnCNhRX3edAVE8&YFEoB51>!G1%1ei}26)StlI&p%e zkPHeDKnemP&?GU)IT14f8UY-Y0+(W!#31JoUmm)VQoc(-d%-io(SA^4w3VTHK?KnI^xL#q~Ko2J|dKfek zDp<=UMN@@MMXxEm*8lJvC50UYwNmH&1WI5tH|&a1G^ac&l@K-xJTy?25WH3!NXiua yK}C1668F@U0^{6V3XJ8r&Y?NYD6IB&i2MU2c1fp(jPK_F0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940ftFLK~z{r?UqkU z!$1^=ry__T;-cb4g)VgC1w2IV;~8?F9Ks89ql<#N5xWo(L=bC!m2%46H?>4oqfYqa5!JLfdsRy$8z6jI z9n>pr#|QZE`8Ug5T`>TbJ%0D1VBeZKpPIS1pt%y@4sXLCP7Db-yxHOS^&fnz#0xr n0w72LYxrOwfs1ap7;x?f)LTMp4{f!l00000NkvXXu0mjfl48%h literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach414.png b/Pictures/Default/ach414.png new file mode 100644 index 0000000000000000000000000000000000000000..7319b2a194ee567c98a336c6616029806c0930f5 GIT binary patch literal 558 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 literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach422.png b/Pictures/Default/ach422.png new file mode 100644 index 0000000000000000000000000000000000000000..94e80854e03f2dd0a7a37a857957fbb179040741 GIT binary patch literal 550 zcmV+>0@?kEP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0lP^=K~z{r#g{!! z#4r$ro$ZmRS6l$Z9VjU{0BNWZ1yBK-69h!XQXp!YZ~zJ_ghWL_g~SCAH76kCO+1kk zInIo;Qa;I>T_^T?^Ak&(l*f;ynUX0DKznAtPe!zX^82QAhn-dvWdMTN=Dl%8vBY% zS<=0~=u(JQxzPh(^dP1bYTMmN(|jj7dN8=sSNjm!EU2tEU0Mx14uo0KZ##{8gp_n%1Ez)VETnf${^m^ZMr7 zbB}1E2fYT8jngFmIyBkcy0`A!XdF59hm oK)e2!2xv#W1*>G@zvssM0|O>blwA)BT>t<807*qoM6N<$f=4&%)c^nh literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach423.png b/Pictures/Default/ach423.png new file mode 100644 index 0000000000000000000000000000000000000000..94e80854e03f2dd0a7a37a857957fbb179040741 GIT binary patch literal 550 zcmV+>0@?kEP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0lP^=K~z{r#g{!! z#4r$ro$ZmRS6l$Z9VjU{0BNWZ1yBK-69h!XQXp!YZ~zJ_ghWL_g~SCAH76kCO+1kk zInIo;Qa;I>T_^T?^Ak&(l*f;ynUX0DKznAtPe!zX^82QAhn-dvWdMTN=Dl%8vBY% zS<=0~=u(JQxzPh(^dP1bYTMmN(|jj7dN8=sSNjm!EU2tEU0Mx14uo0KZ##{8gp_n%1Ez)VETnf${^m^ZMr7 zbB}1E2fYT8jngFmIyBkcy0`A!XdF59hm oK)e2!2xv#W1*>G@zvssM0|O>blwA)BT>t<807*qoM6N<$f=4&%)c^nh literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach424.png b/Pictures/Default/ach424.png new file mode 100644 index 0000000000000000000000000000000000000000..94e80854e03f2dd0a7a37a857957fbb179040741 GIT binary patch literal 550 zcmV+>0@?kEP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0lP^=K~z{r#g{!! z#4r$ro$ZmRS6l$Z9VjU{0BNWZ1yBK-69h!XQXp!YZ~zJ_ghWL_g~SCAH76kCO+1kk zInIo;Qa;I>T_^T?^Ak&(l*f;ynUX0DKznAtPe!zX^82QAhn-dvWdMTN=Dl%8vBY% zS<=0~=u(JQxzPh(^dP1bYTMmN(|jj7dN8=sSNjm!EU2tEU0Mx14uo0KZ##{8gp_n%1Ez)VETnf${^m^ZMr7 zbB}1E2fYT8jngFmIyBkcy0`A!XdF59hm oK)e2!2xv#W1*>G@zvssM0|O>blwA)BT>t<807*qoM6N<$f=4&%)c^nh literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach425.png b/Pictures/Default/ach425.png new file mode 100644 index 0000000000000000000000000000000000000000..94e80854e03f2dd0a7a37a857957fbb179040741 GIT binary patch literal 550 zcmV+>0@?kEP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0lP^=K~z{r#g{!! z#4r$ro$ZmRS6l$Z9VjU{0BNWZ1yBK-69h!XQXp!YZ~zJ_ghWL_g~SCAH76kCO+1kk zInIo;Qa;I>T_^T?^Ak&(l*f;ynUX0DKznAtPe!zX^82QAhn-dvWdMTN=Dl%8vBY% zS<=0~=u(JQxzPh(^dP1bYTMmN(|jj7dN8=sSNjm!EU2tEU0Mx14uo0KZ##{8gp_n%1Ez)VETnf${^m^ZMr7 zbB}1E2fYT8jngFmIyBkcy0`A!XdF59hm oK)e2!2xv#W1*>G@zvssM0|O>blwA)BT>t<807*qoM6N<$f=4&%)c^nh literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach426.png b/Pictures/Default/ach426.png new file mode 100644 index 0000000000000000000000000000000000000000..94e80854e03f2dd0a7a37a857957fbb179040741 GIT binary patch literal 550 zcmV+>0@?kEP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0lP^=K~z{r#g{!! z#4r$ro$ZmRS6l$Z9VjU{0BNWZ1yBK-69h!XQXp!YZ~zJ_ghWL_g~SCAH76kCO+1kk zInIo;Qa;I>T_^T?^Ak&(l*f;ynUX0DKznAtPe!zX^82QAhn-dvWdMTN=Dl%8vBY% zS<=0~=u(JQxzPh(^dP1bYTMmN(|jj7dN8=sSNjm!EU2tEU0Mx14uo0KZ##{8gp_n%1Ez)VETnf${^m^ZMr7 zbB}1E2fYT8jngFmIyBkcy0`A!XdF59hm oK)e2!2xv#W1*>G@zvssM0|O>blwA)BT>t<807*qoM6N<$f=4&%)c^nh literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach427.png b/Pictures/Default/ach427.png new file mode 100644 index 0000000000000000000000000000000000000000..94e80854e03f2dd0a7a37a857957fbb179040741 GIT binary patch literal 550 zcmV+>0@?kEP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0lP^=K~z{r#g{!! z#4r$ro$ZmRS6l$Z9VjU{0BNWZ1yBK-69h!XQXp!YZ~zJ_ghWL_g~SCAH76kCO+1kk zInIo;Qa;I>T_^T?^Ak&(l*f;ynUX0DKznAtPe!zX^82QAhn-dvWdMTN=Dl%8vBY% zS<=0~=u(JQxzPh(^dP1bYTMmN(|jj7dN8=sSNjm!EU2tEU0Mx14uo0KZ##{8gp_n%1Ez)VETnf${^m^ZMr7 zbB}1E2fYT8jngFmIyBkcy0`A!XdF59hm oK)e2!2xv#W1*>G@zvssM0|O>blwA)BT>t<807*qoM6N<$f=4&%)c^nh literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach428.png b/Pictures/Default/ach428.png new file mode 100644 index 0000000000000000000000000000000000000000..dcc53d2453d17de0f159989c97c1051b47101483 GIT binary patch literal 386 zcmV-|0e$|7P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0T)R`K~z{r?UykQ z!Y~X)Q)bv%kQm@39D-A@atPL*fKN?5{yT0r}0#U9}rHAN+$4UbqPL;>#8q8P4gC9(osIQEz#?GcRx zE07E48jNaGNrDxS!u#7uBF=LX6sjha-aLhp;PA)trrl2p$1MPs@F7wSePx#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0T)R`K~z{r?UykQ z!Y~X)Q)bv%kQm@39D-A@atPL*fKN?5{yT0r}0#U9}rHAN+$4UbqPL;>#8q8P4gC9(osIQEz#?GcRx zE07E48jNaGNrDxS!u#7uBF=LX6sjha-aLhp;PA)trrl2p$1MPs@F7wSePx#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0T)R`K~z{r?UykQ z!Y~X)Q)bv%kQm@39D-A@atPL*fKN?5{yT0r}0#U9}rHAN+$4UbqPL;>#8q8P4gC9(osIQEz#?GcRx zE07E48jNaGNrDxS!u#7uBF=LX6sjha-aLhp;PA)trrl2p$1MPs@F7wSe!lvI6;>1s;*b3=DjGL736~_k^`T4XK_kjv*25$$#eW{$zjHp{cQi;Y6OAM)iRM zE12D64PG%6I3BUEoFjPZICoiCYw{Gy-RJHmy|`OAPvh?kh8%N4zJ^GiO+4}nR~21E zT@+3`iV1I$Vfm$$^H025Vp7PaN2LsBiUcNzJzz^NY0&xi<#4!xZ=$n=;#kc*LA23{G5o_~ z<^YcaSMqoMV9+{spdjVGoI&iCM;vXI5_}9tfB$S>ztD!`fasYU44aN7YE)z> zV)61jIFr}$W4eYu*Hb|@h3>6Wmq=P&muLO#SjCy@J?Ex?NV>xHW+x^wDFyC=#DG1` zHN2Z-QVQJ@xh|$MT@zqX6%*j)vYOy{WXZGI>+>7VHoV+gSd?hsovk3jB*4VmAf%{S zDJd(kT7Eh63s#4+$GROa7(pS|5XjzRmC&&JIS&uRBi{?Vvt}HA1&jp-Pgg&ebxsLQ E0NM?#s{jB1 literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach432.png b/Pictures/Default/ach432.png new file mode 100644 index 0000000000000000000000000000000000000000..02b5e637cba14d8716fb58c5ae3c57bc48841a88 GIT binary patch literal 464 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjGL736~_k^`T4XK_kjv*25$$#eW{$zjHp{cQi;Y6OAM)iRM zE12D64PG%6I3BUEoFjPZICoiCYw{Gy-RJHmy|`OAPvh?kh8%N4zJ^GiO+4}nR~21E zT@+3`iV1I$Vfm$$^H025Vp7PaN2LsBiUcNzJzz^NY0&xi<#4!xZ=$n=;#kc*LA23{G5o_~ z<^YcaSMqoMV9+{spdjVGoI&iCM;vXI5_}9tfB$S>ztD!`fasYU44aN7YE)z> zV)61jIFr}$W4eYu*Hb|@h3>6Wmq=P&muLO#SjCy@J?Ex?NV>xHW+x^wDFyC=#DG1` zHN2Z-QVQJ@xh|$MT@zqX6%*j)vYOy{WXZGI>+>7VHoV+gSd?hsovk3jB*4VmAf%{S zDJd(kT7Eh63s#4+$GROa7(pS|5XjzRmC&&JIS&uRBi{?Vvt}HA1&jp-Pgg&ebxsLQ E0NM?#s{jB1 literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach433.png b/Pictures/Default/ach433.png new file mode 100644 index 0000000000000000000000000000000000000000..02b5e637cba14d8716fb58c5ae3c57bc48841a88 GIT binary patch literal 464 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjGL736~_k^`T4XK_kjv*25$$#eW{$zjHp{cQi;Y6OAM)iRM zE12D64PG%6I3BUEoFjPZICoiCYw{Gy-RJHmy|`OAPvh?kh8%N4zJ^GiO+4}nR~21E zT@+3`iV1I$Vfm$$^H025Vp7PaN2LsBiUcNzJzz^NY0&xi<#4!xZ=$n=;#kc*LA23{G5o_~ z<^YcaSMqoMV9+{spdjVGoI&iCM;vXI5_}9tfB$S>ztD!`fasYU44aN7YE)z> zV)61jIFr}$W4eYu*Hb|@h3>6Wmq=P&muLO#SjCy@J?Ex?NV>xHW+x^wDFyC=#DG1` zHN2Z-QVQJ@xh|$MT@zqX6%*j)vYOy{WXZGI>+>7VHoV+gSd?hsovk3jB*4VmAf%{S zDJd(kT7Eh63s#4+$GROa7(pS|5XjzRmC&&JIS&uRBi{?Vvt}HA1&jp-Pgg&ebxsLQ E0NM?#s{jB1 literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach434.png b/Pictures/Default/ach434.png new file mode 100644 index 0000000000000000000000000000000000000000..bf3bf6dd5ba28bd3f0500bc474140a1650dc8579 GIT binary patch literal 482 zcmV<80UiE{P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGiyZ`_WyaAQGa!CLH0e4A6K~z{r?U%7i z1TheXXDvjm?WDy|7Vh7w`q?qTB=D+1JIuH@74JK2Hw`zTW)?RL7Fogki>Fx=r2D% zHNKmmGQb=2X5of$AH?x~I7`t0Ho-F|6q1`Si38C3~bI18e|Qw?;q)MYv|s0Zf{&Qj+a(V z=MT(x03s0P%x4h?Sp(XeJgYbmE0DXr7=uBylDKsH8PgHO8)`F`D%xp)7eSO;I9@^< zZ>oS*T!UyJ77QzqBc9h7R$am_BXRT74sEs6M}Q5v`Jn_&OhW%z?w{4@4fF;o|DF^5 Y0B}VHBC0?cHvj+t07*qoM6N<$f&`MtQ~&?~ literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach435.png b/Pictures/Default/ach435.png new file mode 100644 index 0000000000000000000000000000000000000000..bf3bf6dd5ba28bd3f0500bc474140a1650dc8579 GIT binary patch literal 482 zcmV<80UiE{P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGiyZ`_WyaAQGa!CLH0e4A6K~z{r?U%7i z1TheXXDvjm?WDy|7Vh7w`q?qTB=D+1JIuH@74JK2Hw`zTW)?RL7Fogki>Fx=r2D% zHNKmmGQb=2X5of$AH?x~I7`t0Ho-F|6q1`Si38C3~bI18e|Qw?;q)MYv|s0Zf{&Qj+a(V z=MT(x03s0P%x4h?Sp(XeJgYbmE0DXr7=uBylDKsH8PgHO8)`F`D%xp)7eSO;I9@^< zZ>oS*T!UyJ77QzqBc9h7R$am_BXRT74sEs6M}Q5v`Jn_&OhW%z?w{4@4fF;o|DF^5 Y0B}VHBC0?cHvj+t07*qoM6N<$f&`MtQ~&?~ literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach436.png b/Pictures/Default/ach436.png new file mode 100644 index 0000000000000000000000000000000000000000..bf3bf6dd5ba28bd3f0500bc474140a1650dc8579 GIT binary patch literal 482 zcmV<80UiE{P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGiyZ`_WyaAQGa!CLH0e4A6K~z{r?U%7i z1TheXXDvjm?WDy|7Vh7w`q?qTB=D+1JIuH@74JK2Hw`zTW)?RL7Fogki>Fx=r2D% zHNKmmGQb=2X5of$AH?x~I7`t0Ho-F|6q1`Si38C3~bI18e|Qw?;q)MYv|s0Zf{&Qj+a(V z=MT(x03s0P%x4h?Sp(XeJgYbmE0DXr7=uBylDKsH8PgHO8)`F`D%xp)7eSO;I9@^< zZ>oS*T!UyJ77QzqBc9h7R$am_BXRT74sEs6M}Q5v`Jn_&OhW%z?w{4@4fF;o|DF^5 Y0B}VHBC0?cHvj+t07*qoM6N<$f&`MtQ~&?~ literal 0 HcmV?d00001 diff --git a/Pictures/Default/ach437.png b/Pictures/Default/ach437.png new file mode 100644 index 0000000000000000000000000000000000000000..d23166c2ef991a67d8024d4e95fc1641e9371c1d GIT binary patch literal 265 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 YFS+zw!2duQV9sRlboFyt=akR{0MR3~3IG5A diff --git a/Pictures/Legacy/BlueberryLuckDilator.png b/Pictures/Legacy/BlueberryLuckDilator.png new file mode 100644 index 0000000000000000000000000000000000000000..f10ea35bf9fd046abac983f9fbb74f84651a1aee GIT binary patch literal 944 zcmV;h15f;kP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ9414T(hK~z{r#ga>mZTgsR#w3tb;`1DWrQ)ffp&Lh@ilrL!{85L){|qkf*Lnhv?72 zgV{ka!Voev5L(4Dv(&J4+V9(WtpQoxe^g?$y}hU+Nk*Y-?;^(15sL0!R{9)AyBK zbhjaC-1a%T)Md0XOFtHAt8M_Fc&=+ew@RQds=LCDlEwx2uAQDRebCP6y1_QEncefA z#y{lgXv0ZvLr_+V`q`GZ+<$MXhQCDZ`s?=z%Fcibdv&dCr>Lgh&R02o)Izy^&0Mzw z4B-s`lSO=R@s)85LO}r7@*EvRC=h1=B1{kNa_X`2)yWk-T4Hr~!~y{6$La;xVh(~B zzjW1^jkMaq-_+v5H?FwAp3BNzt444LG7fAJgq#;2&<>t~M{TvbwoW_~KvpkfwoOtH zWdXRZAe>17vbyPdoJuH&V@v;sWeIT-akW4+XyB zZ-P+q4hWcF9~?Pw0DF&>3#iX`j!`auK=%}FilTx~9HbWJzVZ)45^yNRM>RG!(Dr7) zTt$t%bf8x?@ror2H#_HOr#eU-{dc$xuzdo2#j}uED_uip03vRS+V`Ajg#{4=Kpm9X z=qk>IyaTSSC_99%HycjlkBqztyyus1P)Ge}RW|^{HG=QJ`VUJ95%&p6U^cj}A%Xz_ z+;I>R@11PYwGv_@b3>$-^K<517O+=*l8fm@ng^dhtq?EF6wGPIUAMFSh{7u{f2?D&Hc*)-oV&hwNoQeSOR!h-c%;D^D zE=WDf_ny;yy-*+~&n{MuV&n4(BHI5}v|?yq8Qf!CHRSqV5DhPzvtVPd z-sSIDWXeRBUH@l8M`ATEznHGA#z1?`B^ zPt=i2f!l9>oe4S;?CnSrcY*ZdJEWG%0|3Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940p3YOK~z{r#gxBJ z!!QuWFAjyOC1UK{2SALKcoYVh8JUnkVqjq99T*Th?|{UJc!16o5^9t-Dhf^LnR9US z$Mrd-{Yg>mHebFk_W8V{^Y09{hzyWE+|YEhh|}A0fcNR0N5g;NuzMv}Tx4B2 zSAuJvUSt_wG_?Xfq&blXa4{c-L%@q0;w`?;y+k~TXlRczAH^eixr9K_dua=7(9LJ_ z8AM6cCP0kO6aw|;qL_Qmxq9hM}I z&ee!_EQ%(1BI3UifSVJt!vn#{4XO{b$yufskC zy17fAQ26se-dO>P=G;C}g-AaZ&4Bvyrjgz>wgUGPiwY~-rB77Bu7P5RCgun`0HTLz zVvghi278aZ;-L^O=EpnFxt9mtQ#RO5X$tWAb>j3Tw&>@00000NkvXXu0mjf{lNda literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d94d5b9ae87a84bec5a20ab19744e8c4256a1376 GIT binary patch literal 1617 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 literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelAmbrosiaGeneration.png b/Pictures/Legacy/PixelAmbrosiaGeneration.png new file mode 100644 index 0000000000000000000000000000000000000000..216e2cd247bc20728eb1de0f4d04c94fab63d0fc GIT binary patch literal 783 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 literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelAmbrosiaLuck2.png b/Pictures/Legacy/PixelAmbrosiaLuck2.png new file mode 100644 index 0000000000000000000000000000000000000000..8f5f049f204e8d77fe2cee37a55a84cc733d7991 GIT binary patch literal 829 zcmV-D1H$}?P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0@6uDK~z{ry_dgh z6hRcnXO{%eoO^rziX=oNk|tnbbzCJ9NM#{nz{WXnPaW>i7Bmez_D#=Mbp$> z^RzyXPwIR1-=;HYZk7*)16XKpSk%mg`C{42_;vT7^5rRSaS+t-0^lFC!2FN{GKf&6 zSOj$=sa>!&jJlzI7EAzts3HMvKGqq8D$ZF2V`15+X{oWLI73MYWr4+RO*f3OFxvB@ zYng(8E-dn}QWAWQr1)KT%oq!!{m`1o90Z810YF1Oe!5?&r95Fqw$l=sfkBcO08+_D zLm`GI3)J$HW-YLmjvd$c8yo7`X498)EX4bid}uD4cU-6zY2+VUs~xrdecPKO!PxYR zuFwDFk&?dRxN3;{K3E(@Cf|8w#qaptn^)#}X7-$U0<61M{YX8fj@D18N)3g%tb;*- zp-$k)OK}vLQm`I{YVX-uY5TIkyJz9YiY5YA?fBX`9f2TN_rHn|;@JK3x2KG~|FUGn zA?y=RK_~!3h^VtK59}R3V9^C-S38s&4AoJ8v|z-XFgF+nKs7a<|h$b0}DUK)K&eBMth*r z`K$v7b08Sw-zD$?Ur{vx>}EIoZzzLcrz|WT;rwIgat%zbNfHOv(<9^hNvok=c3Pnc z!FR?^F#cfnu&I392|H?mgx+dOT|(z0Cc!2qewccZlBNa;e?MY$F|j9@emD$TU~v#00000NkvXX Hu0mjfEV_4# literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelAmbrosiaLuck3.png b/Pictures/Legacy/PixelAmbrosiaLuck3.png new file mode 100644 index 0000000000000000000000000000000000000000..f397639a56d685ed8276c45e157af56224dee51d GIT binary patch literal 831 zcmV-F1Hk-=P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0@O)FK~z{ry_dgh z6hRcnXO{%eoO^rziX=oNk|tnbbzCJ9NM#{nz{WwgXQY)Ie zZkwm`d3;jetNu2fL36Ws$PQqkx#3VV6Xx^9ZpN?s2UQ?XS&M_PMmGTdK?}?e86bnO zD#anF8%gDYt6|i&`u$)6_(K&5Xz{VmAXM_sDi{mPK21xFE5!jNATk3ic5Aw3jD^vj zA6@G!25n@q9Hz{QxYEB9nVwS_wLS_vV#(o|!#oo&fJ%D}SV(Qb(&NRH=f(T-M**Q(y&v2(f3kD+P66nWFavFzt)>3y)XuCUOj_0#=`Sp@R5WS zfUJSVlT+rH@llfkQOG07?Or!zYzE}&*%&yxIP-~m%Cs>SH$REk8d&%-rmpI5G}-}` z&SxD!m;=EW|1N6l;MUv0e?uUHV5clB9pU_AnDwxdf94N z6T*AOPB8vp_OPjZ+zDZUxc4M;`#n9E_mTq$!;X{0)4~C`)rc*Kf>({S?^axrcn^em zw0hbI?}hkQzgIEDaOFaHFIEna{k}2)Q8pUdHQi%)K6k*nrLsb5nGE1V5jL}LB=aDk z!Fs^CQykT=HyfriXfEXoodD3`s*ED(sQNuV!-o?-vOL#Se*qC64Tc`8%I*LF002ov JPDHLkV1fl9bwdCE literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelBlueberry.png b/Pictures/Legacy/PixelBlueberry.png new file mode 100644 index 0000000000000000000000000000000000000000..82caf946ef082189d574d63eab707d3c91771c19 GIT binary patch literal 789 zcmV+w1M2*VP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0;)+wK~z{r#h1@( z6G0TmXV(PNrkljoRt>@5=t=CM`Uga*r=miNUcFSjc`W!3c<8}vbMa^o1(jk!Q4fL_ z>BWoSK~V%flt%NzB#@Xf-?uyKWV5rgk#79JV|FIf{l53+y-8#26i#s#1D0vJPr=lA zk4EEt{y4v1{Xvs)vz)Vs9Vq|$X}FKEu$0bu8NZX=#|H8gw>a=?cn*jUcpqAb5!s3G zN*M#>K+~$(Ps2+@&Fg95DL0j|0pt>~LZ3 zl1EU)5XacvZqi(ZHUmQR^E;c(9&t?N2$(7sSn90p&h$h&g4)-=FZ}kMF*pN*6LRzr z_eY$Vo@5^{K2qK=ef!$ZVHsv@extl-b(Y9~w0%O<4SPCKv92s?tSfYST+J${aiAc&c*(4&1b|>KcH! zsCL;vP}HI>#Ga@GIv~Ww*~`dI;PVS}G-Zk8D=N@YQD(sI>!9rrnTSph6eWuDU(mK8 zB7^yz0P?+n&M@}eqi0bgQ84TM%fOHP0z`%vFD}k|=|*<22cry*#J{G4GSCUR3*?^9 zA08Cwekjvi*y}gW+NahnZ5sjvZ>$~2^M{QZd(v(U{LzVtRh~FA+-48}LInG0!6m9V z+OU+in6YXf;+xIJkORQ~au8KOhj4(wfh(yg^%=wjG?9I67sScP--dDEwc$9ALDr%S z;D;itxOXykC!itpfU%OB;hU`nO~%djbjEQ2ld#JO#iAms`5B%J{wJHTOq2ZqPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0>4Q_K~z{ry_e5x z6G0TmXV(PNrupI8Rt=&4L{DN5)juFgJrxyF^eRY2ym&11AMoJ8Yjg2v4+WKCK~WEa z7wN@|;6YIYJ(NcC!z7THvER2dak9I!lN2@|c+9@p$$sB^^Jc?ZJNZ+bML^27#Z@ph z-lfs{m^;oNR(_E)YL>H(KY-Go-1=oax=xps zsZK4?sB-L_8>uM>1aLEz(f0tvWw)yag0hxT|s zMOy)9R|m%qnaS)VL0O_X_k!^lA~Tpb2%x?fa5AiY_vu>p$ROCY-IswE^#RBX4_;iH z@0APx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0=`K^K~z{ry_e5x z6G0TmXV(PNrupI8Rt=&4L{DN5)juFgJrxyF^eRY2ym&11AMoJ8Yjg2v4+WKCK~WEa z7wN@|;6YIYJ(NcC!z7THvER2daWcEJn-n%5c+9@p$$sB^^Jc?ZJNZ+bML^27#g#ub z-lfs{m^;oNR(_E)YL>H(H-OTg-F61gJrH zI>izQH*zR|hUiEjl8-EV9a|L#q5ylYz@e4%941^N(1m%nKonr;3it^hUAxRrzP?5# zraTyX0EnqR<`#B55A(|y;ut&I4f0KR0?>gVY;uP4TX#91opE||Vo4tpg*;1~b%YmA zXaJ!4{r>}h{ABFw2ZsznsM$kY&p0+U&OTp!V(clq((SUAVap)^@p9SqpKdVre#^bq zLDpgA)`9jw6_D`1%Vh1=OY+OF)@d}AJS=-)o3aN|;OYVmtkW)##S`=HgaAT1-)_9H zg2bh+^?W+dAJr;sy;<{Je0tVhDYrqA-Y(JTTq@G2vbAwAFl$g8OYuADY;XXkPM4Lb zPA$=>a_pQNX;=^l;ASdg?g5C)ZdVQXWi9(ct{D{H0HnCwdlfYZ+`lkKE{nzAP=gMO zu>#Jn4vrl%li5l9vP5(4h0tS&%wT#DKz%RZWLW#|)3xl8L9lDPF9RL*0muvwUR<2- zl^fN;8jLE~5`8WVsz5v7U7()%+>w5P&ZiRj(%!yv=e{&=haN+KytJIyznb#g|{^<>%&08Y@$ n2+d+56Y?1z5BS7L**5zJ0^e#KMBw?P00000NkvXXu0mjfC*5vW literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelCubes.png b/Pictures/Legacy/PixelCubes.png new file mode 100644 index 0000000000000000000000000000000000000000..4080f4e0c46b2bc08bf8b5d844dc390035f25b95 GIT binary patch literal 761 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0**;UK~z{r#g|WO z6G0fpXGf(rX_K^4DK#L1g;p;;2vNa{M=w%A3Ly z**fb}r^M6dmK+>34@=`w121-eI;xuqck-p6;`fSUtfx*{h=*TsSR*iymH1+#8EYbb zrxIgi$7TV&1@zDum^7D3iclr5NPKa8DRqud(0+;SStvz&18$Q zX##rz+Ptlf0|g#_@)f=2-LC2=%*@&Bwm<2$;YvUk5&H^I<}~6n)02M3<5=UfbGuw* z)yk0PzTi)KEykF~@BXCEVbw-}INQ3!hHt2e5VggZsuu+!$h2BPC1`PwdK2yyvl5gz z7>I%Tr?0Bli#9=t1KxC9))BFXU|+O}zSglOa|%yOE%XHBkS)#MoFZ5^~-{XN4BR6d%65RlQzN1=4`d?&HNTk?7uX zWdMlBWvIo?%gTf_fCp<48}Hxv?RvS(rYp=EROTjD18KzvLBs&WXP#YWXD=*R!xX2= zYJ)mee8;;C{wJ~me~i0eFIlDK(cF3KWrgI)O_+u>mlY+hk^cq#aBd^ndy+Wls{#<$ z4?fd4B;(rfiJrh*oVb4N&hzm}vD$92l}<}8)~A4?es?J`t2A6aIwG#*M(hUU3J-Hb z>i0beaS#}IQaUbbowl6RCb9Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0mMl}K~z{r#g|V? z!$1_qCj;W2S{p@Nlx_si-~qgVAc8k=t-BsV(6uLU<n!FAUjB0_d*7k^JVzODAJoWd@&G>EBSv13Rr*7c(^F6VL zt#IB+i;7?LwpFQ4ZHt4dMqwaUJi9ce8unC>k`|`GEsKOEu^1E3g!ZfgQ@bK1Ktx|B zY_*V&F#+_v#0jYh=py`^)j=Xo#8g6LAV!>!nh;l@EtYR!oMq}eP^sAR6QOa?u297-ayg{SuK|gP!~7bA3&tT_xST`tA`F?J zvbu0N52%8F7m#yi?%2|Dxd46xxEuT+S3<6|TrNPf0iSp?1KWz>4M@bf`5vj~S}uT| zH$DX1?IceRqMbk96|eb}y2k3Unf`~PsXx>1Oq xb++mT7D-_M9a@zfzOC8|{0(36%t%*j^#|1iDtCfz@&5n-002ovPDHLkV1hz#^Oyht literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelFreeUpgradeImprovement2.png b/Pictures/Legacy/PixelFreeUpgradeImprovement2.png new file mode 100644 index 0000000000000000000000000000000000000000..b8df10430ed6b358e7328234653a670331a56030 GIT binary patch literal 624 zcmV-$0+0QPP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0tHD#K~z{ry_da8 z13?hS_ZCD=%!eX^As~X!-~(9N2qM^6TWjY-2wM9DR)USCja{(z1+*0ni7_JNy#Km$ zZ1!e9PLup#xV_oAng7o1Wl8ed-b%$3s7a|uJiTj$vla=)u$inLP zMIv6ZD;_8do`aciz6`3%?|~Q*+gS|E1kb@tIG=%g6NW@kTTM8h2Xw*z6_9e~-Lb9Z zd;$Cduo@)fTFAAQ^967V@D+E{*4Jow0Wrn7_uUcC1z!N!%YF>Th+R2i$Oz6C;(E1} z?ky~pQauR{7HcVL`!}J+b<)|Ur*b%-jXDd;g2d)2NETDjCaMEwaw@JSEMnupx7HdZ z08nyYQV<&l_|wnatX^X6LmFdV3x+hLzoZLi3e+>YZqL0{c&W$9PI-Dh7- zfcvjOuyy}oXTFk)Kdjb^0%l1r05`NNIeedLBk(tT&a)S5Qi>mtZioPnoPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0yarRK~z{ry_e5Q z12GWBvk~!6TU$j0OD{^F!J8l+MG-_0U%<28dNHBDxdtXh9Cba#@?eEBxJ*+!4Gx?p{v#JM`6X^U9?M%UFDanO2_C;!cEWx^J4 z`1%~F!@jUpsHBc>m&aL;PyH?qm^D%XuHx~Iu+|CW%ur1!R1VN zi1GQ}u=*s|snblPfR0*`E>Hv(XZNZ>qrR|`IulYH;338P0n~*Ex&;8vN;+|rI9*c> zirIl>c5`(mokF)%lan9;rllw%ZhQw8S6!@ilSQxtCQ!f()s%}L3-~K|D~?&$Kpxuh7$a{^gIlv-W08Eu;ex!tb>{nl$|Yc3dJTk#m`nOV=)iRl zI#f<0dlC9XpshMo&H=dKehN@IaqmcLshkJ50GJI7NLff(OXWOd3vdso6(2T8YBQf5n06%6cMt6(z{^> zI4FDx-AnmbUX6owEIG;HfQ7--0Vj=fluAiXz@$H#oLQ)050D< zUh96t;?QU+exopE3;0h`0dRt=lEU?>tdE00000NkvXX Hu0mjfM;s=B literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelObtainium.png b/Pictures/Legacy/PixelObtainium.png new file mode 100644 index 0000000000000000000000000000000000000000..efb8ffcf321e64706dd9ddef71a76eafbf7bc1af GIT binary patch literal 529 zcmV+s0`C2ZP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0j5brK~z{ry_Y{r z#4s3#lYl6m=hYKL#6`G8KZQ68j(!7YadPtui0G)B;NmVWI=DDGxSWfhKse6h)Dwh8 ze`yojYtz4P?tzy!S)O0sCN1T?)sAEiXbKVDr8AViy7KPInmir!)nL*bdhKL@i_do+ z-a28g;hB!_w-#8ePp;))++hMtLavFrvUf^7&}v;)RDiE=M-n2BE+x~2v6@XmxRO6T zGj@N+)HN*xyeR5NVC4O`U;mmhCxbyY^R;Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0sKisK~z{ry_dgB z!$25@F9&LAt*s7<#YO4hqDx)6iMWfCgOiImDlYyJijLy$>>xNfxOK6Mf}@iZ9Hf?N zEfsS1{mjLrO)i&s?E^}K+A#rJcQ%vYyDhlAb>S3oly_WzzU-YoS@@gv0b4nsqqt{8v>TF#7A zK;fXZ)G;c-b;4_>W$LuoOLQ~=a?zrOfWl{sixh6ZR-DV`Pzfl*O$|esfHEBO0GN;n z5)k)?C1u(9Oxc(OZ`d|#i{Rg;AUmi6*2+nhRqr0CHLjjn`f=3x=#O3r zXQjlJ;30QU5@>~kiYwBKR{}#8M?&VRRspt4Y7nWtbc{;?m4KIlNT3S30w7WX1W3ph zNE`v6l#qBO(6Fq#1WLpe06qznJ_tzUHW%3B-Zm?(E{94a5df}4{roai0)*`)65i}? z1__CjkoyOgF}~ZS?@td^;5%d|)W9dS2l002ovPDHLkV1g?# B2zdYi literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelPixelGeneration.png b/Pictures/Legacy/PixelPixelGeneration.png new file mode 100644 index 0000000000000000000000000000000000000000..0e8992bb702ab5eeb503010f9a508e57b91fa3fc GIT binary patch literal 802 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 literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelPixelLuck.png b/Pictures/Legacy/PixelPixelLuck.png new file mode 100644 index 0000000000000000000000000000000000000000..03f421a6c6eb06f0f5c1786503616b148ce7d97a GIT binary patch literal 576 zcmV-G0>AxPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0o6%FK~z{r#aBU2 z!!QtZj3TO*(87UAh)X11!Us6=1I}>c5lC?6Av}d^&pjZB0wq#J0%PLJb?r^oY0F4f zlQxr??9MuB^m=w)i!C6LvN>`iuPgN#y_}}?WA>&_c8$Bq@w$Ph&-bV~+zPHolV!zk z#z$hMPF(Towyv?7(@wB8mIgw^XW2|(^)W#w#RDxqU(D4CF`=OhESf}ifhk^m7a}k7 zUM6H8@vz`hB0&bfSN3(T8PWc1UOiLQLW zn*n_jN*tl`1+$H>A@kqOzy}a1aU`3X4jyPGg9Bc88WSPnrk1Jz{wQKy z><`%{xZ=>zdO&nPIjNt&KGeysaWy*pGk_CnGonUy-10X(CJK~DDSiMb`2A(r=#Aq5 O0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz18Ye{K~z{ry_e5R zR8bVi?|V3Dj-!*Lg}7+UMbx687PD4YL9`JhvOpI?WMo9qU(lk0j3m&7EgYzzO^bxY z+_W)Js72<&w5@^FIR2QLoZEcQ-1EG?ci){U&<`Bu-gkd|&pG$p=hInfZk1veh`Fw6 znaRjJ{W^0^2|1YlL7lzkPP{(oz{vVfM>ThazG&Rb_(0tOu_I5rEe`w|o&)}Y{0+II zHsq?1x~az=wsHSnx|Xq0OyZ6G9YQx%81_o3s!RF{~p7!j%U+ah{Oj9y4k4KNTtT6or*N~dbr9D#GGnLZ%GNt_-V| znUWcpo_R#SHu2G=Q>s;j=kQt^Zl>@u@Po6$nY9eIh~%F>k$QVAAilM{xD!PJkDSx9Haf&#^_V;|$jy zmg5_1;#GFdo6Mh2{1t<1S=--+rpM~gl=pUonEuWHx&!|G0Ip$YG$sTbIA2v0I0Msn zq2C&woRbZgI|9#PY8her9)#xegH1B@2>jo0e3l&5%~V67%r|Ka=;J(x3Hu%l{cC6g z(LtPFPUW6;7|w%uqkNa$ppIS#HuMz#k2oLs+3K2N2Jnv}tgW&-a8@S5Qe6(vU_C$? z7~fo@&R)|MEkpnZ&@sJ?7!*qwbtV1{kC^L^h`Fx#3;Z)alqvWNbpQYW07*qoM6N<$ Ef|9P!PXGV_ literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelPixelLuckConverter2.png b/Pictures/Legacy/PixelPixelLuckConverter2.png new file mode 100644 index 0000000000000000000000000000000000000000..e06876055202367ee879f45be5c9ade90d35b1e4 GIT binary patch literal 982 zcmV;{11bE8P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz18Ye{K~z{ry_e5R zR8bVi?|V3Dj-!*Lg}7+UMbx687PD4YL9`JhvOpI?WMo9qU(lk0j3m&7EgYzzO^bxY z+_W)Js72<&w5@^FIR2QLoZEcQ-1EG?ci){U&<`Bu-gkd|&pG$p=hInfZk1veh`Fw6 znaRjJ{W^0^2|1YlL7lzkPP{(oz{vVfM>ThazG&Rb_(0tOu_I5rEe`w|o&)}Y{0+II zHsq?1x~az=wsHSnx|Xq0OyZ6G9YQx%81_o3s!RF{~p7!j%U+ah{Oj9y4k4KNTtT6or*N~dbr9D#GGnLZ%GNt_-V| znUWcpo_R#SHu2G=Q>s;j=kQt^Zl>@u@Po6$nY9eIh~%F>k$QVAAilM{xD!PJkDSx9Haf&#^_V;|$jy zmg5_1;#GFdo6Mh2{1t<1S=--+rpM~gl=pUonEuWHx&!|G0Ip$YG$sTbIA2v0I0Msn zq2C&woRbZgI|9#PY8her9)#xegH1B@2>jo0e3l&5%~V67%r|Ka=;J(x3Hu%l{cC6g z(LtPFPUW6;7|w%uqkNa$ppIS#HuMz#k2oLs+3K2N2Jnv}tgW&-a8@S5Qe6(vU_C$? z7~fo@&R)|MEkpnZ&@sJ?7!*qwbtV1{kC^L^h`Fx#3;Z)alqvWNbpQYW07*qoM6N<$ Ef|9P!PXGV_ literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelQuarks.png b/Pictures/Legacy/PixelQuarks.png new file mode 100644 index 0000000000000000000000000000000000000000..ade3b8857a063d769d42ab51540799aabdb2e200 GIT binary patch literal 744 zcmVP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0)0tDK~z{ry_d~v z6Hye!-#lz$l1`I0Vx@HB*FuEuyA@o!upr{zZoBLs;iB8R7gsLabmJf3Rs`)rDhN_2 z7-~$Kv{5ql+|GTxOy0+hIQ_w8zB2Eecix>Dl5|$@WU2&Gt@AxMy=+X|kGh|?pcccIk zIvixmReT*gQnXNfLfFSFMxcw5EWwoUt5JvQ!~QoaK4uC=g2W7vIKx5@hc&7n_u6#+ z{z0F%E+gjzO^BP&7G{n{XU4>@?;~@~HW4Faz|7t^plt@cs|}4wz9*J~?vBUmGz+Fg zU{DCy#k{Xp)ayn)KavA&UjkFJf79tw%)7@|r~pi08C>Gh6traaXtMRQ5!KU^0i9zb zY-V%u4{fEeZnO!x!_jQ0ySGxW821E{`Pdwrdqaqx0th4OwXUY}0a4U)rK+y&$DahG z5H;}W_B@H&vvYx^`0}+!!Yqz^V~7$cVy`CWJ>_M`-bR*jv^wrzbe&~l35x<^e zSf;&WZq(9jqmhc65Cc&f#YAkZ>-2l<_~2!q^(mMzQY^lX9SNbYVGI^3*36j4@X^(I z*#iFuY%NLve-u#Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0p>|WK~z{r#h1NK z!!Q(uogf6Xq$%Z3RFx1vFTudV3$P%uFu(vaV;_Nmff*JC28PbO07xv%Ou#~=3L&5& zv_&9lI3_nrTQ`lZCjF$V*j3bXeDAfb7%zoo&SJnaO>ZQ}?CxTkxoss~;K;7%eL15g>&5I^HtG~CD z;DAkQZO2B59H3;K6vsi& z+b{`C*Xw~KcS2B0WB?zEh_#Va>?WW=dcZi$&hU%IhnOVIW;*k402As;8DU%1?(rEu fY;->uEz@MbY@{T{tRS{E00000NkvXXu0mjfgHZBY literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/PixelTutorial.png b/Pictures/Legacy/PixelTutorial.png new file mode 100644 index 0000000000000000000000000000000000000000..f36eb7c596908284740a4c99ca3a72b5c041bcb0 GIT binary patch literal 627 zcmV-(0*w8MP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0tiV&K~z{ry_d^M z!$25?Cj(;X#onNZ)P&%;zQf1n} zxw1Y(AA)#meTTK11&h@p+HZYU!-&cRH$W|SJE%~JgGRl`3Jj~J z1iC2F&B~+K5%+`fIwpYpw3q`z197A0=w?AH1C`fjR?>j>$75nUVv{<;++c95DhtpK z&A_bbj{=oN@8@H6(`_XK*Hx|o2@JXTQ+sz?auBh<=we({mYt3@B-i$E$|1iKaF|2|kpofm`}lktjeIh*A#&d)d6&07rDCico!&dIru)HRs;`yLMG3k^N zUCbuG9|J&x>j9R5&i9aY=FLHFvIt=S9obPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0~bj|K~z{ry_Y>` z6j2bz->#91_ic)xa&ia?7J_BKPHp50twbam(Za^U6oP^lDMSdQh=qj~il?cp6ueS9 zAz~8|@uL#$BzTv*Z0-hn&Axs6aZ2t7%e?pQz5UOdH?zBEtycECY6~dXHnq&O z-9B3DrIQATf*gB*^l^aX{QRrDM@@~`Ojl&Mv^oqqyZ6- zUL_GHkj6m)&W z?d>O1XlEXd*X4TMp>x?HMj$c=U;!*-aTaD|pT!yILsWRZE-pz-LR}no&bybu&UyC$ zJ3-w@hN=Q^gfATsyU0Lb7fs2Y7-We!Qml;vAC`APzL=U;9TO zj{$x&RYPJDa`@p2aODLxl-e>sP(De8t zfO8Lpp1F6D8cJ;}y`feRI0DFnI6@A{3XtMhf|PuIG74aq03@Rnm3d&QuCccFFkobv zcx~077myDffhj5=)SRb|3O<(OUQ8H)-&B*PGT{o)MKL0T9%ilpxqC)xz~&=!04Bow zo`vu^AVj4@QV5)3hrr6+o4|KL9PET1g{TPd&RLv>BeCvJ>~b4UM?LR$Qhksx{58br zuim5&l2hY(_iVmscEGd%#;BPJ(|S1u4%D)FrN9B`(0C$ojtt`@Xo9xQWjKrz|BKYJ z7Rr-uW1~Y|?<2G4r20JnSB_<}zWAA(mjk*3qr`UrI{Yv)5m&0Egumh22k)H_1>07C Y0p~FFp;yMMO8@`>07*qoM6N<$g825BF#rGn literal 0 HcmV?d00001 diff --git a/Pictures/Legacy/SingularityPixelLuck.png b/Pictures/Legacy/SingularityPixelLuck.png new file mode 100644 index 0000000000000000000000000000000000000000..573534a1f5b20fe1715cef9e6d89b582640e7718 GIT binary patch literal 851 zcmV-Z1FZasP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940_aIZK~z{ry;s3< z(=ZTS%XVTrjgy|jg+t-Ufv?~z_zJ#+kKxA0&>2o-hG8a634yc~@2%ycIEi9;Xy43c zWykA%)~;5oL_S$7=aB3~%pYio+5VIC7i5F+Pfz=DBa*G0tlc&BEric+Ln!JN9lCr1`u#cMm(sO+JuBDfQ40{2!Du!>`dI(?J5b;U3J#B)OVh$)Z|F zkrw*(oP}vV)qDJp&$!3Wppr}c8m(|FGCk2HG0ZuTT*#&7K!UP#I0*{I^H@xM5+UcO z>=o%$=1@k`;{<5Pq&k&YEs2oxkiDd}Ora106lhi^53MmXJCxmY9C9AC&uW=KfdF<4 zZVnE<@sM@i+diAgM00=y+zfP$W7m0f;O?*B^JBRqwGfr z0d2H%@n)d=lGt_L+nynSY6!4%@!-ECUEu39yelk^}8aLe7~~rxNp= zJy$_Ppc4WgGz>XsW`|bCDSO3eDg{(C1Dz0r;5#2uCmw;^7=xOT9IbLs0$t~^bz%?c zM8;4E0eW_?5x-`!aiD>jkuudIFZrP&eDnCPM52|>qhDDpXj zvmY<4ef_QJif~#{VULKu9fv0f>lL;Q^l)O(!=RB+K`oaIO%*m39aA{g|L`0ogB=CA z(#CubN?=u6c10PQQy!Hn2pa_+8YpuJUaJixPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940{uxuK~z{ry;n<) z(?Ad{{}S8z&MItJ3@ll23QoZ(I0=VgH-}*)RzyNbnG7M2nQ7iDw?oIVJ8nxePpXvN zak-wWs=KQr`C^P*LUa&`|3X9J{eMY*Lw30SJXHQz0T%%my{4wrW7L%Tx!R83^KE=iAo_^0XM|aasXt=0Mi8pu3Zc%QJ{d!? zx4jUp;e%0l5Xs^FNWgWDm>gk;&Opbvn_Hm-lemX35GY&%E+PwidxqNidbd^?LV`6l zg@;xG_TyV$=sMp&?qz$}4kKX_nRgK&Y!FVO&~$!yI!G3014$Gz?@9q-gAf+hAQZB| zZ>)<<1NP$;c1RI_j-uj-zY7#!@K6^>#GJ`@2ut0NV za!?zyvVGM}$3Ev?`*bc7C=kGo!Og+KH6Ak0d)ucAnP?4=fQ>-YICP!|*=GwWafKSd zzRYd%rI9VqQ&1OHJ;g%jd64}GDWHvZE=~lRFA1IJz3rI-sEPnP7YFW3e9oEAwwmZ= zKbm7PCIR+wEj3WT#OItv)m506>^Tc60*w^7prOw>E890ay6hFBndDGa1R5#u!F4`l zoj3xuF$T3*GPKG)2{fIDt`jFnCNhRX3edAVE8&YFEoB51>!G1%1ei}26)StlI&p%e zkPHeDKnemP&?GU)IT14f8UY-Y0+(W!#31JoUmm)VQoc(-d%-io(SA^4w3VTHK?KnI^xL#q~Ko2J|dKfek zDp<=UMN@@MMXxEm*8lJvC50UYwNmH&1WI5tH|&a1G^ac&l@K-xJTy?25WH3!NXiua yK}C1668F@U0^{6V3XJ8r&Y?NYD6IB&i2MU2c1fp(jPK_F0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940ftFLK~z{r?UqkU z!$1^=ry__T;-cb4g)VgC1w2IV;~8?F9Ks89ql<#N5xWo(L=bC!m2%46H?>4oqfYqa5!JLfdsRy$8z6jI z9n>pr#|QZE`8Ug5T`>TbJ%0D1VBeZKpPIS1pt%y@4sXLCP7Db-yxHOS^&fnz#0xr n0w72LYxrOwfs1ap7;x?f)LTMp4{f!l00000NkvXXu0mjfl48%h literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..216e2cd247bc20728eb1de0f4d04c94fab63d0fc GIT binary patch literal 783 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 literal 0 HcmV?d00001 diff --git a/Pictures/Monotonous/PixelAmbrosiaLuck2.png b/Pictures/Monotonous/PixelAmbrosiaLuck2.png new file mode 100644 index 0000000000000000000000000000000000000000..8f5f049f204e8d77fe2cee37a55a84cc733d7991 GIT binary patch literal 829 zcmV-D1H$}?P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0@6uDK~z{ry_dgh z6hRcnXO{%eoO^rziX=oNk|tnbbzCJ9NM#{nz{WXnPaW>i7Bmez_D#=Mbp$> z^RzyXPwIR1-=;HYZk7*)16XKpSk%mg`C{42_;vT7^5rRSaS+t-0^lFC!2FN{GKf&6 zSOj$=sa>!&jJlzI7EAzts3HMvKGqq8D$ZF2V`15+X{oWLI73MYWr4+RO*f3OFxvB@ zYng(8E-dn}QWAWQr1)KT%oq!!{m`1o90Z810YF1Oe!5?&r95Fqw$l=sfkBcO08+_D zLm`GI3)J$HW-YLmjvd$c8yo7`X498)EX4bid}uD4cU-6zY2+VUs~xrdecPKO!PxYR zuFwDFk&?dRxN3;{K3E(@Cf|8w#qaptn^)#}X7-$U0<61M{YX8fj@D18N)3g%tb;*- zp-$k)OK}vLQm`I{YVX-uY5TIkyJz9YiY5YA?fBX`9f2TN_rHn|;@JK3x2KG~|FUGn zA?y=RK_~!3h^VtK59}R3V9^C-S38s&4AoJ8v|z-XFgF+nKs7a<|h$b0}DUK)K&eBMth*r z`K$v7b08Sw-zD$?Ur{vx>}EIoZzzLcrz|WT;rwIgat%zbNfHOv(<9^hNvok=c3Pnc z!FR?^F#cfnu&I392|H?mgx+dOT|(z0Cc!2qewccZlBNa;e?MY$F|j9@emD$TU~v#00000NkvXX Hu0mjfEV_4# literal 0 HcmV?d00001 diff --git a/Pictures/Monotonous/PixelAmbrosiaLuck3.png b/Pictures/Monotonous/PixelAmbrosiaLuck3.png new file mode 100644 index 0000000000000000000000000000000000000000..f397639a56d685ed8276c45e157af56224dee51d GIT binary patch literal 831 zcmV-F1Hk-=P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0@O)FK~z{ry_dgh z6hRcnXO{%eoO^rziX=oNk|tnbbzCJ9NM#{nz{WwgXQY)Ie zZkwm`d3;jetNu2fL36Ws$PQqkx#3VV6Xx^9ZpN?s2UQ?XS&M_PMmGTdK?}?e86bnO zD#anF8%gDYt6|i&`u$)6_(K&5Xz{VmAXM_sDi{mPK21xFE5!jNATk3ic5Aw3jD^vj zA6@G!25n@q9Hz{QxYEB9nVwS_wLS_vV#(o|!#oo&fJ%D}SV(Qb(&NRH=f(T-M**Q(y&v2(f3kD+P66nWFavFzt)>3y)XuCUOj_0#=`Sp@R5WS zfUJSVlT+rH@llfkQOG07?Or!zYzE}&*%&yxIP-~m%Cs>SH$REk8d&%-rmpI5G}-}` z&SxD!m;=EW|1N6l;MUv0e?uUHV5clB9pU_AnDwxdf94N z6T*AOPB8vp_OPjZ+zDZUxc4M;`#n9E_mTq$!;X{0)4~C`)rc*Kf>({S?^axrcn^em zw0hbI?}hkQzgIEDaOFaHFIEna{k}2)Q8pUdHQi%)K6k*nrLsb5nGE1V5jL}LB=aDk z!Fs^CQykT=HyfriXfEXoodD3`s*ED(sQNuV!-o?-vOL#Se*qC64Tc`8%I*LF002ov JPDHLkV1fl9bwdCE literal 0 HcmV?d00001 diff --git a/Pictures/Monotonous/PixelBlueberry.png b/Pictures/Monotonous/PixelBlueberry.png new file mode 100644 index 0000000000000000000000000000000000000000..82caf946ef082189d574d63eab707d3c91771c19 GIT binary patch literal 789 zcmV+w1M2*VP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0;)+wK~z{r#h1@( z6G0TmXV(PNrkljoRt>@5=t=CM`Uga*r=miNUcFSjc`W!3c<8}vbMa^o1(jk!Q4fL_ z>BWoSK~V%flt%NzB#@Xf-?uyKWV5rgk#79JV|FIf{l53+y-8#26i#s#1D0vJPr=lA zk4EEt{y4v1{Xvs)vz)Vs9Vq|$X}FKEu$0bu8NZX=#|H8gw>a=?cn*jUcpqAb5!s3G zN*M#>K+~$(Ps2+@&Fg95DL0j|0pt>~LZ3 zl1EU)5XacvZqi(ZHUmQR^E;c(9&t?N2$(7sSn90p&h$h&g4)-=FZ}kMF*pN*6LRzr z_eY$Vo@5^{K2qK=ef!$ZVHsv@extl-b(Y9~w0%O<4SPCKv92s?tSfYST+J${aiAc&c*(4&1b|>KcH! zsCL;vP}HI>#Ga@GIv~Ww*~`dI;PVS}G-Zk8D=N@YQD(sI>!9rrnTSph6eWuDU(mK8 zB7^yz0P?+n&M@}eqi0bgQ84TM%fOHP0z`%vFD}k|=|*<22cry*#J{G4GSCUR3*?^9 zA08Cwekjvi*y}gW+NahnZ5sjvZ>$~2^M{QZd(v(U{LzVtRh~FA+-48}LInG0!6m9V z+OU+in6YXf;+xIJkORQ~au8KOhj4(wfh(yg^%=wjG?9I67sScP--dDEwc$9ALDr%S z;D;itxOXykC!itpfU%OB;hU`nO~%djbjEQ2ld#JO#iAms`5B%J{wJHTOq2ZqPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0>4Q_K~z{ry_e5x z6G0TmXV(PNrupI8Rt=&4L{DN5)juFgJrxyF^eRY2ym&11AMoJ8Yjg2v4+WKCK~WEa z7wN@|;6YIYJ(NcC!z7THvER2dak9I!lN2@|c+9@p$$sB^^Jc?ZJNZ+bML^27#Z@ph z-lfs{m^;oNR(_E)YL>H(KY-Go-1=oax=xps zsZK4?sB-L_8>uM>1aLEz(f0tvWw)yag0hxT|s zMOy)9R|m%qnaS)VL0O_X_k!^lA~Tpb2%x?fa5AiY_vu>p$ROCY-IswE^#RBX4_;iH z@0APx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0=`K^K~z{ry_e5x z6G0TmXV(PNrupI8Rt=&4L{DN5)juFgJrxyF^eRY2ym&11AMoJ8Yjg2v4+WKCK~WEa z7wN@|;6YIYJ(NcC!z7THvER2daWcEJn-n%5c+9@p$$sB^^Jc?ZJNZ+bML^27#g#ub z-lfs{m^;oNR(_E)YL>H(H-OTg-F61gJrH zI>izQH*zR|hUiEjl8-EV9a|L#q5ylYz@e4%941^N(1m%nKonr;3it^hUAxRrzP?5# zraTyX0EnqR<`#B55A(|y;ut&I4f0KR0?>gVY;uP4TX#91opE||Vo4tpg*;1~b%YmA zXaJ!4{r>}h{ABFw2ZsznsM$kY&p0+U&OTp!V(clq((SUAVap)^@p9SqpKdVre#^bq zLDpgA)`9jw6_D`1%Vh1=OY+OF)@d}AJS=-)o3aN|;OYVmtkW)##S`=HgaAT1-)_9H zg2bh+^?W+dAJr;sy;<{Je0tVhDYrqA-Y(JTTq@G2vbAwAFl$g8OYuADY;XXkPM4Lb zPA$=>a_pQNX;=^l;ASdg?g5C)ZdVQXWi9(ct{D{H0HnCwdlfYZ+`lkKE{nzAP=gMO zu>#Jn4vrl%li5l9vP5(4h0tS&%wT#DKz%RZWLW#|)3xl8L9lDPF9RL*0muvwUR<2- zl^fN;8jLE~5`8WVsz5v7U7()%+>w5P&ZiRj(%!yv=e{&=haN+KytJIyznb#g|{^<>%&08Y@$ n2+d+56Y?1z5BS7L**5zJ0^e#KMBw?P00000NkvXXu0mjfC*5vW literal 0 HcmV?d00001 diff --git a/Pictures/Monotonous/PixelCubes.png b/Pictures/Monotonous/PixelCubes.png new file mode 100644 index 0000000000000000000000000000000000000000..4080f4e0c46b2bc08bf8b5d844dc390035f25b95 GIT binary patch literal 761 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0**;UK~z{r#g|WO z6G0fpXGf(rX_K^4DK#L1g;p;;2vNa{M=w%A3Ly z**fb}r^M6dmK+>34@=`w121-eI;xuqck-p6;`fSUtfx*{h=*TsSR*iymH1+#8EYbb zrxIgi$7TV&1@zDum^7D3iclr5NPKa8DRqud(0+;SStvz&18$Q zX##rz+Ptlf0|g#_@)f=2-LC2=%*@&Bwm<2$;YvUk5&H^I<}~6n)02M3<5=UfbGuw* z)yk0PzTi)KEykF~@BXCEVbw-}INQ3!hHt2e5VggZsuu+!$h2BPC1`PwdK2yyvl5gz z7>I%Tr?0Bli#9=t1KxC9))BFXU|+O}zSglOa|%yOE%XHBkS)#MoFZ5^~-{XN4BR6d%65RlQzN1=4`d?&HNTk?7uX zWdMlBWvIo?%gTf_fCp<48}Hxv?RvS(rYp=EROTjD18KzvLBs&WXP#YWXD=*R!xX2= zYJ)mee8;;C{wJ~me~i0eFIlDK(cF3KWrgI)O_+u>mlY+hk^cq#aBd^ndy+Wls{#<$ z4?fd4B;(rfiJrh*oVb4N&hzm}vD$92l}<}8)~A4?es?J`t2A6aIwG#*M(hUU3J-Hb z>i0beaS#}IQaUbbowl6RCb9Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0mMl}K~z{r#g|V? z!$1_qCj;W2S{p@Nlx_si-~qgVAc8k=t-BsV(6uLU<n!FAUjB0_d*7k^JVzODAJoWd@&G>EBSv13Rr*7c(^F6VL zt#IB+i;7?LwpFQ4ZHt4dMqwaUJi9ce8unC>k`|`GEsKOEu^1E3g!ZfgQ@bK1Ktx|B zY_*V&F#+_v#0jYh=py`^)j=Xo#8g6LAV!>!nh;l@EtYR!oMq}eP^sAR6QOa?u297-ayg{SuK|gP!~7bA3&tT_xST`tA`F?J zvbu0N52%8F7m#yi?%2|Dxd46xxEuT+S3<6|TrNPf0iSp?1KWz>4M@bf`5vj~S}uT| zH$DX1?IceRqMbk96|eb}y2k3Unf`~PsXx>1Oq xb++mT7D-_M9a@zfzOC8|{0(36%t%*j^#|1iDtCfz@&5n-002ovPDHLkV1hz#^Oyht literal 0 HcmV?d00001 diff --git a/Pictures/Monotonous/PixelFreeUpgradeImprovement2.png b/Pictures/Monotonous/PixelFreeUpgradeImprovement2.png new file mode 100644 index 0000000000000000000000000000000000000000..b8df10430ed6b358e7328234653a670331a56030 GIT binary patch literal 624 zcmV-$0+0QPP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0tHD#K~z{ry_da8 z13?hS_ZCD=%!eX^As~X!-~(9N2qM^6TWjY-2wM9DR)USCja{(z1+*0ni7_JNy#Km$ zZ1!e9PLup#xV_oAng7o1Wl8ed-b%$3s7a|uJiTj$vla=)u$inLP zMIv6ZD;_8do`aciz6`3%?|~Q*+gS|E1kb@tIG=%g6NW@kTTM8h2Xw*z6_9e~-Lb9Z zd;$Cduo@)fTFAAQ^967V@D+E{*4Jow0Wrn7_uUcC1z!N!%YF>Th+R2i$Oz6C;(E1} z?ky~pQauR{7HcVL`!}J+b<)|Ur*b%-jXDd;g2d)2NETDjCaMEwaw@JSEMnupx7HdZ z08nyYQV<&l_|wnatX^X6LmFdV3x+hLzoZLi3e+>YZqL0{c&W$9PI-Dh7- zfcvjOuyy}oXTFk)Kdjb^0%l1r05`NNIeedLBk(tT&a)S5Qi>mtZioPnoPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0yarRK~z{ry_e5Q z12GWBvk~!6TU$j0OD{^F!J8l+MG-_0U%<28dNHBDxdtXh9Cba#@?eEBxJ*+!4Gx?p{v#JM`6X^U9?M%UFDanO2_C;!cEWx^J4 z`1%~F!@jUpsHBc>m&aL;PyH?qm^D%XuHx~Iu+|CW%ur1!R1VN zi1GQ}u=*s|snblPfR0*`E>Hv(XZNZ>qrR|`IulYH;338P0n~*Ex&;8vN;+|rI9*c> zirIl>c5`(mokF)%lan9;rllw%ZhQw8S6!@ilSQxtCQ!f()s%}L3-~K|D~?&$Kpxuh7$a{^gIlv-W08Eu;ex!tb>{nl$|Yc3dJTk#m`nOV=)iRl zI#f<0dlC9XpshMo&H=dKehN@IaqmcLshkJ50GJI7NLff(OXWOd3vdso6(2T8YBQf5n06%6cMt6(z{^> zI4FDx-AnmbUX6owEIG;HfQ7--0Vj=fluAiXz@$H#oLQ)050D< zUh96t;?QU+exopE3;0h`0dRt=lEU?>tdE00000NkvXX Hu0mjfM;s=B literal 0 HcmV?d00001 diff --git a/Pictures/Monotonous/PixelObtainium.png b/Pictures/Monotonous/PixelObtainium.png new file mode 100644 index 0000000000000000000000000000000000000000..efb8ffcf321e64706dd9ddef71a76eafbf7bc1af GIT binary patch literal 529 zcmV+s0`C2ZP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0j5brK~z{ry_Y{r z#4s3#lYl6m=hYKL#6`G8KZQ68j(!7YadPtui0G)B;NmVWI=DDGxSWfhKse6h)Dwh8 ze`yojYtz4P?tzy!S)O0sCN1T?)sAEiXbKVDr8AViy7KPInmir!)nL*bdhKL@i_do+ z-a28g;hB!_w-#8ePp;))++hMtLavFrvUf^7&}v;)RDiE=M-n2BE+x~2v6@XmxRO6T zGj@N+)HN*xyeR5NVC4O`U;mmhCxbyY^R;Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0sKisK~z{ry_dgB z!$25@F9&LAt*s7<#YO4hqDx)6iMWfCgOiImDlYyJijLy$>>xNfxOK6Mf}@iZ9Hf?N zEfsS1{mjLrO)i&s?E^}K+A#rJcQ%vYyDhlAb>S3oly_WzzU-YoS@@gv0b4nsqqt{8v>TF#7A zK;fXZ)G;c-b;4_>W$LuoOLQ~=a?zrOfWl{sixh6ZR-DV`Pzfl*O$|esfHEBO0GN;n z5)k)?C1u(9Oxc(OZ`d|#i{Rg;AUmi6*2+nhRqr0CHLjjn`f=3x=#O3r zXQjlJ;30QU5@>~kiYwBKR{}#8M?&VRRspt4Y7nWtbc{;?m4KIlNT3S30w7WX1W3ph zNE`v6l#qBO(6Fq#1WLpe06qznJ_tzUHW%3B-Zm?(E{94a5df}4{roai0)*`)65i}? z1__CjkoyOgF}~ZS?@td^;5%d|)W9dS2l002ovPDHLkV1g?# B2zdYi literal 0 HcmV?d00001 diff --git a/Pictures/Monotonous/PixelPixelGeneration.png b/Pictures/Monotonous/PixelPixelGeneration.png new file mode 100644 index 0000000000000000000000000000000000000000..0e8992bb702ab5eeb503010f9a508e57b91fa3fc GIT binary patch literal 802 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 literal 0 HcmV?d00001 diff --git a/Pictures/Monotonous/PixelPixelLuck.png b/Pictures/Monotonous/PixelPixelLuck.png new file mode 100644 index 0000000000000000000000000000000000000000..03f421a6c6eb06f0f5c1786503616b148ce7d97a GIT binary patch literal 576 zcmV-G0>AxPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0o6%FK~z{r#aBU2 z!!QtZj3TO*(87UAh)X11!Us6=1I}>c5lC?6Av}d^&pjZB0wq#J0%PLJb?r^oY0F4f zlQxr??9MuB^m=w)i!C6LvN>`iuPgN#y_}}?WA>&_c8$Bq@w$Ph&-bV~+zPHolV!zk z#z$hMPF(Towyv?7(@wB8mIgw^XW2|(^)W#w#RDxqU(D4CF`=OhESf}ifhk^m7a}k7 zUM6H8@vz`hB0&bfSN3(T8PWc1UOiLQLW zn*n_jN*tl`1+$H>A@kqOzy}a1aU`3X4jyPGg9Bc88WSPnrk1Jz{wQKy z><`%{xZ=>zdO&nPIjNt&KGeysaWy*pGk_CnGonUy-10X(CJK~DDSiMb`2A(r=#Aq5 O0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz18Ye{K~z{ry_e5R zR8bVi?|V3Dj-!*Lg}7+UMbx687PD4YL9`JhvOpI?WMo9qU(lk0j3m&7EgYzzO^bxY z+_W)Js72<&w5@^FIR2QLoZEcQ-1EG?ci){U&<`Bu-gkd|&pG$p=hInfZk1veh`Fw6 znaRjJ{W^0^2|1YlL7lzkPP{(oz{vVfM>ThazG&Rb_(0tOu_I5rEe`w|o&)}Y{0+II zHsq?1x~az=wsHSnx|Xq0OyZ6G9YQx%81_o3s!RF{~p7!j%U+ah{Oj9y4k4KNTtT6or*N~dbr9D#GGnLZ%GNt_-V| znUWcpo_R#SHu2G=Q>s;j=kQt^Zl>@u@Po6$nY9eIh~%F>k$QVAAilM{xD!PJkDSx9Haf&#^_V;|$jy zmg5_1;#GFdo6Mh2{1t<1S=--+rpM~gl=pUonEuWHx&!|G0Ip$YG$sTbIA2v0I0Msn zq2C&woRbZgI|9#PY8her9)#xegH1B@2>jo0e3l&5%~V67%r|Ka=;J(x3Hu%l{cC6g z(LtPFPUW6;7|w%uqkNa$ppIS#HuMz#k2oLs+3K2N2Jnv}tgW&-a8@S5Qe6(vU_C$? z7~fo@&R)|MEkpnZ&@sJ?7!*qwbtV1{kC^L^h`Fx#3;Z)alqvWNbpQYW07*qoM6N<$ Ef|9P!PXGV_ literal 0 HcmV?d00001 diff --git a/Pictures/Monotonous/PixelPixelLuckConverter2.png b/Pictures/Monotonous/PixelPixelLuckConverter2.png new file mode 100644 index 0000000000000000000000000000000000000000..e06876055202367ee879f45be5c9ade90d35b1e4 GIT binary patch literal 982 zcmV;{11bE8P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz18Ye{K~z{ry_e5R zR8bVi?|V3Dj-!*Lg}7+UMbx687PD4YL9`JhvOpI?WMo9qU(lk0j3m&7EgYzzO^bxY z+_W)Js72<&w5@^FIR2QLoZEcQ-1EG?ci){U&<`Bu-gkd|&pG$p=hInfZk1veh`Fw6 znaRjJ{W^0^2|1YlL7lzkPP{(oz{vVfM>ThazG&Rb_(0tOu_I5rEe`w|o&)}Y{0+II zHsq?1x~az=wsHSnx|Xq0OyZ6G9YQx%81_o3s!RF{~p7!j%U+ah{Oj9y4k4KNTtT6or*N~dbr9D#GGnLZ%GNt_-V| znUWcpo_R#SHu2G=Q>s;j=kQt^Zl>@u@Po6$nY9eIh~%F>k$QVAAilM{xD!PJkDSx9Haf&#^_V;|$jy zmg5_1;#GFdo6Mh2{1t<1S=--+rpM~gl=pUonEuWHx&!|G0Ip$YG$sTbIA2v0I0Msn zq2C&woRbZgI|9#PY8her9)#xegH1B@2>jo0e3l&5%~V67%r|Ka=;J(x3Hu%l{cC6g z(LtPFPUW6;7|w%uqkNa$ppIS#HuMz#k2oLs+3K2N2Jnv}tgW&-a8@S5Qe6(vU_C$? z7~fo@&R)|MEkpnZ&@sJ?7!*qwbtV1{kC^L^h`Fx#3;Z)alqvWNbpQYW07*qoM6N<$ Ef|9P!PXGV_ literal 0 HcmV?d00001 diff --git a/Pictures/Monotonous/PixelQuarks.png b/Pictures/Monotonous/PixelQuarks.png new file mode 100644 index 0000000000000000000000000000000000000000..ade3b8857a063d769d42ab51540799aabdb2e200 GIT binary patch literal 744 zcmVP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0)0tDK~z{ry_d~v z6Hye!-#lz$l1`I0Vx@HB*FuEuyA@o!upr{zZoBLs;iB8R7gsLabmJf3Rs`)rDhN_2 z7-~$Kv{5ql+|GTxOy0+hIQ_w8zB2Eecix>Dl5|$@WU2&Gt@AxMy=+X|kGh|?pcccIk zIvixmReT*gQnXNfLfFSFMxcw5EWwoUt5JvQ!~QoaK4uC=g2W7vIKx5@hc&7n_u6#+ z{z0F%E+gjzO^BP&7G{n{XU4>@?;~@~HW4Faz|7t^plt@cs|}4wz9*J~?vBUmGz+Fg zU{DCy#k{Xp)ayn)KavA&UjkFJf79tw%)7@|r~pi08C>Gh6traaXtMRQ5!KU^0i9zb zY-V%u4{fEeZnO!x!_jQ0ySGxW821E{`Pdwrdqaqx0th4OwXUY}0a4U)rK+y&$DahG z5H;}W_B@H&vvYx^`0}+!!Yqz^V~7$cVy`CWJ>_M`-bR*jv^wrzbe&~l35x<^e zSf;&WZq(9jqmhc65Cc&f#YAkZ>-2l<_~2!q^(mMzQY^lX9SNbYVGI^3*36j4@X^(I z*#iFuY%NLve-u#Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0p>|WK~z{r#h1NK z!!Q(uogf6Xq$%Z3RFx1vFTudV3$P%uFu(vaV;_Nmff*JC28PbO07xv%Ou#~=3L&5& zv_&9lI3_nrTQ`lZCjF$V*j3bXeDAfb7%zoo&SJnaO>ZQ}?CxTkxoss~;K;7%eL15g>&5I^HtG~CD z;DAkQZO2B59H3;K6vsi& z+b{`C*Xw~KcS2B0WB?zEh_#Va>?WW=dcZi$&hU%IhnOVIW;*k402As;8DU%1?(rEu fY;->uEz@MbY@{T{tRS{E00000NkvXXu0mjfgHZBY literal 0 HcmV?d00001 diff --git a/Pictures/Monotonous/PixelTutorial.png b/Pictures/Monotonous/PixelTutorial.png new file mode 100644 index 0000000000000000000000000000000000000000..f36eb7c596908284740a4c99ca3a72b5c041bcb0 GIT binary patch literal 627 zcmV-(0*w8MP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0tiV&K~z{ry_d^M z!$25?Cj(;X#onNZ)P&%;zQf1n} zxw1Y(AA)#meTTK11&h@p+HZYU!-&cRH$W|SJE%~JgGRl`3Jj~J z1iC2F&B~+K5%+`fIwpYpw3q`z197A0=w?AH1C`fjR?>j>$75nUVv{<;++c95DhtpK z&A_bbj{=oN@8@H6(`_XK*Hx|o2@JXTQ+sz?auBh<=we({mYt3@B-i$E$|1iKaF|2|kpofm`}lktjeIh*A#&d)d6&07rDCico!&dIru)HRs;`yLMG3k^N zUCbuG9|J&x>j9R5&i9aY=FLHFvIt=S9obPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0~bj|K~z{ry_Y>` z6j2bz->#91_ic)xa&ia?7J_BKPHp50twbam(Za^U6oP^lDMSdQh=qj~il?cp6ueS9 zAz~8|@uL#$BzTv*Z0-hn&Axs6aZ2t7%e?pQz5UOdH?zBEtycECY6~dXHnq&O z-9B3DrIQATf*gB*^l^aX{QRrDM@@~`Ojl&Mv^oqqyZ6- zUL_GHkj6m)&W z?d>O1XlEXd*X4TMp>x?HMj$c=U;!*-aTaD|pT!yILsWRZE-pz-LR}no&bybu&UyC$ zJ3-w@hN=Q^gfATsyU0Lb7fs2Y7-We!Qml;vAC`APzL=U;9TO zj{$x&RYPJDa`@p2aODLxl-e>sP(De8t zfO8Lpp1F6D8cJ;}y`feRI0DFnI6@A{3XtMhf|PuIG74aq03@Rnm3d&QuCccFFkobv zcx~077myDffhj5=)SRb|3O<(OUQ8H)-&B*PGT{o)MKL0T9%ilpxqC)xz~&=!04Bow zo`vu^AVj4@QV5)3hrr6+o4|KL9PET1g{TPd&RLv>BeCvJ>~b4UM?LR$Qhksx{58br zuim5&l2hY(_iVmscEGd%#;BPJ(|S1u4%D)FrN9B`(0C$ojtt`@Xo9xQWjKrz|BKYJ z7Rr-uW1~Y|?<2G4r20JnSB_<}zWAA(mjk*3qr`UrI{Yv)5m&0Egumh22k)H_1>07C Y0p~FFp;yMMO8@`>07*qoM6N<$g825BF#rGn literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..216e2cd247bc20728eb1de0f4d04c94fab63d0fc GIT binary patch literal 783 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 literal 0 HcmV?d00001 diff --git a/Pictures/Simplified/PixelAmbrosiaLuck2.png b/Pictures/Simplified/PixelAmbrosiaLuck2.png new file mode 100644 index 0000000000000000000000000000000000000000..8f5f049f204e8d77fe2cee37a55a84cc733d7991 GIT binary patch literal 829 zcmV-D1H$}?P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0@6uDK~z{ry_dgh z6hRcnXO{%eoO^rziX=oNk|tnbbzCJ9NM#{nz{WXnPaW>i7Bmez_D#=Mbp$> z^RzyXPwIR1-=;HYZk7*)16XKpSk%mg`C{42_;vT7^5rRSaS+t-0^lFC!2FN{GKf&6 zSOj$=sa>!&jJlzI7EAzts3HMvKGqq8D$ZF2V`15+X{oWLI73MYWr4+RO*f3OFxvB@ zYng(8E-dn}QWAWQr1)KT%oq!!{m`1o90Z810YF1Oe!5?&r95Fqw$l=sfkBcO08+_D zLm`GI3)J$HW-YLmjvd$c8yo7`X498)EX4bid}uD4cU-6zY2+VUs~xrdecPKO!PxYR zuFwDFk&?dRxN3;{K3E(@Cf|8w#qaptn^)#}X7-$U0<61M{YX8fj@D18N)3g%tb;*- zp-$k)OK}vLQm`I{YVX-uY5TIkyJz9YiY5YA?fBX`9f2TN_rHn|;@JK3x2KG~|FUGn zA?y=RK_~!3h^VtK59}R3V9^C-S38s&4AoJ8v|z-XFgF+nKs7a<|h$b0}DUK)K&eBMth*r z`K$v7b08Sw-zD$?Ur{vx>}EIoZzzLcrz|WT;rwIgat%zbNfHOv(<9^hNvok=c3Pnc z!FR?^F#cfnu&I392|H?mgx+dOT|(z0Cc!2qewccZlBNa;e?MY$F|j9@emD$TU~v#00000NkvXX Hu0mjfEV_4# literal 0 HcmV?d00001 diff --git a/Pictures/Simplified/PixelAmbrosiaLuck3.png b/Pictures/Simplified/PixelAmbrosiaLuck3.png new file mode 100644 index 0000000000000000000000000000000000000000..f397639a56d685ed8276c45e157af56224dee51d GIT binary patch literal 831 zcmV-F1Hk-=P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizW@LZzX3P}QzQTY0@O)FK~z{ry_dgh z6hRcnXO{%eoO^rziX=oNk|tnbbzCJ9NM#{nz{WwgXQY)Ie zZkwm`d3;jetNu2fL36Ws$PQqkx#3VV6Xx^9ZpN?s2UQ?XS&M_PMmGTdK?}?e86bnO zD#anF8%gDYt6|i&`u$)6_(K&5Xz{VmAXM_sDi{mPK21xFE5!jNATk3ic5Aw3jD^vj zA6@G!25n@q9Hz{QxYEB9nVwS_wLS_vV#(o|!#oo&fJ%D}SV(Qb(&NRH=f(T-M**Q(y&v2(f3kD+P66nWFavFzt)>3y)XuCUOj_0#=`Sp@R5WS zfUJSVlT+rH@llfkQOG07?Or!zYzE}&*%&yxIP-~m%Cs>SH$REk8d&%-rmpI5G}-}` z&SxD!m;=EW|1N6l;MUv0e?uUHV5clB9pU_AnDwxdf94N z6T*AOPB8vp_OPjZ+zDZUxc4M;`#n9E_mTq$!;X{0)4~C`)rc*Kf>({S?^axrcn^em zw0hbI?}hkQzgIEDaOFaHFIEna{k}2)Q8pUdHQi%)K6k*nrLsb5nGE1V5jL}LB=aDk z!Fs^CQykT=HyfriXfEXoodD3`s*ED(sQNuV!-o?-vOL#Se*qC64Tc`8%I*LF002ov JPDHLkV1fl9bwdCE literal 0 HcmV?d00001 diff --git a/Pictures/Simplified/PixelBlueberry.png b/Pictures/Simplified/PixelBlueberry.png new file mode 100644 index 0000000000000000000000000000000000000000..82caf946ef082189d574d63eab707d3c91771c19 GIT binary patch literal 789 zcmV+w1M2*VP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0;)+wK~z{r#h1@( z6G0TmXV(PNrkljoRt>@5=t=CM`Uga*r=miNUcFSjc`W!3c<8}vbMa^o1(jk!Q4fL_ z>BWoSK~V%flt%NzB#@Xf-?uyKWV5rgk#79JV|FIf{l53+y-8#26i#s#1D0vJPr=lA zk4EEt{y4v1{Xvs)vz)Vs9Vq|$X}FKEu$0bu8NZX=#|H8gw>a=?cn*jUcpqAb5!s3G zN*M#>K+~$(Ps2+@&Fg95DL0j|0pt>~LZ3 zl1EU)5XacvZqi(ZHUmQR^E;c(9&t?N2$(7sSn90p&h$h&g4)-=FZ}kMF*pN*6LRzr z_eY$Vo@5^{K2qK=ef!$ZVHsv@extl-b(Y9~w0%O<4SPCKv92s?tSfYST+J${aiAc&c*(4&1b|>KcH! zsCL;vP}HI>#Ga@GIv~Ww*~`dI;PVS}G-Zk8D=N@YQD(sI>!9rrnTSph6eWuDU(mK8 zB7^yz0P?+n&M@}eqi0bgQ84TM%fOHP0z`%vFD}k|=|*<22cry*#J{G4GSCUR3*?^9 zA08Cwekjvi*y}gW+NahnZ5sjvZ>$~2^M{QZd(v(U{LzVtRh~FA+-48}LInG0!6m9V z+OU+in6YXf;+xIJkORQ~au8KOhj4(wfh(yg^%=wjG?9I67sScP--dDEwc$9ALDr%S z;D;itxOXykC!itpfU%OB;hU`nO~%djbjEQ2ld#JO#iAms`5B%J{wJHTOq2ZqPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0>4Q_K~z{ry_e5x z6G0TmXV(PNrupI8Rt=&4L{DN5)juFgJrxyF^eRY2ym&11AMoJ8Yjg2v4+WKCK~WEa z7wN@|;6YIYJ(NcC!z7THvER2dak9I!lN2@|c+9@p$$sB^^Jc?ZJNZ+bML^27#Z@ph z-lfs{m^;oNR(_E)YL>H(KY-Go-1=oax=xps zsZK4?sB-L_8>uM>1aLEz(f0tvWw)yag0hxT|s zMOy)9R|m%qnaS)VL0O_X_k!^lA~Tpb2%x?fa5AiY_vu>p$ROCY-IswE^#RBX4_;iH z@0APx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0=`K^K~z{ry_e5x z6G0TmXV(PNrupI8Rt=&4L{DN5)juFgJrxyF^eRY2ym&11AMoJ8Yjg2v4+WKCK~WEa z7wN@|;6YIYJ(NcC!z7THvER2daWcEJn-n%5c+9@p$$sB^^Jc?ZJNZ+bML^27#g#ub z-lfs{m^;oNR(_E)YL>H(H-OTg-F61gJrH zI>izQH*zR|hUiEjl8-EV9a|L#q5ylYz@e4%941^N(1m%nKonr;3it^hUAxRrzP?5# zraTyX0EnqR<`#B55A(|y;ut&I4f0KR0?>gVY;uP4TX#91opE||Vo4tpg*;1~b%YmA zXaJ!4{r>}h{ABFw2ZsznsM$kY&p0+U&OTp!V(clq((SUAVap)^@p9SqpKdVre#^bq zLDpgA)`9jw6_D`1%Vh1=OY+OF)@d}AJS=-)o3aN|;OYVmtkW)##S`=HgaAT1-)_9H zg2bh+^?W+dAJr;sy;<{Je0tVhDYrqA-Y(JTTq@G2vbAwAFl$g8OYuADY;XXkPM4Lb zPA$=>a_pQNX;=^l;ASdg?g5C)ZdVQXWi9(ct{D{H0HnCwdlfYZ+`lkKE{nzAP=gMO zu>#Jn4vrl%li5l9vP5(4h0tS&%wT#DKz%RZWLW#|)3xl8L9lDPF9RL*0muvwUR<2- zl^fN;8jLE~5`8WVsz5v7U7()%+>w5P&ZiRj(%!yv=e{&=haN+KytJIyznb#g|{^<>%&08Y@$ n2+d+56Y?1z5BS7L**5zJ0^e#KMBw?P00000NkvXXu0mjfC*5vW literal 0 HcmV?d00001 diff --git a/Pictures/Simplified/PixelCubes.png b/Pictures/Simplified/PixelCubes.png new file mode 100644 index 0000000000000000000000000000000000000000..4080f4e0c46b2bc08bf8b5d844dc390035f25b95 GIT binary patch literal 761 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0**;UK~z{r#g|WO z6G0fpXGf(rX_K^4DK#L1g;p;;2vNa{M=w%A3Ly z**fb}r^M6dmK+>34@=`w121-eI;xuqck-p6;`fSUtfx*{h=*TsSR*iymH1+#8EYbb zrxIgi$7TV&1@zDum^7D3iclr5NPKa8DRqud(0+;SStvz&18$Q zX##rz+Ptlf0|g#_@)f=2-LC2=%*@&Bwm<2$;YvUk5&H^I<}~6n)02M3<5=UfbGuw* z)yk0PzTi)KEykF~@BXCEVbw-}INQ3!hHt2e5VggZsuu+!$h2BPC1`PwdK2yyvl5gz z7>I%Tr?0Bli#9=t1KxC9))BFXU|+O}zSglOa|%yOE%XHBkS)#MoFZ5^~-{XN4BR6d%65RlQzN1=4`d?&HNTk?7uX zWdMlBWvIo?%gTf_fCp<48}Hxv?RvS(rYp=EROTjD18KzvLBs&WXP#YWXD=*R!xX2= zYJ)mee8;;C{wJ~me~i0eFIlDK(cF3KWrgI)O_+u>mlY+hk^cq#aBd^ndy+Wls{#<$ z4?fd4B;(rfiJrh*oVb4N&hzm}vD$92l}<}8)~A4?es?J`t2A6aIwG#*M(hUU3J-Hb z>i0beaS#}IQaUbbowl6RCb9Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0mMl}K~z{r#g|V? z!$1_qCj;W2S{p@Nlx_si-~qgVAc8k=t-BsV(6uLU<n!FAUjB0_d*7k^JVzODAJoWd@&G>EBSv13Rr*7c(^F6VL zt#IB+i;7?LwpFQ4ZHt4dMqwaUJi9ce8unC>k`|`GEsKOEu^1E3g!ZfgQ@bK1Ktx|B zY_*V&F#+_v#0jYh=py`^)j=Xo#8g6LAV!>!nh;l@EtYR!oMq}eP^sAR6QOa?u297-ayg{SuK|gP!~7bA3&tT_xST`tA`F?J zvbu0N52%8F7m#yi?%2|Dxd46xxEuT+S3<6|TrNPf0iSp?1KWz>4M@bf`5vj~S}uT| zH$DX1?IceRqMbk96|eb}y2k3Unf`~PsXx>1Oq xb++mT7D-_M9a@zfzOC8|{0(36%t%*j^#|1iDtCfz@&5n-002ovPDHLkV1hz#^Oyht literal 0 HcmV?d00001 diff --git a/Pictures/Simplified/PixelFreeUpgradeImprovement2.png b/Pictures/Simplified/PixelFreeUpgradeImprovement2.png new file mode 100644 index 0000000000000000000000000000000000000000..b8df10430ed6b358e7328234653a670331a56030 GIT binary patch literal 624 zcmV-$0+0QPP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0tHD#K~z{ry_da8 z13?hS_ZCD=%!eX^As~X!-~(9N2qM^6TWjY-2wM9DR)USCja{(z1+*0ni7_JNy#Km$ zZ1!e9PLup#xV_oAng7o1Wl8ed-b%$3s7a|uJiTj$vla=)u$inLP zMIv6ZD;_8do`aciz6`3%?|~Q*+gS|E1kb@tIG=%g6NW@kTTM8h2Xw*z6_9e~-Lb9Z zd;$Cduo@)fTFAAQ^967V@D+E{*4Jow0Wrn7_uUcC1z!N!%YF>Th+R2i$Oz6C;(E1} z?ky~pQauR{7HcVL`!}J+b<)|Ur*b%-jXDd;g2d)2NETDjCaMEwaw@JSEMnupx7HdZ z08nyYQV<&l_|wnatX^X6LmFdV3x+hLzoZLi3e+>YZqL0{c&W$9PI-Dh7- zfcvjOuyy}oXTFk)Kdjb^0%l1r05`NNIeedLBk(tT&a)S5Qi>mtZioPnoPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0yarRK~z{ry_e5Q z12GWBvk~!6TU$j0OD{^F!J8l+MG-_0U%<28dNHBDxdtXh9Cba#@?eEBxJ*+!4Gx?p{v#JM`6X^U9?M%UFDanO2_C;!cEWx^J4 z`1%~F!@jUpsHBc>m&aL;PyH?qm^D%XuHx~Iu+|CW%ur1!R1VN zi1GQ}u=*s|snblPfR0*`E>Hv(XZNZ>qrR|`IulYH;338P0n~*Ex&;8vN;+|rI9*c> zirIl>c5`(mokF)%lan9;rllw%ZhQw8S6!@ilSQxtCQ!f()s%}L3-~K|D~?&$Kpxuh7$a{^gIlv-W08Eu;ex!tb>{nl$|Yc3dJTk#m`nOV=)iRl zI#f<0dlC9XpshMo&H=dKehN@IaqmcLshkJ50GJI7NLff(OXWOd3vdso6(2T8YBQf5n06%6cMt6(z{^> zI4FDx-AnmbUX6owEIG;HfQ7--0Vj=fluAiXz@$H#oLQ)050D< zUh96t;?QU+exopE3;0h`0dRt=lEU?>tdE00000NkvXX Hu0mjfM;s=B literal 0 HcmV?d00001 diff --git a/Pictures/Simplified/PixelObtainium.png b/Pictures/Simplified/PixelObtainium.png new file mode 100644 index 0000000000000000000000000000000000000000..efb8ffcf321e64706dd9ddef71a76eafbf7bc1af GIT binary patch literal 529 zcmV+s0`C2ZP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0j5brK~z{ry_Y{r z#4s3#lYl6m=hYKL#6`G8KZQ68j(!7YadPtui0G)B;NmVWI=DDGxSWfhKse6h)Dwh8 ze`yojYtz4P?tzy!S)O0sCN1T?)sAEiXbKVDr8AViy7KPInmir!)nL*bdhKL@i_do+ z-a28g;hB!_w-#8ePp;))++hMtLavFrvUf^7&}v;)RDiE=M-n2BE+x~2v6@XmxRO6T zGj@N+)HN*xyeR5NVC4O`U;mmhCxbyY^R;Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0sKisK~z{ry_dgB z!$25@F9&LAt*s7<#YO4hqDx)6iMWfCgOiImDlYyJijLy$>>xNfxOK6Mf}@iZ9Hf?N zEfsS1{mjLrO)i&s?E^}K+A#rJcQ%vYyDhlAb>S3oly_WzzU-YoS@@gv0b4nsqqt{8v>TF#7A zK;fXZ)G;c-b;4_>W$LuoOLQ~=a?zrOfWl{sixh6ZR-DV`Pzfl*O$|esfHEBO0GN;n z5)k)?C1u(9Oxc(OZ`d|#i{Rg;AUmi6*2+nhRqr0CHLjjn`f=3x=#O3r zXQjlJ;30QU5@>~kiYwBKR{}#8M?&VRRspt4Y7nWtbc{;?m4KIlNT3S30w7WX1W3ph zNE`v6l#qBO(6Fq#1WLpe06qznJ_tzUHW%3B-Zm?(E{94a5df}4{roai0)*`)65i}? z1__CjkoyOgF}~ZS?@td^;5%d|)W9dS2l002ovPDHLkV1g?# B2zdYi literal 0 HcmV?d00001 diff --git a/Pictures/Simplified/PixelPixelGeneration.png b/Pictures/Simplified/PixelPixelGeneration.png new file mode 100644 index 0000000000000000000000000000000000000000..0e8992bb702ab5eeb503010f9a508e57b91fa3fc GIT binary patch literal 802 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 literal 0 HcmV?d00001 diff --git a/Pictures/Simplified/PixelPixelLuck.png b/Pictures/Simplified/PixelPixelLuck.png new file mode 100644 index 0000000000000000000000000000000000000000..03f421a6c6eb06f0f5c1786503616b148ce7d97a GIT binary patch literal 576 zcmV-G0>AxPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0o6%FK~z{r#aBU2 z!!QtZj3TO*(87UAh)X11!Us6=1I}>c5lC?6Av}d^&pjZB0wq#J0%PLJb?r^oY0F4f zlQxr??9MuB^m=w)i!C6LvN>`iuPgN#y_}}?WA>&_c8$Bq@w$Ph&-bV~+zPHolV!zk z#z$hMPF(Towyv?7(@wB8mIgw^XW2|(^)W#w#RDxqU(D4CF`=OhESf}ifhk^m7a}k7 zUM6H8@vz`hB0&bfSN3(T8PWc1UOiLQLW zn*n_jN*tl`1+$H>A@kqOzy}a1aU`3X4jyPGg9Bc88WSPnrk1Jz{wQKy z><`%{xZ=>zdO&nPIjNt&KGeysaWy*pGk_CnGonUy-10X(CJK~DDSiMb`2A(r=#Aq5 O0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz18Ye{K~z{ry_e5R zR8bVi?|V3Dj-!*Lg}7+UMbx687PD4YL9`JhvOpI?WMo9qU(lk0j3m&7EgYzzO^bxY z+_W)Js72<&w5@^FIR2QLoZEcQ-1EG?ci){U&<`Bu-gkd|&pG$p=hInfZk1veh`Fw6 znaRjJ{W^0^2|1YlL7lzkPP{(oz{vVfM>ThazG&Rb_(0tOu_I5rEe`w|o&)}Y{0+II zHsq?1x~az=wsHSnx|Xq0OyZ6G9YQx%81_o3s!RF{~p7!j%U+ah{Oj9y4k4KNTtT6or*N~dbr9D#GGnLZ%GNt_-V| znUWcpo_R#SHu2G=Q>s;j=kQt^Zl>@u@Po6$nY9eIh~%F>k$QVAAilM{xD!PJkDSx9Haf&#^_V;|$jy zmg5_1;#GFdo6Mh2{1t<1S=--+rpM~gl=pUonEuWHx&!|G0Ip$YG$sTbIA2v0I0Msn zq2C&woRbZgI|9#PY8her9)#xegH1B@2>jo0e3l&5%~V67%r|Ka=;J(x3Hu%l{cC6g z(LtPFPUW6;7|w%uqkNa$ppIS#HuMz#k2oLs+3K2N2Jnv}tgW&-a8@S5Qe6(vU_C$? z7~fo@&R)|MEkpnZ&@sJ?7!*qwbtV1{kC^L^h`Fx#3;Z)alqvWNbpQYW07*qoM6N<$ Ef|9P!PXGV_ literal 0 HcmV?d00001 diff --git a/Pictures/Simplified/PixelPixelLuckConverter2.png b/Pictures/Simplified/PixelPixelLuckConverter2.png new file mode 100644 index 0000000000000000000000000000000000000000..e06876055202367ee879f45be5c9ade90d35b1e4 GIT binary patch literal 982 zcmV;{11bE8P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz18Ye{K~z{ry_e5R zR8bVi?|V3Dj-!*Lg}7+UMbx687PD4YL9`JhvOpI?WMo9qU(lk0j3m&7EgYzzO^bxY z+_W)Js72<&w5@^FIR2QLoZEcQ-1EG?ci){U&<`Bu-gkd|&pG$p=hInfZk1veh`Fw6 znaRjJ{W^0^2|1YlL7lzkPP{(oz{vVfM>ThazG&Rb_(0tOu_I5rEe`w|o&)}Y{0+II zHsq?1x~az=wsHSnx|Xq0OyZ6G9YQx%81_o3s!RF{~p7!j%U+ah{Oj9y4k4KNTtT6or*N~dbr9D#GGnLZ%GNt_-V| znUWcpo_R#SHu2G=Q>s;j=kQt^Zl>@u@Po6$nY9eIh~%F>k$QVAAilM{xD!PJkDSx9Haf&#^_V;|$jy zmg5_1;#GFdo6Mh2{1t<1S=--+rpM~gl=pUonEuWHx&!|G0Ip$YG$sTbIA2v0I0Msn zq2C&woRbZgI|9#PY8her9)#xegH1B@2>jo0e3l&5%~V67%r|Ka=;J(x3Hu%l{cC6g z(LtPFPUW6;7|w%uqkNa$ppIS#HuMz#k2oLs+3K2N2Jnv}tgW&-a8@S5Qe6(vU_C$? z7~fo@&R)|MEkpnZ&@sJ?7!*qwbtV1{kC^L^h`Fx#3;Z)alqvWNbpQYW07*qoM6N<$ Ef|9P!PXGV_ literal 0 HcmV?d00001 diff --git a/Pictures/Simplified/PixelQuarks.png b/Pictures/Simplified/PixelQuarks.png new file mode 100644 index 0000000000000000000000000000000000000000..ade3b8857a063d769d42ab51540799aabdb2e200 GIT binary patch literal 744 zcmVP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0)0tDK~z{ry_d~v z6Hye!-#lz$l1`I0Vx@HB*FuEuyA@o!upr{zZoBLs;iB8R7gsLabmJf3Rs`)rDhN_2 z7-~$Kv{5ql+|GTxOy0+hIQ_w8zB2Eecix>Dl5|$@WU2&Gt@AxMy=+X|kGh|?pcccIk zIvixmReT*gQnXNfLfFSFMxcw5EWwoUt5JvQ!~QoaK4uC=g2W7vIKx5@hc&7n_u6#+ z{z0F%E+gjzO^BP&7G{n{XU4>@?;~@~HW4Faz|7t^plt@cs|}4wz9*J~?vBUmGz+Fg zU{DCy#k{Xp)ayn)KavA&UjkFJf79tw%)7@|r~pi08C>Gh6traaXtMRQ5!KU^0i9zb zY-V%u4{fEeZnO!x!_jQ0ySGxW821E{`Pdwrdqaqx0th4OwXUY}0a4U)rK+y&$DahG z5H;}W_B@H&vvYx^`0}+!!Yqz^V~7$cVy`CWJ>_M`-bR*jv^wrzbe&~l35x<^e zSf;&WZq(9jqmhc65Cc&f#YAkZ>-2l<_~2!q^(mMzQY^lX9SNbYVGI^3*36j4@X^(I z*#iFuY%NLve-u#Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0p>|WK~z{r#h1NK z!!Q(uogf6Xq$%Z3RFx1vFTudV3$P%uFu(vaV;_Nmff*JC28PbO07xv%Ou#~=3L&5& zv_&9lI3_nrTQ`lZCjF$V*j3bXeDAfb7%zoo&SJnaO>ZQ}?CxTkxoss~;K;7%eL15g>&5I^HtG~CD z;DAkQZO2B59H3;K6vsi& z+b{`C*Xw~KcS2B0WB?zEh_#Va>?WW=dcZi$&hU%IhnOVIW;*k402As;8DU%1?(rEu fY;->uEz@MbY@{T{tRS{E00000NkvXXu0mjfgHZBY literal 0 HcmV?d00001 diff --git a/Pictures/Simplified/PixelTutorial.png b/Pictures/Simplified/PixelTutorial.png new file mode 100644 index 0000000000000000000000000000000000000000..f36eb7c596908284740a4c99ca3a72b5c041bcb0 GIT binary patch literal 627 zcmV-(0*w8MP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0tiV&K~z{ry_d^M z!$25?Cj(;X#onNZ)P&%;zQf1n} zxw1Y(AA)#meTTK11&h@p+HZYU!-&cRH$W|SJE%~JgGRl`3Jj~J z1iC2F&B~+K5%+`fIwpYpw3q`z197A0=w?AH1C`fjR?>j>$75nUVv{<;++c95DhtpK z&A_bbj{=oN@8@H6(`_XK*Hx|o2@JXTQ+sz?auBh<=we({mYt3@B-i$E$|1iKaF|2|kpofm`}lktjeIh*A#&d)d6&07rDCico!&dIru)HRs;`yLMG3k^N zUCbuG9|J&x>j9R5&i9aY=FLHFvIt=S9obPx#1ZP1_K>z@;j|==^1poj532;bRa{vGizyJUazyWI3i3tDz0~bj|K~z{ry_Y>` z6j2bz->#91_ic)xa&ia?7J_BKPHp50twbam(Za^U6oP^lDMSdQh=qj~il?cp6ueS9 zAz~8|@uL#$BzTv*Z0-hn&Axs6aZ2t7%e?pQz5UOdH?zBEtycECY6~dXHnq&O z-9B3DrIQATf*gB*^l^aX{QRrDM@@~`Ojl&Mv^oqqyZ6- zUL_GHkj6m)&W z?d>O1XlEXd*X4TMp>x?HMj$c=U;!*-aTaD|pT!yILsWRZE-pz-LR}no&bybu&UyC$ zJ3-w@hN=Q^gfATsyU0Lb7fs2Y7-We!Qml;vAC`APzL=U;9TO zj{$x&RYPJDa`@p2aODLxl-e>sP(De8t zfO8Lpp1F6D8cJ;}y`feRI0DFnI6@A{3XtMhf|PuIG74aq03@Rnm3d&QuCccFFkobv zcx~077myDffhj5=)SRb|3O<(OUQ8H)-&B*PGT{o)MKL0T9%ilpxqC)xz~&=!04Bow zo`vu^AVj4@QV5)3hrr6+o4|KL9PET1g{TPd&RLv>BeCvJ>~b4UM?LR$Qhksx{58br zuim5&l2hY(_iVmscEGd%#;BPJ(|S1u4%D)FrN9B`(0C$ojtt`@Xo9xQWjKrz|BKYJ z7Rr-uW1~Y|?<2G4r20JnSB_<}zWAA(mjk*3qr`UrI{Yv)5m&0Egumh22k)H_1>07C Y0p~FFp;yMMO8@`>07*qoM6N<$g825BF#rGn literal 0 HcmV?d00001 diff --git a/Synergism.css b/Synergism.css index e170d65e9..39836b994 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; @@ -1961,7 +1967,8 @@ p#reincarnatehotkeys { #goldenQuarksDisplay, #octeractsDisplay, #totalOcteractsDisplay, -#ambrosiaDisplay { +#ambrosiaDisplay, +#ultimatePixelDisplay { display: flex; flex-direction: row; align-items: center; @@ -1993,7 +2000,8 @@ p#reincarnatehotkeys { margin-left: 5px; } -#ambrosiaAmount { +#ambrosiaAmount, +#ultimatePixelAmount { font-size: 1.2em; margin-left: 5px; } @@ -3523,7 +3531,8 @@ header #obtainiumDisplay { color: pink; } #singularityUpgradeContainer, #singularityOcteracts, -#singularityAmbrosia { +#singularityAmbrosia, +#singularityUltimatePixels { display: flex; flex-direction: column; align-items: center; @@ -3531,7 +3540,9 @@ header #obtainiumDisplay { color: pink; } #actualSingularityUpgradeContainer, #octeractUpgradeContainer, -#blueberryUpgradeContainer { +#blueberryUpgradeContainer, +#pixelUpgradeContainer { + position: relative; display: flex; flex-wrap: wrap; justify-content: center; @@ -3557,7 +3568,8 @@ header #obtainiumDisplay { color: pink; } .singularityUpgrade, .octeractUpgrade, .singularityChallenge, -.blueberryUpgrade { +.blueberryUpgrade, +.pixelUpgrade { font-size: 0; cursor: pointer; } @@ -3789,6 +3801,12 @@ img#singularityPerksIcon { text-align: center; } +#testing { + position: relative; + padding: 0; + text-align: center; +} + @keyframes rotation { from { transform: rotate(0deg); @@ -3872,6 +3890,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 +3933,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 +3984,85 @@ 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; +} diff --git a/index.html b/index.html index 960f08b84..68a559abb 100644 --- a/index.html +++ b/index.html @@ -106,6 +106,14 @@ +
+ + +
+
+ + +
@@ -873,9 +881,13 @@ Notification +
+ + +
-
- +
+
@@ -903,20 +915,6 @@ - - - - - - - - - - - - - - @@ -945,20 +943,6 @@ - - - - - - - - - - - - - - @@ -987,20 +971,6 @@ - - - - - - - - - - - - - - @@ -1029,20 +999,6 @@ - - - - - - - - - - - - - - @@ -1071,20 +1027,6 @@ - - - - - - - - - - - - - - @@ -1113,20 +1055,6 @@ - - - - - - - - - - - - - - @@ -1155,23 +1083,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 +2834,10 @@
- - - - - - - + - - + + @@ -2807,11 +2845,17 @@ - - + + - + + + + + + +
@@ -2820,28 +2864,28 @@ - + - + - + - + - + - + - + - + @@ -3068,6 +3112,8 @@

Artists

+ +
@@ -3155,8 +3201,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 +3620,10 @@

Artists

a0

a0

a0

+

a0

+

a0

+

a0

+

a0

Multipliers (Additive)0

TOTAL AMBROSIA LUCK: 0

@@ -3586,10 +3641,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 +4152,9 @@

Artists

- + + +
@@ -4078,6 +4163,9 @@

Artists

+
+

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

+

@@ -4286,6 +4374,12 @@

Artists

+
+ +
+
+ +
@@ -4442,6 +4536,12 @@

Artists

+
+ +
+
+ +
@@ -4457,9 +4557,7 @@

Artists

-

-

@@ -4467,10 +4565,6 @@

Artists

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

Artists

+
+ +
@@ -4530,6 +4627,14 @@

Artists

+
+ +
+
+
+
+ +
@@ -4554,6 +4659,142 @@

Artists

+
@@ -4561,5 +4802,9 @@

Artists

+ +
+

Welcome to the exclusive testing realm!

+
diff --git a/package.json b/package.json index 919689051..aeab8a3c5 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", diff --git a/src/Achievements.ts b/src/Achievements.ts index 95ad7cbc9..bec7331e0 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,7 @@ 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..714ed36dd 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' @@ -8,8 +13,8 @@ import { getQuarkBonus } from './Quark' import { format, player } from './Synergism' import type { Player } from './types/Synergism' import { Alert, Confirm, Prompt } from './UpdateHTML' -import { visualUpdateAmbrosia } from './UpdateVisuals' import { Globals as G } from './Variables' +import { visualUpdateAmbrosia } from './UpdateVisuals' export type blueberryUpgradeNames = | 'ambrosiaTutorial' @@ -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..1988325df 100644 --- a/src/Calculate.ts +++ b/src/Calculate.ts @@ -7,6 +7,7 @@ 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' @@ -19,6 +20,7 @@ import type { resetNames } from './types/Synergism' import { Alert, Prompt } from './UpdateHTML' import { productContents, sumContents } from './Utility' import { Globals as G } from './Variables' +import type { Corruptions } from './Corruptions' const CASH_GRAB_ULTRA_QUARK = 0.08 const CASH_GRAB_ULTRA_CUBE = 1.2 @@ -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..0224d26aa --- /dev/null +++ b/src/Campaign.ts @@ -0,0 +1,138 @@ +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..3244ecb88 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..bdb749245 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,47 +322,27 @@ 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'), description: i18next.t('corruptions.exitCorruption.description'), @@ -93,34 +353,19 @@ 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) - }), - planned: i18next.t(`corruptions.prototypeLevel.${index - 1}`, { - level: format(player.prototypeCorruptions[index]) + bonusText, - effect: format(corruptEffectValues[index - 2][player.prototypeCorruptions[index]], 3) - }), - 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 - ) - }), - 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]}` + 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.${corr}`, {level: player.corruptions.next.getLevel(corr), effect: player.corruptions.next.corruptionEffects(corr)}), + multiplier: i18next.t('corruptions.scoreMultiplier', {curr: player.corruptions.used.scoreMult(corr), next: player.corruptions.next.scoreMult(corr)}), + 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 +375,28 @@ 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 +408,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 +425,176 @@ 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]) + else { + 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)) - - for (const value of newCorruptions) { - if ( - !Number.isInteger(value) - || Number.isNaN(value) - || value < 0 - || value > maxCorruptionLevel() - ) { - return false - } - } + let corr:Corruptions + if (!corruptions) { + return false + } - player.prototypeCorruptions = newCorruptions - corruptionLoadoutTableUpdate() + console.log(corruptions) + + 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 +614,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 +624,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 +683,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..81b52bee2 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,9 @@ 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 +956,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 +1075,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 +1099,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 +1206,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..a84afc768 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,31 @@ 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/Octeracts.ts b/src/Octeracts.ts index f9a27bf7d..0dda2dfb6 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..3fbb5580a 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,11 @@ 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 +1140,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 +1214,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 +1309,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..62ed60769 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,10 @@ 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 { getFastForwardTotalMultiplier, singularityData, SingularityUpgrade } from './singularity' import { SingularityChallenge, singularityChallengeData } from './SingularityChallenges' import { @@ -168,12 +168,16 @@ import { AmbrosiaLuckAdditiveMultCache, AmbrosiaLuckCache, BlueberryInventoryCache, - cacheReinitialize + cacheReinitialize, + UltimatePixelGenerationCache, + UltimatePixelLuckAdditiveMultCache, + UltimatePixelLuckCache } from './StatCache' import { changeSubTab, changeTab, Tabs } from './Tabs' import { settingAnnotation, toggleIconSet, toggleTheme } from './Themes' import { clearTimeout, clearTimers, setInterval, setTimeout } from './Timers' import type { PlayerSave } from './types/LegacySynergism' +import { playerUpdateVarSchema } from './saves/PlayerUpdateVarSchema' export const player: Player = { firstPlayed: new Date().toISOString(), @@ -468,7 +472,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 +862,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 +901,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 +1231,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 +1390,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 +1503,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 +1532,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, { @@ -1511,7 +1597,81 @@ export const saveSynergy = async (button?: boolean): Promise => { player.loaded1009 = true player.loaded1009hotfix1 = true - const p = playerJsonSchema.parse(player) + // shallow hold, doesn't modify OG object nor is affected by modifications to OG + const p = Object.assign({}, player, { + codes: Array.from(player.codes), + worlds: Number(player.worlds), + wowCubes: Number(player.wowCubes), + wowTesseracts: Number(player.wowTesseracts), + wowHypercubes: Number(player.wowHypercubes), + wowPlatonicCubes: Number(player.wowPlatonicCubes), + singularityUpgrades: Object.fromEntries( + Object.entries(player.singularityUpgrades).map(([key, value]) => { + return [ + key, + { + level: value.level, + goldenQuarksInvested: value.goldenQuarksInvested, + toggleBuy: value.toggleBuy, + freeLevels: value.freeLevels + } + ] + }) + ), + octeractUpgrades: Object.fromEntries( + Object.entries(player.octeractUpgrades).map(([key, value]) => { + return [ + key, + { + level: value.level, + octeractsInvested: value.octeractsInvested, + toggleBuy: value.toggleBuy, + freeLevels: value.freeLevels + } + ] + }) + ), + pixelUpgrades: Object.fromEntries( + Object.entries(player.pixelUpgrades).map(([key, value]) => { + return [ + key, + { + level: value.level, + pixelsInvested: value.pixelsInvested, + toggleBuy: value.toggleBuy, + freeLevels: value.freeLevels + } + ] + }) + ), + singularityChallenges: Object.fromEntries( + Object.entries(player.singularityChallenges).map(([key, value]) => { + return [ + key, + { + completions: value.completions, + highestSingularityCompleted: value.highestSingularityCompleted, + enabled: value.enabled + } + ] + }) + ), + blueberryUpgrades: Object.fromEntries( + Object.entries(player.blueberryUpgrades).map(([key, value]) => { + return [ + key, + { + level: value.level, + ambrosiaInvested: value.ambrosiaInvested, + blueberriesInvested: value.blueberriesInvested, + toggleBuy: value.toggleBuy, + freeLevels: value.freeLevels + } + ] + }) + ) + }) + const save = btoa(JSON.stringify(p)) if (save !== null) { @@ -1579,7 +1739,7 @@ const loadSynergy = async () => { }) } - const validatedPlayer = playerSchema.safeParse(data) + const validatedPlayer = playerUpdateVarSchema.safeParse(data) if (validatedPlayer.success) { Object.assign(player, validatedPlayer.data) @@ -2059,22 +2219,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 +2382,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 +3434,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 +3677,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 +3869,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 +3884,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 +4690,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 +4699,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 +4725,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 +4824,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 +4839,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 +5114,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 +5938,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 +6026,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 +6198,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() } diff --git a/src/Tabs.ts b/src/Tabs.ts index fb88814b1..620e9f558 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,24 @@ 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 +284,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 +580,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/Toggles.ts b/src/Toggles.ts index 8194e4d26..9d0177ce5 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,11 @@ 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 +958,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..b2c5ad510 100644 --- a/src/UpdateHTML.ts +++ b/src/UpdateHTML.ts @@ -24,10 +24,12 @@ import { visualUpdateSettings, visualUpdateShop, visualUpdateSingularity, + visualUpdateTesting, visualUpdateUpgrades } from './UpdateVisuals' import { createDeferredPromise } from './Utility' import { Globals as G } from './Variables' +import { toggleAchievementScreen } from './Toggles' export const revealStuff = () => { const example = document.getElementsByClassName('coinunlock1') as HTMLCollectionOf @@ -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,8 @@ 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 +694,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 +714,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 +1025,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 +1092,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 +1145,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..08b5a29ae 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..bb9b7faac 100644 --- a/src/Utility.ts +++ b/src/Utility.ts @@ -192,3 +192,8 @@ export const deepClone = (value: unknown) => { return value }) } + + +export const validateNonnegativeInteger = (n: number | string):boolean => { + return Number.isFinite(n) && !Number.isNaN(n) && Number.isInteger(n) +} \ No newline at end of file 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..cede71b10 100644 --- a/src/saves/PlayerJsonSchema.ts +++ b/src/saves/PlayerJsonSchema.ts @@ -1,6 +1,20 @@ import { z } from 'zod' import type { Player } from '../types/Synergism' import { playerSchema } from './PlayerSchema' +import type { Corruptions } from '../Corruptions' + +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)), @@ -10,6 +24,19 @@ 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 +97,53 @@ 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 - dayCheck: z.any().transform((dayCheck: Player['dayCheck']) => dayCheck?.toISOString() ?? null) + return player }) diff --git a/src/saves/PlayerSchema.ts b/src/saves/PlayerSchema.ts index bedbef91b..5d6a972f9 100644 --- a/src/saves/PlayerSchema.ts +++ b/src/saves/PlayerSchema.ts @@ -4,12 +4,14 @@ import { BlueberryUpgrade, blueberryUpgradeData } from '../BlueberryUpgrades' 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' import { blankSave } from '../Synergism' import type { Player } from '../types/Synergism' import { deepClone, padArray } from '../Utility' +import { CorruptionLoadout, CorruptionSaves } from '../Corruptions' const decimalSchema = z.custom((value) => { try { @@ -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')) +}) \ No newline at end of file diff --git a/src/saves/PlayerUpdateVarSchema.ts b/src/saves/PlayerUpdateVarSchema.ts new file mode 100644 index 000000000..358fe867f --- /dev/null +++ b/src/saves/PlayerUpdateVarSchema.ts @@ -0,0 +1,47 @@ +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 +}) \ No newline at end of file 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..aeee5442f 100644 --- a/src/types/Synergism.d.ts +++ b/src/types/Synergism.d.ts @@ -4,6 +4,7 @@ import type { WowCubes, WowHypercubes, WowPlatonicCubes, WowTesseracts } from '. 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,9 +13,13 @@ import type { AmbrosiaGenerationCache, AmbrosiaLuckAdditiveMultCache, AmbrosiaLuckCache, - BlueberryInventoryCache + BlueberryInventoryCache, + UltimatePixelGenerationCache, + UltimatePixelLuckAdditiveMultCache, + UltimatePixelLuckCache } from '../StatCache' import type { Tabs } from '../Tabs' +import type { CorruptionLoadout, Corruptions, CorruptionSaves } from '../Corruptions' type ArrayStartingWithNull = [null, ...T[]] @@ -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", From 90597d5a77daf2a1165612d26bc0632bad34593e Mon Sep 17 00:00:00 2001 From: Khafra Date: Wed, 6 Nov 2024 19:01:49 -0500 Subject: [PATCH 2/3] add fake login support during testing --- index.html | 10 ++ src/Achievements.ts | 3 +- src/BlueberryUpgrades.ts | 2 +- src/Calculate.ts | 4 +- src/Campaign.ts | 213 ++++++++++++++--------------- src/Challenges.ts | 6 +- src/Corruptions.ts | 176 ++++++++++++------------ src/EventListeners.ts | 7 +- src/History.ts | 13 +- src/Login.ts | 93 +++++++------ src/Octeracts.ts | 4 +- src/Reset.ts | 3 +- src/Synergism.ts | 93 ++----------- src/Tabs.ts | 7 +- src/Test.ts | 22 +++ src/Toggles.ts | 1 - src/UpdateHTML.ts | 3 +- src/UpdateVisuals.ts | 4 +- src/Utility.ts | 9 +- src/saves/PlayerJsonSchema.ts | 21 +-- src/saves/PlayerSchema.ts | 4 +- src/saves/PlayerUpdateVarSchema.ts | 39 +++--- src/types/Synergism.d.ts | 2 +- 23 files changed, 352 insertions(+), 387 deletions(-) create mode 100644 src/Test.ts diff --git a/index.html b/index.html index 68a559abb..229128558 100644 --- a/index.html +++ b/index.html @@ -4805,6 +4805,16 @@

Artists

Welcome to the exclusive testing realm!

+ + + +
diff --git a/src/Achievements.ts b/src/Achievements.ts index bec7331e0..ca05eba63 100644 --- a/src/Achievements.ts +++ b/src/Achievements.ts @@ -310,7 +310,8 @@ export const challengeachievementcheck = (i: number, auto?: boolean) => { } if ( - player.challengecompletions[10] >= 50 && i === 11 && player.corruptions.used.getLevel('drought') >= 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/BlueberryUpgrades.ts b/src/BlueberryUpgrades.ts index 714ed36dd..01446f1fe 100644 --- a/src/BlueberryUpgrades.ts +++ b/src/BlueberryUpgrades.ts @@ -13,8 +13,8 @@ import { getQuarkBonus } from './Quark' import { format, player } from './Synergism' import type { Player } from './types/Synergism' import { Alert, Confirm, Prompt } from './UpdateHTML' -import { Globals as G } from './Variables' import { visualUpdateAmbrosia } from './UpdateVisuals' +import { Globals as G } from './Variables' export type blueberryUpgradeNames = | 'ambrosiaTutorial' diff --git a/src/Calculate.ts b/src/Calculate.ts index 1988325df..dce3a0d6f 100644 --- a/src/Calculate.ts +++ b/src/Calculate.ts @@ -3,6 +3,7 @@ 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' @@ -20,7 +21,6 @@ import type { resetNames } from './types/Synergism' import { Alert, Prompt } from './UpdateHTML' import { productContents, sumContents } from './Utility' import { Globals as G } from './Variables' -import type { Corruptions } from './Corruptions' const CASH_GRAB_ULTRA_QUARK = 0.08 const CASH_GRAB_ULTRA_CUBE = 1.2 @@ -2833,7 +2833,7 @@ export const calculateAscensionScore = () => { + 0.0025 * (player.platonicUpgrades[5] + player.platonicUpgrades[10]), player.highestchallengecompletions[10] ) - + corruptionMultiplier = player.corruptions.used.getTotalScore() const bonusMultiplier = computeAscensionScoreBonusMultiplier() diff --git a/src/Campaign.ts b/src/Campaign.ts index 0224d26aa..f4719bb86 100644 --- a/src/Campaign.ts +++ b/src/Campaign.ts @@ -1,6 +1,6 @@ -import i18next from "i18next" -import { CorruptionLoadout, type Corruptions } from "./Corruptions" -import { player } from "./Synergism" +import i18next from 'i18next' +import { CorruptionLoadout, type Corruptions } from './Corruptions' +import { player } from './Synergism' export type AscensionModifiers = 'GlobalSpeed' @@ -10,129 +10,122 @@ export type CampaignModifiers = Partial> export type CampaignKeys = 'test1' | 'test2' | 'test3' export interface ICampaignManagerData { - currentCampaign: CampaignKeys | undefined - campaigns: Record + currentCampaign: CampaignKeys | undefined + campaigns: Record } export interface ICampaignData { - campaignLoadout: CampaignLoadout, - campaignModifiers: CampaignModifiers, - limit: number, - isMeta: boolean - c10Completions?: number + 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() + 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) } - 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 { + const currentKey = campaignManagerData.currentCampaign - // 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 + if (currentKey !== undefined) { + this.currentCampaign = this.campaigns[currentKey] + player.corruptions.used = this.currentCampaign.createUsableLoadout() + } else { + this.currentCampaign = undefined } - public computeTokenValue = () => { - const metaMultiplier = this.isMeta ? 2: 1 - return metaMultiplier * Math.min(this.c10Completions, this.limit) - } + this.totalCampaignTokens = this.computeTotalCampaignTokens() + } - 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 + 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, + test1: { + campaignLoadout: { + viscosity: 1 }, - test2: { - campaignLoadout: { - 'viscosity': 1, - 'deflation': 1 - }, - campaignModifiers: { - 'GlobalSpeed': 1 - }, - isMeta: true, - limit: 15, + campaignModifiers: { + GlobalSpeed: 1 }, - test3: { - campaignLoadout: { - 'viscosity': 1, - 'deflation': 1, - 'dilation': 1, - }, - campaignModifiers: { - 'GlobalSpeed': 1 - }, - isMeta: true, - limit: 20, - } -} + 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 3244ecb88..f62470e12 100644 --- a/src/Challenges.ts +++ b/src/Challenges.ts @@ -403,9 +403,9 @@ export const calculateChallengeRequirementMultiplier = ( completions: number, special = 0 ) => { - let requirementMultiplier = (type === 'ascension') ? - 1: - player.corruptions.used.corruptionEffects('hyperchallenge') + let requirementMultiplier = (type === 'ascension') + ? 1 + : player.corruptions.used.corruptionEffects('hyperchallenge') switch (type) { case 'transcend': requirementMultiplier *= G.challenge15Rewards.transcendChallengeReduction diff --git a/src/Corruptions.ts b/src/Corruptions.ts index bdb749245..896ee0849 100644 --- a/src/Corruptions.ts +++ b/src/Corruptions.ts @@ -7,8 +7,8 @@ import { Alert, Prompt } from './UpdateHTML' 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 corruptions = ['viscosity', 'drought', 'deflation', 'extinction', 'illiteracy', 'recession', 'dilation', 'hyperchallenge'] as const +// export type Corruptions = typeof corruptions[number] export const convertInputToCorruption = (array: number[]): Corruptions => { return { @@ -19,22 +19,22 @@ export const convertInputToCorruption = (array: number[]): Corruptions => { deflation: array[4], extinction: array[5], drought: array[6], - recession: array[7], + recession: array[7] } } export type Corruptions = { - viscosity: number, - drought: number, - deflation: number, - extinction: number, - illiteracy: number, - recession: number, - dilation: number, + viscosity: number + drought: number + deflation: number + extinction: number + illiteracy: number + recession: number + dilation: number hyperchallenge: number } -export const c15Corruptions:Corruptions = { +export const c15Corruptions: Corruptions = { viscosity: 11, drought: 11, deflation: 11, @@ -42,13 +42,13 @@ export const c15Corruptions:Corruptions = { illiteracy: 11, recession: 11, dilation: 11, - hyperchallenge: 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 = { + #levels: Corruptions = { viscosity: 0, drought: 0, deflation: 0, @@ -64,19 +64,21 @@ export class CorruptionLoadout { Object.assign(this.#levels, p) } - public setCorruptionLevels(corruptions: Partial) { + public setCorruptionLevels (corruptions: Partial) { Object.assign(this.#levels, corruptions) this.clipCorruptionLevels() this.#totalScoreMult = this.#calcTotalScoreMult() this.#bonusLevels = this.#calcBonusLevels() } - public setCorruptionLevelsWithChallengeRequirement(corruptions: Partial) { + 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) { + if ( + player.challengecompletions[corrChallengeMinimum(corrKey)] === 0 + && !player.singularityUpgrades.platonicTau.getEffect().bonus + ) { this.setLevel(corrKey, 0) } } @@ -85,13 +87,13 @@ export class CorruptionLoadout { this.#totalScoreMult = this.#calcTotalScoreMult() } - public clipCorruptionLevels() { + 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 @@ -102,73 +104,72 @@ export class CorruptionLoadout { } } - public calculateIndividualRawMultiplier(corr: keyof Corruptions) { - + public calculateIndividualRawMultiplier (corr: keyof Corruptions) { let bonusVal = player.singularityUpgrades.advancedPack.getEffect().bonus - ? 0.33 - : 0 + ? 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 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) + 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() { + #viscosityEffect () { const base = G.viscosityPower[this.#levels.viscosity] const multiplier = 1 + player.platonicUpgrades[6] return Math.min(base * multiplier, 1) } - #droughtEffect() { + #droughtEffect () { return G.droughtMultiplier[this.#levels.drought] } - #deflationEffect() { + #deflationEffect () { return G.deflationMultiplier[this.#levels.deflation] } - #extinctionEffect() { + #extinctionEffect () { return G.extinctionMultiplier[this.#levels.extinction] } - #illiteracyEffect() { + #illiteracyEffect () { const base = G.illiteracyPower[this.#levels.illiteracy] - const multiplier = (1 + (9 / 100) * player.platonicUpgrades[9] * Math.min(100, Math.log10(player.researchPoints + 10))) + const multiplier = 1 + + (9 / 100) * player.platonicUpgrades[9] * Math.min(100, Math.log10(player.researchPoints + 10)) return Math.min(base * multiplier, 1) } - #recessionEffect() { + #recessionEffect () { return G.recessionPower[this.#levels.recession] } - #dilationEffect() { + #dilationEffect () { return G.dilationMultiplier[this.#levels.dilation] } - #hyperchallengeEffect() { + #hyperchallengeEffect () { const baseEffect = G.hyperchallengeMultiplier[this.#levels.hyperchallenge] let divisor = 1 - divisor *= (1 + 2/5 * player.platonicUpgrades[8]) + divisor *= 1 + 2 / 5 * player.platonicUpgrades[8] return Math.max(1, baseEffect / divisor) } - corruptionEffects(corr: keyof Corruptions) { - switch(corr) { + corruptionEffects (corr: keyof Corruptions) { + switch (corr) { case 'deflation': { return this.#deflationEffect() } @@ -196,54 +197,55 @@ export class CorruptionLoadout { } } - get totalLevels() { + get totalLevels () { return sumContents(Object.values(this.#levels)) } - #calcBonusLevels() { + #calcBonusLevels () { let bonusLevel = (player.singularityUpgrades.corruptionFifteen.level > 0) ? 1 : 0 bonusLevel += +player.singularityChallenges.oneChallengeCap.rewards.freeCorruptionLevel return bonusLevel } - public scoreMult(corruption: keyof Corruptions) { + public scoreMult (corruption: keyof Corruptions) { if (corruption !== 'viscosity') { return this.calculateIndividualRawMultiplier(corruption) - } - else { + } 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 + 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) - })) + #calcTotalScoreMult () { + return productContents( + Object.keys(this.#levels).map((key) => { + const corrKey = key as keyof Corruptions + return this.scoreMult(corrKey) + }) + ) } - getLevel(corr: keyof Corruptions) { + getLevel (corr: keyof Corruptions) { return this.#levels[corr] } - getLoadout() { + getLoadout () { return this.#levels } - getBonusLevel() { + getBonusLevel () { return this.#bonusLevels } - setLevel(corr: keyof Corruptions, newLevel: number) { + setLevel (corr: keyof Corruptions, newLevel: number) { this.#levels[corr] = newLevel } - resetCorruptions() { + resetCorruptions () { for (const corr in this.#levels) { const corrKey = corr as keyof Corruptions this.setLevel(corrKey, 0) @@ -253,7 +255,7 @@ export class CorruptionLoadout { corruptionLoadoutTableUpdate(true, 0) } - incrementDecrementLevel(corr: keyof Corruptions, val: number) { + incrementDecrementLevel (corr: keyof Corruptions, val: number) { const level = this.getLevel(corr) const minLevel = 0 const maxLevel = maxCorruptionLevel() @@ -262,29 +264,27 @@ export class CorruptionLoadout { this.setLevel(corr, newLevel) } - - getTotalScore() { + getTotalScore () { return this.#totalScoreMult } - } export type SavedCorruption = { name: string - loadout: CorruptionLoadout + 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])}) + for (const saveKey of Object.keys(corrSaveData).slice(0, 8)) { + this.#saves.push({ name: saveKey, loadout: new CorruptionLoadout(corrSaveData[saveKey]) }) } } - getSaves() { + getSaves () { return this.#saves - } + } } export const maxCorruptionLevel = () => { @@ -333,8 +333,6 @@ const corrIcons: Record = { hyperchallenge: '/CorruptHyperchallenge.png' } - - export const corruptionDisplay = (corr: keyof Corruptions | 'exit') => { if (DOMCacheGetOrSet('corruptionDetails').style.visibility !== 'visible') { DOMCacheGetOrSet('corruptionDetails').style.visibility = 'visible' @@ -342,7 +340,7 @@ export const corruptionDisplay = (corr: keyof Corruptions | 'exit') => { if (DOMCacheGetOrSet('corruptionSelectedPic').style.visibility !== 'visible') { DOMCacheGetOrSet('corruptionSelectedPic').style.visibility = 'visible' } - + let text = { name: i18next.t('corruptions.exitCorruption.name'), description: i18next.t('corruptions.exitCorruption.description'), @@ -358,10 +356,19 @@ export const corruptionDisplay = (corr: keyof Corruptions | 'exit') => { text = { 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.${corr}`, {level: player.corruptions.next.getLevel(corr), effect: player.corruptions.next.corruptionEffects(corr)}), - multiplier: i18next.t('corruptions.scoreMultiplier', {curr: player.corruptions.used.scoreMult(corr), next: player.corruptions.next.scoreMult(corr)}), - spiritContribution: i18next.t('corruptions.spiritEffect', {curr: 1, next: 1}), + current: i18next.t(`corruptions.currentLevel.${corr}`, { + level: player.corruptions.used.getLevel(corr), + effect: player.corruptions.used.corruptionEffects(corr) + }), + planned: i18next.t(`corruptions.prototypeLevel.${corr}`, { + level: player.corruptions.next.getLevel(corr), + effect: player.corruptions.next.corruptionEffects(corr) + }), + multiplier: i18next.t('corruptions.scoreMultiplier', { + curr: player.corruptions.used.scoreMult(corr), + next: player.corruptions.next.scoreMult(corr) + }), + 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)) @@ -378,7 +385,6 @@ export const corruptionDisplay = (corr: keyof Corruptions | 'exit') => { } export const corruptionStatsUpdate = () => { - for (const corr in player.corruptions.used.getLoadout()) { const corrKey = corr as keyof Corruptions // https://discord.com/channels/677271830838640680/706329553639047241/841749032841379901 @@ -387,7 +393,6 @@ export const corruptionStatsUpdate = () => { a.textContent = format(player.corruptions.used.getLevel(corrKey)) b.textContent = format(player.corruptions.next.getLevel(corrKey)) } - } export const corruptionButtonsAdd = () => { @@ -505,7 +510,7 @@ export const corruptionLoadoutTableCreate = () => { // Title Cell const titleCell = row.insertCell() titleCell.className = `test${'Title'}` - titleCell.title = i18next.t('corruptions.loadoutTable.otherRowTitle', { value : i + 1 }) + titleCell.title = i18next.t('corruptions.loadoutTable.otherRowTitle', { value: i + 1 }) console.log(corrLoadout) for (const corr in corrLoadout) { const corrKey = corr as keyof Corruptions @@ -541,8 +546,7 @@ export const corruptionLoadoutTableUpdate = (updateNext = false, updateRow = 0) row[index + 1].textContent = corrNext[corrKey].toString() index += 1 } - } - else { + } else { const corrSaves = player.corruptions.saves.getSaves()[updateRow - 1]?.loadout.getLoadout() let index = 0 for (const corr in corrSaves) { @@ -567,7 +571,7 @@ export const corruptionLoadLoadout = (loadoutNum: number) => { } export const applyCorruptions = (corruptions: string) => { - let corr:Corruptions + let corr: Corruptions if (!corruptions) { return false } @@ -576,8 +580,7 @@ export const applyCorruptions = (corruptions: string) => { if (corruptions.includes('/') && corruptions.split('/').length === 8) { corr = convertInputToCorruption(corruptions.split('/').map(Number)) - } - else { + } else { corr = JSON.parse(corruptions) as Corruptions } @@ -588,7 +591,6 @@ export const applyCorruptions = (corruptions: string) => { return true } return false - } async function importCorruptionsPrompt () { diff --git a/src/EventListeners.ts b/src/EventListeners.ts index 81b52bee2..445836ac0 100644 --- a/src/EventListeners.ts +++ b/src/EventListeners.ts @@ -398,7 +398,7 @@ export const generateEventHandlers = () => { for (let index = 0; index < 2; index++) { DOMCacheGetOrSet(`toggleAchievementSubTab${index + 1}`).addEventListener( 'click', - () => changeSubTab(Tabs.Achievements, {page: index}) + () => changeSubTab(Tabs.Achievements, { page: index }) ) } @@ -847,7 +847,10 @@ export const generateEventHandlers = () => { // Part 1: Displays DOMCacheGetOrSet('corruptionDisplays').addEventListener('click', () => corruptionDisplay('exit')) DOMCacheGetOrSet('corruptionCleanse').addEventListener('click', () => corruptionCleanseConfirm()) - DOMCacheGetOrSet('corruptionCleanseConfirm').addEventListener('click', () => toggleCorruptionLevel('illiteracy', 999, true)) + DOMCacheGetOrSet('corruptionCleanseConfirm').addEventListener( + 'click', + () => toggleCorruptionLevel('illiteracy', 999, true) + ) // Extra toggle DOMCacheGetOrSet('ascensionAutoEnable').addEventListener('click', () => toggleAutoAscend(0)) diff --git a/src/History.ts b/src/History.ts index a84afc768..277c08f0c 100644 --- a/src/History.ts +++ b/src/History.ts @@ -322,7 +322,7 @@ const resetHistoryTableMapping: Record = { } type corruptionInfo = { - image: string, + image: string title: string } @@ -334,7 +334,7 @@ const resetHistoryCorruptionInfo: Record = { }, dilation: { image: 'CorruptDilation.png', - title: 'Spacial Dilation [Time]', + title: 'Spacial Dilation [Time]' }, hyperchallenge: { image: 'CorruptHyperchallenge.png', @@ -354,7 +354,7 @@ const resetHistoryCorruptionInfo: Record = { }, drought: { image: 'CorruptDrought.png', - title: 'Drought [Offering EXP]', + title: 'Drought [Offering EXP]' }, recession: { image: 'CorruptRecession.png', @@ -547,8 +547,7 @@ const resetHistoryFormatCorruptions = (data: ResetHistoryEntryAscend): [string, // Support old format (which is bad) if (Array.isArray(data.usedCorruptions)) { corrToLoad = convertInputToCorruption(data.usedCorruptions.slice(2, 10)) - } - else { + } else { corrToLoad = data.usedCorruptions } @@ -565,9 +564,7 @@ const resetHistoryFormatCorruptions = (data: ResetHistoryEntryAscend): [string, const corr_str = JSON.stringify(corrToLoad) if (corruptions) { - loadout += `` + loadout += `` } if (data.currentChallenge !== undefined) { score += ` / C${data.currentChallenge}` diff --git a/src/Login.ts b/src/Login.ts index 206851a0b..fc00a45b2 100644 --- a/src/Login.ts +++ b/src/Login.ts @@ -1,6 +1,7 @@ import i18next from 'i18next' import localforage from 'localforage' import { DOMCacheGetOrSet } from './Cache/DOM' +import { testing } from './Config' import { importSynergism } from './ImportExport' import { QuarkHandler, setQuarkBonus } from './Quark' import { player } from './Synergism' @@ -75,7 +76,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 +86,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) { @@ -172,7 +215,7 @@ export async function handleLogin () { subtabElement.appendChild(logoutElement) subtabElement.appendChild(cloudSaveParent) - } else { + } else if (!testing) { // User is not logged in subtabElement.innerHTML = ` @@ -195,41 +238,3 @@ export async function handleLogin () { }) } } - -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) -} diff --git a/src/Octeracts.ts b/src/Octeracts.ts index 0dda2dfb6..9d7cfca58 100644 --- a/src/Octeracts.ts +++ b/src/Octeracts.ts @@ -828,7 +828,7 @@ export const octeractData: Record { if (player.currentChallenge.ascension !== 15) { player.corruptions.used.setCorruptionLevelsWithChallengeRequirement(player.corruptions.next.getLoadout()) - } - else { + } else { player.corruptions.used.setCorruptionLevelsWithChallengeRequirement(c15Corruptions) } diff --git a/src/Synergism.ts b/src/Synergism.ts index 62ed60769..54d41a096 100644 --- a/src/Synergism.ts +++ b/src/Synergism.ts @@ -161,6 +161,7 @@ import { pixelData, PixelUpgrade } from './PixelUpgrades' import { updatePlatonicUpgradeBG } from './Platonic' import { getQuarkBonus, QuarkHandler } from './Quark' import { playerJsonSchema } from './saves/PlayerJsonSchema' +import { playerUpdateVarSchema } from './saves/PlayerUpdateVarSchema' import { getFastForwardTotalMultiplier, singularityData, SingularityUpgrade } from './singularity' import { SingularityChallenge, singularityChallengeData } from './SingularityChallenges' import { @@ -174,10 +175,10 @@ import { 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' -import { playerUpdateVarSchema } from './saves/PlayerUpdateVarSchema' export const player: Player = { firstPlayed: new Date().toISOString(), @@ -1597,81 +1598,7 @@ export const saveSynergy = async (button?: boolean): Promise => { player.loaded1009 = true player.loaded1009hotfix1 = true - // shallow hold, doesn't modify OG object nor is affected by modifications to OG - const p = Object.assign({}, player, { - codes: Array.from(player.codes), - worlds: Number(player.worlds), - wowCubes: Number(player.wowCubes), - wowTesseracts: Number(player.wowTesseracts), - wowHypercubes: Number(player.wowHypercubes), - wowPlatonicCubes: Number(player.wowPlatonicCubes), - singularityUpgrades: Object.fromEntries( - Object.entries(player.singularityUpgrades).map(([key, value]) => { - return [ - key, - { - level: value.level, - goldenQuarksInvested: value.goldenQuarksInvested, - toggleBuy: value.toggleBuy, - freeLevels: value.freeLevels - } - ] - }) - ), - octeractUpgrades: Object.fromEntries( - Object.entries(player.octeractUpgrades).map(([key, value]) => { - return [ - key, - { - level: value.level, - octeractsInvested: value.octeractsInvested, - toggleBuy: value.toggleBuy, - freeLevels: value.freeLevels - } - ] - }) - ), - pixelUpgrades: Object.fromEntries( - Object.entries(player.pixelUpgrades).map(([key, value]) => { - return [ - key, - { - level: value.level, - pixelsInvested: value.pixelsInvested, - toggleBuy: value.toggleBuy, - freeLevels: value.freeLevels - } - ] - }) - ), - singularityChallenges: Object.fromEntries( - Object.entries(player.singularityChallenges).map(([key, value]) => { - return [ - key, - { - completions: value.completions, - highestSingularityCompleted: value.highestSingularityCompleted, - enabled: value.enabled - } - ] - }) - ), - blueberryUpgrades: Object.fromEntries( - Object.entries(player.blueberryUpgrades).map(([key, value]) => { - return [ - key, - { - level: value.level, - ambrosiaInvested: value.ambrosiaInvested, - blueberriesInvested: value.blueberriesInvested, - toggleBuy: value.toggleBuy, - freeLevels: value.freeLevels - } - ] - }) - ) - }) - + const p = playerJsonSchema.parse(player) const save = btoa(JSON.stringify(p)) if (save !== null) { @@ -1779,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 } } } @@ -2383,10 +2310,10 @@ const loadSynergy = async () => { corruptionStatsUpdate() const numSavefiles = player.corruptions.saves.getSaves().length - + corruptionLoadoutTableUpdate(true, 0) for (let i = 0; i < numSavefiles; i++) { - corruptionLoadoutTableUpdate(false, i+1) + corruptionLoadoutTableUpdate(false, i + 1) } showCorruptionStatsLoadouts() updateCorruptionLoadoutNames() @@ -6492,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 620e9f558..6d2d4961c 100644 --- a/src/Tabs.ts +++ b/src/Tabs.ts @@ -115,7 +115,7 @@ const subtabInfo: Record = { ] }, [Tabs.Upgrades]: { subTabList: [] }, - [Tabs.Achievements]: { + [Tabs.Achievements]: { tabSwitcher: () => toggleAchievementScreen, subTabList: [ { @@ -131,8 +131,9 @@ const subtabInfo: Record = { return true }, buttonID: 'toggleAchievementSubTab2' - }, - ] }, + } + ] + }, [Tabs.Runes]: { tabSwitcher: () => toggleRuneScreen, subTabList: [ 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 9d0177ce5..eb17f82e5 100644 --- a/src/Toggles.ts +++ b/src/Toggles.ts @@ -947,7 +947,6 @@ export const toggleAutoTesseracts = (i: number) => { } export const toggleCorruptionLevel = (corr: keyof Corruptions, value: number, reset = false) => { - if (reset && player.currentChallenge.ascension !== 15) { player.corruptions.used.resetCorruptions() player.corruptions.next.resetCorruptions() diff --git a/src/UpdateHTML.ts b/src/UpdateHTML.ts index b2c5ad510..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, @@ -29,7 +30,6 @@ import { } from './UpdateVisuals' import { createDeferredPromise } from './Utility' import { Globals as G } from './Variables' -import { toggleAchievementScreen } from './Toggles' export const revealStuff = () => { const example = document.getElementsByClassName('coinunlock1') as HTMLCollectionOf @@ -642,7 +642,6 @@ export const hideStuff = () => { 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' diff --git a/src/UpdateVisuals.ts b/src/UpdateVisuals.ts index 08b5a29ae..ad3c6c048 100644 --- a/src/UpdateVisuals.ts +++ b/src/UpdateVisuals.ts @@ -1301,8 +1301,8 @@ export const visualUpdateCorruptions = () => { 'corruptions.antExponent', { exponent: format( - (1 - (0.9 / 90) * Math.min(99, player.corruptions.used.totalLevels) - * player.corruptions.used.corruptionEffects('extinction')), + 1 - (0.9 / 90) * Math.min(99, player.corruptions.used.totalLevels) + * player.corruptions.used.corruptionEffects('extinction'), 3 ) } diff --git a/src/Utility.ts b/src/Utility.ts index bb9b7faac..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') } } @@ -193,7 +193,6 @@ export const deepClone = (value: unknown) => { }) } - -export const validateNonnegativeInteger = (n: number | string):boolean => { +export const validateNonnegativeInteger = (n: number | string): boolean => { return Number.isFinite(n) && !Number.isNaN(n) && Number.isInteger(n) -} \ No newline at end of file +} diff --git a/src/saves/PlayerJsonSchema.ts b/src/saves/PlayerJsonSchema.ts index cede71b10..dae795cc9 100644 --- a/src/saves/PlayerJsonSchema.ts +++ b/src/saves/PlayerJsonSchema.ts @@ -1,7 +1,7 @@ import { z } from 'zod' +import type { Corruptions } from '../Corruptions' import type { Player } from '../types/Synergism' import { playerSchema } from './PlayerSchema' -import type { Corruptions } from '../Corruptions' const convertArrayToCorruption = (array: number[]): Corruptions => { return { @@ -12,7 +12,7 @@ const convertArrayToCorruption = (array: number[]): Corruptions => { deflation: array[6], extinction: array[7], drought: array[8], - recession: array[9], + recession: array[9] } } @@ -35,8 +35,7 @@ export const playerJsonSchema = playerSchema.extend({ ), showStats: stuff.showStats } - } - ), + }), singularityUpgrades: z.any().transform((upgrades: Player['singularityUpgrades']) => Object.fromEntries( Object.entries(upgrades).map(([key, value]) => { @@ -112,9 +111,8 @@ export const playerJsonSchema = playerSchema.extend({ }) ) ), - dayCheck: z.any().transform((dayCheck: Player['dayCheck']) => dayCheck?.toISOString() ?? null), + 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 @@ -132,10 +130,13 @@ export const playerJsonSchema = playerSchema.extend({ 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) + 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 } diff --git a/src/saves/PlayerSchema.ts b/src/saves/PlayerSchema.ts index 5d6a972f9..e5fbdc474 100644 --- a/src/saves/PlayerSchema.ts +++ b/src/saves/PlayerSchema.ts @@ -1,6 +1,7 @@ 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' @@ -11,7 +12,6 @@ import { SingularityChallenge, singularityChallengeData } from '../SingularityCh import { blankSave } from '../Synergism' import type { Player } from '../types/Synergism' import { deepClone, padArray } from '../Utility' -import { CorruptionLoadout, CorruptionSaves } from '../Corruptions' const decimalSchema = z.custom((value) => { try { @@ -795,4 +795,4 @@ export const playerSchema = z.object({ lastExportedSave: z.number().default(() => blankSave.lastExportedSave), seed: z.number().array().default(() => blankSave.seed).transform((value) => arrayExtend(value, 'seed')) -}) \ No newline at end of file +}) diff --git a/src/saves/PlayerUpdateVarSchema.ts b/src/saves/PlayerUpdateVarSchema.ts index 358fe867f..5b5d89b53 100644 --- a/src/saves/PlayerUpdateVarSchema.ts +++ b/src/saves/PlayerUpdateVarSchema.ts @@ -1,21 +1,21 @@ -import { CorruptionLoadout, type Corruptions, CorruptionSaves } from "../Corruptions"; -import { playerSchema } from "./PlayerSchema"; +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], - } + 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) { + if (player.usedCorruptions !== undefined) { const corrLoadout = convertArrayToCorruption(player.usedCorruptions) player.corruptions.used = new CorruptionLoadout(corrLoadout) } @@ -30,10 +30,13 @@ export const playerUpdateVarSchema = playerSchema.transform((player) => { } 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) + 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) } @@ -44,4 +47,4 @@ export const playerUpdateVarSchema = playerSchema.transform((player) => { player.corruptionLoadouts = undefined return player -}) \ No newline at end of file +}) diff --git a/src/types/Synergism.d.ts b/src/types/Synergism.d.ts index aeee5442f..eb1519485 100644 --- a/src/types/Synergism.d.ts +++ b/src/types/Synergism.d.ts @@ -1,5 +1,6 @@ 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' @@ -19,7 +20,6 @@ import type { UltimatePixelLuckCache } from '../StatCache' import type { Tabs } from '../Tabs' -import type { CorruptionLoadout, Corruptions, CorruptionSaves } from '../Corruptions' type ArrayStartingWithNull = [null, ...T[]] From 376d2760980cefc5799690bac8dbd8573c9f4cf2 Mon Sep 17 00:00:00 2001 From: Khafra Date: Fri, 8 Nov 2024 16:26:51 -0500 Subject: [PATCH 3/3] add captcha (#618) * add captcha * fixup --- Synergism.css | 9 ++++++++- index.html | 6 ++++++ package.json | 1 + src/Login.ts | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/Synergism.css b/Synergism.css index 39836b994..b1adebb1d 100644 --- a/Synergism.css +++ b/Synergism.css @@ -327,7 +327,8 @@ body button:active { background-color: var(--hover-color); } -#confirmationBox { +#confirmationBox, +#captchaHolder { display: none; position: fixed; top: 50vh; @@ -4066,3 +4067,9 @@ form input:hover { #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 229128558..c4a1f29df 100644 --- a/index.html +++ b/index.html @@ -16,9 +16,15 @@ Synergism + + +
+
+
+
diff --git a/package.json b/package.json index aeab8a3c5..9ad6c7209 100644 --- a/package.json +++ b/package.json @@ -18,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/Login.ts b/src/Login.ts index fc00a45b2..c0174add2 100644 --- a/src/Login.ts +++ b/src/Login.ts @@ -1,11 +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' @@ -213,7 +217,36 @@ export function setAccount ( 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 if (!testing) { // User is not logged in @@ -238,3 +271,23 @@ export function setAccount ( }) } } + +async function uploadValues (token: string) { + const response1 = await fetch('https://synergism.cc/api/v1/roles/upload') + const fields: (keyof z.infer)[] = await response1.json() + + const p = playerJsonSchema.parse(player) + + const fd = new FormData() + fd.set('cf-token', token) + + for (const field of fields) { + fd.set(field, JSON.stringify(p[field])) + } + + const response2 = await fetch('https://synergism.cc/api/v1/roles/upload', { + method: 'POST' + }) + + Notification(await response2.text()) +}