Complete packing elf and book

This commit is contained in:
Seth Posner 2022-12-24 00:57:10 -08:00
parent 8d3dd4f339
commit bcdd2e55f8
4 changed files with 233 additions and 21 deletions

View file

@ -39,6 +39,7 @@ import wrappingPaper from "./wrapping-paper";
import dyes, { enumColor } from "./dyes"; import dyes, { enumColor } from "./dyes";
import ribbon from "./ribbon"; import ribbon from "./ribbon";
import letters from "./letters"; import letters from "./letters";
import packing from "./packing";
export interface ElfBuyable extends GenericBuyable { export interface ElfBuyable extends GenericBuyable {
/** The inverse function of the cost formula, used to calculate the maximum amount that can be bought by elves. */ /** The inverse function of the cost formula, used to calculate the maximum amount that can be bought by elves. */
@ -455,6 +456,23 @@ const layer = createLayer(id, function (this: BaseLayer) {
enabled: elvesMilestone2.earned enabled: elvesMilestone2.earned
})) }))
]); ]);
const packingCooldown = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "6 Elves Trained",
enabled: elvesMilestone.earned
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.times(paper.books.packingBook.totalAmount.value, 0.1).add(1),
description: "The Tetris Effect",
enabled: () => Decimal.gt(paper.books.packingBook.totalAmount.value, 0)
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "10 Elves Trained",
enabled: elvesMilestone2.earned
}))
]);
const [generalTab, generalTabCollapsed] = createCollapsibleModifierSections(() => [ const [generalTab, generalTabCollapsed] = createCollapsibleModifierSections(() => [
{ {
@ -590,6 +608,13 @@ const layer = createLayer(id, function (this: BaseLayer) {
base: 10, base: 10,
unit: "/s", unit: "/s",
visible: plastic.masteryEffectActive visible: plastic.masteryEffectActive
},
{
title: "Jingle Auto-Buy Frequency",
modifier: packingCooldown,
base: 10,
unit: "/s",
visible: packing.upgrades.packingElf.bought
} }
]); ]);
const showModifiersModal = ref(false); const showModifiersModal = ref(false);
@ -1012,6 +1037,20 @@ const layer = createLayer(id, function (this: BaseLayer) {
buyMax: () => management.elfTraining.plasticElfTraining.milestones[4].earned.value buyMax: () => management.elfTraining.plasticElfTraining.milestones[4].earned.value
}); });
const wrappingPaperElves = [dyeElf, plasticElf]; const wrappingPaperElves = [dyeElf, plasticElf];
const packingElf = createElf({
name: "Jingle",
description: "Jingle will automatically hire more elves to help out with packing the sleigh.",
buyable: [packing.helpers.elf, packing.helpers.loader],
cooldownModifier: packingCooldown,
visibility: () => showIf(packing.upgrades.packingElf.bought.value),
buyMax: true,
onAutoPurchase(buyable, amount) {
if (buyable === packing.helpers.loader && !management.elfTraining.packingElfTraining.milestones[3].earned.value) {
buyable.amount.value = Decimal.sub(buyable.amount.value, amount);
}
}
});
const elves = { const elves = {
cuttersElf, cuttersElf,
plantersElf, plantersElf,
@ -1030,7 +1069,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
oilElf, oilElf,
metalElf, metalElf,
dyeElf, dyeElf,
plasticElf plasticElf,
packingElf
}; };
const totalElves = computed(() => Object.values(elves).filter(elf => elf.bought.value).length); const totalElves = computed(() => Object.values(elves).filter(elf => elf.bought.value).length);
@ -1277,6 +1317,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
buyProgress: persistent<DecimalSource>(0), buyProgress: persistent<DecimalSource>(0),
amountOfTimesDone: persistent<number>(0), amountOfTimesDone: persistent<number>(0),
bought: persistent<boolean>(false) bought: persistent<boolean>(false)
},
packingElf: {
buyProgress: persistent<DecimalSource>(0),
amountOftimesDone: persistent<number>(0),
bought: persistent<boolean>(false)
} }
}, },
milestones: [ milestones: [
@ -1332,7 +1377,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
fireElves, fireElves,
plasticElves, plasticElves,
managementElves, managementElves,
managementElves2.concat(wrappingPaperElves) managementElves2.concat(wrappingPaperElves),
[packingElf]
)} )}
</div> </div>
{milestonesDisplay()} {milestonesDisplay()}

View file

@ -26,7 +26,6 @@ import boxes from "./boxes";
import cloth from "./cloth"; import cloth from "./cloth";
import coal from "./coal"; import coal from "./coal";
import dyes from "./dyes"; import dyes from "./dyes";
import elves from "./elves";
import metal from "./metal"; import metal from "./metal";
import oil from "./oil"; import oil from "./oil";
import paper from "./paper"; import paper from "./paper";
@ -37,6 +36,8 @@ import "./styles/management.css";
import { Resource } from "features/resources/resource"; import { Resource } from "features/resources/resource";
import { isArray } from "@vue/shared"; import { isArray } from "@vue/shared";
import { createTab } from "features/tabs/tab"; import { createTab } from "features/tabs/tab";
import packing from "./packing";
import elves from "./elves";
const id = "management"; const id = "management";
const day = 12; const day = 12;
@ -189,11 +190,15 @@ const layer = createLayer(id, () => {
"Cocoa", "Cocoa",
"Twinkle", "Twinkle",
"Carol", "Carol",
"Tinsel" "Tinsel",
"Jingle"
].indexOf(elf.name) + 1; ].indexOf(elf.name) + 1;
if (elf.name == "Star" || elf.name == "Bell") { if (elf.name == "Star" || elf.name == "Bell") {
costMulti /= 3; costMulti /= 3;
} }
if (elf.name == "Jingle") {
costMulti *= 30;
}
const costBase = 4000 * costMulti; const costBase = 4000 * costMulti;
const expRequiredForNextLevel = computed(() => Decimal.pow(5, level.value).mul(costBase)); const expRequiredForNextLevel = computed(() => Decimal.pow(5, level.value).mul(costBase));
const level = computed(() => const level = computed(() =>
@ -1139,6 +1144,57 @@ const layer = createLayer(id, () => {
visibility: () => showIf(plasticElfMilestones[3].earned.value && main.day.value >= 16) visibility: () => showIf(plasticElfMilestones[3].earned.value && main.day.value >= 16)
})) }))
] as Array<GenericMilestone>; ] as Array<GenericMilestone>;
const packingElfMilestones = [
createMilestone(() => ({
display: {
requirement: "Jingle Level 1",
effectDisplay: "Double elf packing speed"
},
shouldEarn: () => packingElfTraining.level.value >= 1
})),
createMilestone(() => ({
display: {
requirement: "Jingle Level 2",
effectDisplay: jsx(() => (
<>
Each elf assistant increases packing speed by 10%<br />
Currently: +{formatWhole(Decimal.times(packing.helpers.elf.amount.value, 0.1).times(100))}%
</>
))
},
shouldEarn: () => packingElfTraining.level.value >= 2,
visibility: () => showIf(packingElfMilestones[0].earned.value)
})),
createMilestone(() => ({
display: {
requirement: "Jingle Level 3",
effectDisplay: jsx(() => (
<>
Multiply packing speed by the number of completed packing milestones<br />
Currently: {formatWhole(Object.values(packing.packingMilestones).filter(milestone => milestone.earned.value).length+1)}x
</>
))
},
shouldEarn: () => packingElfTraining.level.value >= 3,
visibility: () => showIf(packingElfMilestones[1].earned.value)
})),
createMilestone(() => ({
display: {
requirement: "Jingle Level 4",
effectDisplay: "Jingle will now also buy loaders"
},
shouldEarn: () => packingElfTraining.level.value >= 4,
visibility: () => showIf(packingElfMilestones[2].earned.value && main.day.value >= 16)
})),
createMilestone(() => ({
display: {
requirement: "Jingle Level 5",
effectDisplay: "Multipliers to elf packing speed also apply to loaders"
},
shouldEarn: () => packingElfTraining.level.value >= 5,
visibility: () => showIf(packingElfMilestones[3].earned.value && main.day.value >= 16)
}))
] as Array<GenericMilestone>;
// ------------------------------------------------------------------------------- Milestone display // ------------------------------------------------------------------------------- Milestone display
const currentShown = persistent<string>("Holly"); const currentShown = persistent<string>("Holly");
@ -1219,8 +1275,10 @@ const layer = createLayer(id, () => {
); );
const dyeElfTraining = createElfTraining(elves.elves.dyeElf, dyeElfMilestones); const dyeElfTraining = createElfTraining(elves.elves.dyeElf, dyeElfMilestones);
const plasticElfTraining = createElfTraining(elves.elves.plasticElf, plasticElfMilestones); const plasticElfTraining = createElfTraining(elves.elves.plasticElf, plasticElfMilestones);
const packingElfTraining = createElfTraining(elves.elves.packingElf, packingElfMilestones);
const row5Elves = [coalDrillElfTraining, heavyDrillElfTraining, oilElfTraining]; const row5Elves = [coalDrillElfTraining, heavyDrillElfTraining, oilElfTraining];
const row6Elves = [metalElfTraining, dyeElfTraining, plasticElfTraining]; const row6Elves = [metalElfTraining, dyeElfTraining, plasticElfTraining];
const row7Elves = [packingElfTraining]
const elfTraining = { const elfTraining = {
cutterElfTraining, cutterElfTraining,
planterElfTraining, planterElfTraining,
@ -1239,7 +1297,8 @@ const layer = createLayer(id, () => {
oilElfTraining, oilElfTraining,
heavyDrillElfTraining, heavyDrillElfTraining,
dyeElfTraining, dyeElfTraining,
plasticElfTraining plasticElfTraining,
packingElfTraining
}; };
const day12Elves = [ const day12Elves = [
cutterElfTraining, cutterElfTraining,
@ -1761,6 +1820,12 @@ const layer = createLayer(id, () => {
modifier: plasticElfTraining.elfXPGain, modifier: plasticElfTraining.elfXPGain,
base: 0.1, base: 0.1,
unit: " XP" unit: " XP"
},
{
title: "Jingle XP Gain per Action",
modifier: packingElfTraining.elfXPGain,
base: 0.1,
unit: " XP"
} }
]); ]);
const showModifiersModal = ref(false); const showModifiersModal = ref(false);
@ -2056,7 +2121,8 @@ const layer = createLayer(id, () => {
fireElfTraining, fireElfTraining,
plasticElvesTraining, plasticElvesTraining,
row5Elves, row5Elves,
row6Elves row6Elves,
row7Elves
)} )}
<Spacer /> <Spacer />
{currentElfDisplay()} {currentElfDisplay()}

View file

@ -10,7 +10,7 @@ import { createMilestone, GenericMilestone } from "features/milestones/milestone
import MainDisplayVue from "features/resources/MainDisplay.vue"; import MainDisplayVue from "features/resources/MainDisplay.vue";
import { createResource, trackBest, trackTotal, Resource } from "features/resources/resource"; import { createResource, trackBest, trackTotal, Resource } from "features/resources/resource";
import { createLayer, BaseLayer } from "game/layers"; import { createLayer, BaseLayer } from "game/layers";
import { createSequentialModifier } from "game/modifiers"; import { createMultiplicativeModifier, createSequentialModifier } from "game/modifiers";
import { persistent } from "game/persistence"; import { persistent } from "game/persistence";
import Decimal, { DecimalSource, format, formatWhole } from "util/bignum"; import Decimal, { DecimalSource, format, formatWhole } from "util/bignum";
import { Direction } from "util/common"; import { Direction } from "util/common";
@ -20,6 +20,10 @@ import metal from "./metal";
import oil from "./oil"; import oil from "./oil";
import { createCollapsibleMilestones } from "data/common" import { createCollapsibleMilestones } from "data/common"
import { globalBus } from "game/events"; import { globalBus } from "game/events";
import { createUpgrade } from "features/upgrades/upgrade";
import { ElfBuyable } from "./elves";
import management from "./management";
import paper from "./paper";
const id = "packing" const id = "packing"
const day = 24; const day = 24;
@ -92,18 +96,65 @@ const layer = createLayer(id, function (this: BaseLayer) {
const remainingSize = computed(() => Decimal.sub(sledSpace, packedPresentsSize.value)); const remainingSize = computed(() => Decimal.sub(sledSpace, packedPresentsSize.value));
const elfPackingSpeed = createSequentialModifier(() => [ const elfPackingSpeed = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.pow(0.5, packingResets.value),
description: "Better Organization",
enabled: () => packingResets.value >= 1
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "Jingle Level 1",
enabled: management.elfTraining.packingElfTraining.milestones[0].earned
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.times(helpers.elf.amount.value, 0.1).plus(1),
description: "Jingle Level 2",
enabled: management.elfTraining.packingElfTraining.milestones[1].earned
})),
createMultiplicativeModifier(() => ({
multiplier: () => 1 + Object.values(packingMilestones).filter(milestone => milestone.earned).length,
description: "Jingle Level 3",
enabled: management.elfTraining.packingElfTraining.milestones[2].earned
}))
]); ]);
const computedElfPackingSpeed = computed(() => elfPackingSpeed.apply(1)); const computedElfPackingSpeed = computed(() => elfPackingSpeed.apply(1));
const loaderPackingSpeed = createSequentialModifier(() => [ const loaderPackingSpeed = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.pow(0.5, packingResets.value),
description: "Better Organization",
enabled: () => packingResets.value >= 1
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "Jingle Level 1",
enabled: management.elfTraining.packingElfTraining.milestones[4].earned
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.times(helpers.elf.amount.value, 0.1).plus(1),
description: "Jingle Level 2",
enabled: management.elfTraining.packingElfTraining.milestones[4].earned
})),
createMultiplicativeModifier(() => ({
multiplier: () => 1 + Object.values(packingMilestones).filter(milestone => milestone.earned).length,
description: "Jingle Level 3",
enabled: management.elfTraining.packingElfTraining.milestones[4].earned
}))
]); ]);
const computedLoaderPackingSpeed = computed(() => loaderPackingSpeed.apply(1000)); const computedLoaderPackingSpeed = computed(() => loaderPackingSpeed.apply(1000));
const helpers = { const helpers = {
elf: createBuyable(() => ({ elf: createBuyable(() => ({
visibility: () => showIf(Decimal.gte(totalPresents.value, 10)), visibility: () => showIf(Decimal.gte(totalPresents.value, 10)),
cost() { return Decimal.pow(1.2, this.amount.value).times(10).floor() }, cost() {
let v = this.amount.value;
v = Decimal.pow(0.95, paper.books.packingBook.totalAmount.value).times(v);
return Decimal.pow(1.2, v).times(10).floor()
},
inverseCost(cost: DecimalSource) {
let amount = Decimal.div(cost, 10).log(1.2);
amount = amount.div(Decimal.pow(0.95, paper.books.packingBook.totalAmount.value));
return Decimal.isNaN(amount) ? Decimal.dZero : amount.floor().max(0);
},
resource: totalPresentsResource, resource: totalPresentsResource,
display: jsx(() => ( display: jsx(() => (
<> <>
@ -121,13 +172,19 @@ const layer = createLayer(id, function (this: BaseLayer) {
} }
})), })),
loader: createBuyable(() => ({ loader: createBuyable(() => ({
visibility: () => showIf(false), visibility: () => showIf(upgrades.loaderUnlock.bought.value),
metalCost: computed(() => Decimal.pow(1.5, helpers.loader.amount.value).times(1e40) ), metalCost: computed(() => Decimal.pow(1.2, helpers.loader.amount.value).times(1e70) ),
oilCost: computed(() => Decimal.pow(1.5, helpers.loader.amount.value).times(1e20) ), oilCost: computed(() => Decimal.pow(1.2, helpers.loader.amount.value).times(1e25) ),
canPurchase(this: GenericBuyable & {metalCost: ComputedRef<DecimalSource>, oilCost: ComputedRef<DecimalSource>}) { canPurchase(this: GenericBuyable & {metalCost: ComputedRef<DecimalSource>, oilCost: ComputedRef<DecimalSource>}) {
return Decimal.gte(metal.metal.value, this.metalCost.value) return Decimal.gte(metal.metal.value, this.metalCost.value)
&& Decimal.gte(oil.oil.value, this.oilCost.value) && Decimal.gte(oil.oil.value, this.oilCost.value)
}, },
inverseCost() {
let metalAmount = Decimal.div(metal.metal.value, 1e40).log(1.5);
let oilAmount = Decimal.div(oil.oil.value, 1e20).log(1.5);
if (Decimal.isNaN(metalAmount) || Decimal.isNaN(oilAmount)) return Decimal.dZero;
return Decimal.min(metalAmount, oilAmount).floor().max(0);
},
display: jsx(() => ( display: jsx(() => (
<> <>
<div><h3>Build a loader</h3></div> <div><h3>Build a loader</h3></div>
@ -140,13 +197,41 @@ const layer = createLayer(id, function (this: BaseLayer) {
Cost: {displayCost(metal.metal, helpers.loader.metalCost.value, metal.metal.displayName)}, Cost: {displayCost(metal.metal, helpers.loader.metalCost.value, metal.metal.displayName)},
{displayCost(oil.oil, helpers.loader.oilCost.value, oil.oil.displayName)}</div> {displayCost(oil.oil, helpers.loader.oilCost.value, oil.oil.displayName)}</div>
</> </>
)) )),
style: {
width: "200px"
}
})) }))
} as { } as {
elf: GenericBuyable, elf: ElfBuyable,
loader: GenericBuyable & {metalCost: ComputedRef<DecimalSource>, oilCost: ComputedRef<DecimalSource>} loader: ElfBuyable & {metalCost: ComputedRef<DecimalSource>, oilCost: ComputedRef<DecimalSource>}
}; };
const upgrades = {
packingElf: createUpgrade(() => ({
display: {
title: "An Elf's Elf",
description: "Hire an Elf to help you hire more Elves"
},
cost: 1000,
resource: totalPresentsResource,
style: {
width: "200px"
}
})),
loaderUnlock: createUpgrade(() => ({
display: {
title: "Heavy Machinery",
description: "Those construction vehicles you have from building the workshop should be useful for loading presents too"
},
cost: 100000,
resource: totalPresentsResource,
style: {
width: "200px"
}
}))
}
const packingMilestones: Record<string, GenericMilestone> = { const packingMilestones: Record<string, GenericMilestone> = {
logBoost: createMilestone(() => ({ logBoost: createMilestone(() => ({
display: { display: {
@ -353,7 +438,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
gradient: "packing-bar", gradient: "packing-bar",
duration: "15s" duration: "15s"
}, },
textColor: "var(--feature-foreground)", textColor: "var(--bought)",
}); });
globalBus.on("update", diff => { globalBus.on("update", diff => {
@ -378,7 +463,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
Decimal.times(helpers.elf.amount.value, computedElfPackingSpeed.value), Decimal.times(helpers.elf.amount.value, computedElfPackingSpeed.value),
Decimal.times(helpers.loader.amount.value, computedLoaderPackingSpeed.value) Decimal.times(helpers.loader.amount.value, computedLoaderPackingSpeed.value)
).times(diff).plus(packedPresents.value).min(8e9); ).times(diff).plus(packedPresents.value).min(8e9);
}) });
return { return {
name, name,
@ -390,19 +475,22 @@ const layer = createLayer(id, function (this: BaseLayer) {
packingResets, packingResets,
packingProgress, packingProgress,
helpers, helpers,
upgrades,
packingMilestones, packingMilestones,
collapseMilestones, collapseMilestones,
display: jsx(() => ( display: jsx(() => (
<> <>
{render(trackerDisplay)} {render(trackerDisplay)}
<SpacerVue /> <SpacerVue />
<MainDisplayVue resource={packedPresents} color={color} /> <MainDisplayVue resource={packedPresents} color={color}/>
<SpacerVue /> <SpacerVue />
{render(resetPacking)} {render(resetPacking)}
{render(packPresent)} {render(packPresent)}
<SpacerVue /> <SpacerVue />
{renderRow(...Object.values(helpers))} {renderRow(...Object.values(helpers))}
<SpacerVue /> <SpacerVue />
{renderRow(...Object.values(upgrades))}
<SpacerVue />
{milestonesDisplay()} {milestonesDisplay()}
</> </>
)), )),

View file

@ -26,6 +26,7 @@ import coal from "./coal";
import dyes from "./dyes"; import dyes from "./dyes";
import elves, { ElfBuyable } from "./elves"; import elves, { ElfBuyable } from "./elves";
import management from "./management"; import management from "./management";
import packing from "./packing";
import plastic from "./plastic"; import plastic from "./plastic";
import reindeer from "./reindeer"; import reindeer from "./reindeer";
import ribbon from "./ribbon"; import ribbon from "./ribbon";
@ -131,6 +132,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
if (["Peppermint", "Twinkle", "Cocoa", "Frosty"].includes(options.elfName)) { if (["Peppermint", "Twinkle", "Cocoa", "Frosty"].includes(options.elfName)) {
cost = cost.mul(1e31); cost = cost.mul(1e31);
} }
if (["Jingle"].includes(options.elfName)) {
cost = cost.mul(1e120);
}
if (management.elfTraining.paperElfTraining.milestones[0].earned.value) { if (management.elfTraining.paperElfTraining.milestones[0].earned.value) {
cost = Decimal.div(cost, sumBooks.value.max(1)); cost = Decimal.div(cost, sumBooks.value.max(1));
} }
@ -305,6 +309,12 @@ const layer = createLayer(id, function (this: BaseLayer) {
buyableName: "Plastic Buyables", buyableName: "Plastic Buyables",
visibility: () => showIf(plastic.masteryEffectActive.value) visibility: () => showIf(plastic.masteryEffectActive.value)
}); });
const packingBook = createBook({
name: "The Tetris Effect",
elfName: "Jingle",
buyableName: "Elf Assistants",
visibility: () => showIf(packing.upgrades.packingElf.bought.value)
})
const books = { const books = {
cuttersBook, cuttersBook,
plantersBook, plantersBook,
@ -324,7 +334,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
metalBook, metalBook,
primaryDyeBook, primaryDyeBook,
secondaryDyeBook, secondaryDyeBook,
plasticBook plasticBook,
packingBook
}; };
const sumBooks = computed(() => const sumBooks = computed(() =>
Object.values(books).reduce((acc, curr) => acc.add(curr.amount.value), new Decimal(0)) Object.values(books).reduce((acc, curr) => acc.add(curr.amount.value), new Decimal(0))
@ -513,7 +524,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
metalBook: { amount: persistent<DecimalSource>(0) }, metalBook: { amount: persistent<DecimalSource>(0) },
primaryDyeBook: { amount: persistent<DecimalSource>(0) }, primaryDyeBook: { amount: persistent<DecimalSource>(0) },
secondaryDyeBook: { amount: persistent<DecimalSource>(0) }, secondaryDyeBook: { amount: persistent<DecimalSource>(0) },
plasticBook: { amount: persistent<DecimalSource>(0) } plasticBook: { amount: persistent<DecimalSource>(0) },
packingBook: { amount: persistent<DecimalSource>(0) }
}, },
upgrades: { upgrades: {
clothUpgrade: { bought: persistent<boolean>(false) }, clothUpgrade: { bought: persistent<boolean>(false) },