Merge remote-tracking branch 'origin/main' into day-25-credits

This commit is contained in:
Chunkybanana 2022-12-24 06:05:30 +00:00
commit 944a7d717f
34 changed files with 1661 additions and 199 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -96,10 +96,9 @@ const useHeader = projInfo.useHeader;
const loreBody = computeOptionalComponent(main.loreBody);
function gatherLayerProps(layer: GenericLayer) {
const { display, minimized, minWidth, name, color, minimizable, nodes, minimizedDisplay } =
layer;
return { display, minimized, minWidth, name, color, minimizable, nodes, minimizedDisplay };
};
const { display, minimized, name, color, minimizable, nodes, minimizedDisplay } = layer;
return { display, minimized, name, color, minimizable, nodes, minimizedDisplay };
}
</script>
<style scoped>

View file

@ -2,7 +2,7 @@
<div class="layer-container" :style="{ '--layer-color': unref(color) }">
<button v-if="showGoBack" class="goBack" @click="goBack"></button>
<button class="layer-tab minimized" v-if="minimized" @click="setMinimized(false)">
<button class="layer-tab minimized" v-if="unref(minimized)" @click="setMinimized(false)">
<component v-if="minimizedComponent" :is="minimizedComponent" />
<div v-else>{{ unref(name) }}</div>
</button>
@ -34,10 +34,6 @@ export default defineComponent({
type: Number,
required: true
},
tab: {
type: Function as PropType<() => HTMLElement | undefined>,
required: true
},
display: {
type: processedPropType<CoercableComponent>(Object, String, Function),
required: true
@ -47,10 +43,6 @@ export default defineComponent({
type: Object as PropType<Persistent<boolean>>,
required: true
},
minWidth: {
type: processedPropType<number | string>(Number, String),
required: true
},
name: {
type: processedPropType<string>(String),
required: true
@ -63,7 +55,7 @@ export default defineComponent({
}
},
setup(props) {
const { display, index, minimized, minWidth, tab, minimizedDisplay, name } = toRefs(props);
const { display, index, minimized, minimizedDisplay } = toRefs(props);
const component = computeComponent(display);
const minimizedComponent = computeOptionalComponent(minimizedDisplay);
@ -79,39 +71,10 @@ export default defineComponent({
minimized.value = min;
}
nextTick(() => updateTab(minimized.value, unref(minWidth.value)));
watch([name, minimized, wrapRef(minWidth)], ([name, minimized, minWidth]) => {
updateTab(minimized, minWidth);
});
function updateNodes(nodes: Record<string, FeatureNode | undefined>) {
props.nodes.value = nodes;
}
function updateTab(min: boolean, minWidth: number | string) {
minimized.value = min;
const width =
typeof minWidth === "number" || Number.isNaN(parseInt(minWidth))
? minWidth + "px"
: minWidth;
const tabValue = tab.value();
if (tabValue != undefined) {
if (min) {
tabValue.style.flexGrow = "0";
tabValue.style.flexShrink = "0";
tabValue.style.width = "60px";
tabValue.style.minWidth = tabValue.style.flexBasis = "";
tabValue.style.margin = "0";
} else {
tabValue.style.flexGrow = "";
tabValue.style.flexShrink = "";
tabValue.style.width = "";
tabValue.style.minWidth = tabValue.style.flexBasis = width;
tabValue.style.margin = "";
}
}
}
return {
component,
minimizedComponent,
@ -119,16 +82,13 @@ export default defineComponent({
updateNodes,
unref,
goBack,
setMinimized,
minimized,
minWidth
setMinimized
};
}
});
</script>
<style scoped>
.layer-tab:not(.minimized) {
padding-top: 20px;
padding-bottom: 20px;

View file

@ -98,7 +98,7 @@ const isPaused = computed({
});
const canAutoSave = computed(
() => (layers as any).main.days[(layers as any).main.day.value - 1].opened.value
() => (layers as any).main?.days[(layers as any).main?.day.value - 1].opened.value
);
const autosaveTitle = jsx(() => (

View file

@ -6,7 +6,13 @@
class="scene-item"
style="left: 4%; bottom: 3%; width: 40px; height: 40px"
/>
<img v-if="day >= 0" :src="tree" class="scene-item" style="left: 10%; bottom: 10%" />
<img
v-if="day >= 0"
:src="tree"
class="scene-item"
style="left: 6%; bottom: 10%; width: 120px; height: 120px"
/>
<img v-if="day >= 20" :src="reindeer" class="scene-item" style="left: 13%; bottom: 8%" />
<img
v-if="day >= 13"
:src="letters"
@ -69,6 +75,7 @@
<div v-if="day >= 4" class="scene-bubble left" style="left: 64%; bottom: 37%">
<img v-if="day >= 17" :src="toys" class="scene-item" />
<img v-if="day >= 18" :src="advFactory" class="scene-item" />
<img v-if="day >= 19" :src="presents" class="scene-item" />
</div>
</div>
</template>
@ -93,6 +100,8 @@ import ribbons from "./symbols/ribbons.png";
import toys from "./symbols/truck.png";
import factory from "./symbols/gears.png";
import advFactory from "./symbols/teddyBear.png";
import presents from "./symbols/presents.png";
import reindeer from "./symbols/reindeer.png";
defineProps<{
day: number;

View file

@ -28,9 +28,11 @@ import { render, renderGrid } from "util/vue";
import { computed, ComputedRef, ref, unref } from "vue";
import dyes from "./dyes";
import elves, { ElfBuyable } from "./elves";
import factory from "./factory";
import management from "./management";
import paper from "./paper";
import plastic from "./plastic";
import reindeer from "./reindeer";
import trees from "./trees";
import workshop from "./workshop";
import wrappingPaper from "./wrapping-paper";
@ -55,6 +57,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: "1000% Foundation Completed",
enabled: workshop.milestones.extraExpansionMilestone5.earned
})),
reindeer.reindeer.vixen.modifier,
createExponentialModifier(() => ({
exponent: 1.1,
description: "Bell Level 2",
@ -587,7 +590,36 @@ const layer = createLayer(id, function (this: BaseLayer) {
Decimal.add(plasticBoxesBuyable.amount.value, plasticBoxesBuyable.freeLevels.value)
)
})) as BoxesBuyable;
const presentBuyable = createBuyable(() => ({
display: {
title: "Carry presents in boxes",
description: jsx(() => (
<>
Use boxes to carry presents, boosting its gain
<br />
<br />
<div>Amount: {formatWhole(presentBuyable.amount.value)} boxes</div>
</>
)),
effectDisplay: jsx(() => (
<>{format(Decimal.div(presentBuyable.amount.value, 10).add(1).pow(2))}x</>
)),
showAmount: false
},
resource: noPersist(boxes),
cost() {
return Decimal.pow(2, presentBuyable.amount.value).mul(1e87);
},
inverseCost(x: DecimalSource) {
const amt = Decimal.div(x, 1e87).log2();
return Decimal.isNaN(amt) ? Decimal.dZero : amt.floor().max(0);
},
freeLevels: computed(() => 0),
totalAmount: computed(() => presentBuyable.amount.value),
visibility: () => showIf(factory.upgrades[3][3].bought.value)
})) as BoxesBuyable;
const buyables2 = { oreBoxesBuyable, metalBoxesBuyable, plasticBoxesBuyable };
const buyables3 = { presentBuyable };
globalBus.on("update", diff => {
if (Decimal.lt(main.day.value, day)) {
return;
@ -677,6 +709,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
row3Upgrades,
buyables,
buyables2,
buyables3,
minWidth: 700,
generalTabCollapsed,
display: jsx(() => (
@ -703,7 +736,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
Object.values(row3Upgrades)
)}
<Spacer />
{renderGrid(Object.values(buyables), Object.values(buyables2))}
{renderGrid(
Object.values(buyables),
Object.values(buyables2),
Object.values(buyables3)
)}
</>
)),
minimizedDisplay: jsx(() => (

View file

@ -21,12 +21,13 @@ import { BaseLayer, createLayer } from "game/layers";
import {
createAdditiveModifier,
createMultiplicativeModifier,
createSequentialModifier
createSequentialModifier,
Modifier
} from "game/modifiers";
import { noPersist, persistent } from "game/persistence";
import Decimal, { DecimalSource, format } from "util/bignum";
import { formatWhole } from "util/break_eternity";
import { Direction } from "util/common";
import { Direction, WithRequired } from "util/common";
import { render, renderCol, renderRow } from "util/vue";
import { computed, ref, unref } from "vue";
import boxes from "./boxes";
@ -36,6 +37,7 @@ import management from "./management";
import metal from "./metal";
import paper from "./paper";
import plastic from "./plastic";
import reindeer from "./reindeer";
import trees from "./trees";
import workshop from "./workshop";
@ -449,8 +451,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: dyes.boosts.yellow2,
description: "Yellow Dye",
enabled: dyes.masteryEffectActive
}))
]);
})),
reindeer.reindeer.cupid.modifier
]) as WithRequired<Modifier, "description" | "revert">;
const computedSheepGain = computed(() => sheepGain.apply(1));
const breedingCooldown = createSequentialModifier(() => []);
const computedBreedingCooldown = computed(() => breedingCooldown.apply(1));
@ -494,8 +497,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: dyes.boosts.yellow2,
description: "Yellow Dye",
enabled: dyes.masteryEffectActive
}))
]);
})),
reindeer.reindeer.cupid.modifier
]) as WithRequired<Modifier, "description" | "revert">;
const computedShearingAmount = computed(() => shearingAmount.apply(1));
const shearingCooldown = createSequentialModifier(() => []);
const computedShearingCooldown = computed(() => shearingCooldown.apply(1));
@ -539,8 +543,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: dyes.boosts.yellow2,
description: "Yellow Dye",
enabled: dyes.masteryEffectActive
}))
]);
})),
reindeer.reindeer.cupid.modifier
]) as WithRequired<Modifier, "description" | "revert">;
const computedSpinningAmount = computed(() => spinningAmount.apply(1));
const spinningCooldown = createSequentialModifier(() => []);
const computedSpinningCooldown = computed(() => spinningCooldown.apply(1));

View file

@ -29,6 +29,7 @@ import {
import { noPersist, persistent } from "game/persistence";
import Decimal, { DecimalSource, format, formatWhole } from "util/bignum";
import { WithRequired } from "util/common";
import { Computable } from "util/computed";
import { render, renderGrid, renderRow } from "util/vue";
import { computed, ref, unref } from "vue";
import boxes from "./boxes";
@ -40,6 +41,7 @@ import metal from "./metal";
import oil from "./oil";
import paper from "./paper";
import plastic from "./plastic";
import reindeer from "./reindeer";
import trees from "./trees";
import wrappingPaper from "./wrapping-paper";
@ -47,7 +49,7 @@ interface BetterFertilizerUpgOptions {
canAfford: () => boolean;
onPurchase: VoidFunction;
display: JSXFunction;
style: StyleValue;
style: Computable<StyleValue>;
visibility: () => Visibility;
}
interface UnlockKilnUpgOptions {
@ -57,7 +59,7 @@ interface UnlockKilnUpgOptions {
title: string;
description: string;
};
style: StyleValue;
style: Computable<StyleValue>;
visibility: () => Visibility;
}
interface EfficientSmeltherUpgOptions {
@ -67,7 +69,7 @@ interface EfficientSmeltherUpgOptions {
title: string;
description: string;
};
style: StyleValue;
style: Computable<StyleValue>;
visibility: () => Visibility;
}
@ -360,7 +362,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Warmer Cutters",
description: "Cut down twice as many trees/s"
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
}));
const warmerPlanters = createUpgrade(() => ({
resource: noPersist(coal),
@ -369,7 +373,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Warmer Planters",
description: "Plant twice as many trees/s"
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
}));
const basicFertilizer = createUpgrade(() => ({
resource: noPersist(ash),
@ -378,7 +384,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Ashy Soil",
description: "Trees give 25% more logs"
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
}));
const unlockBonfire = createUpgrade(() => ({
resource: fireResource,
@ -388,9 +396,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: "Put all those fires together into a larger blaze"
},
onPurchase() {
fireResource.value = Decimal.add(fireResource.value, this.cost);
fireResource.value = Decimal.add(fireResource.value, this.cost as number);
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
}));
const row1upgrades = [warmerCutters, warmerPlanters, basicFertilizer, unlockBonfire];
@ -401,7 +411,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Dedicated Cutter Heaters",
description: "Double the bonus from Heated Cutters"
},
style: { color: colorText },
style() {
return this.bought.value ? "" : { color: colorText };
},
visibility: () => showIf(unlockBonfire.bought.value)
}));
const dedicatedPlanters = createUpgrade(() => ({
@ -411,7 +423,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Dedicated Planter Heaters",
description: "Double the bonus from Heated Planters"
},
style: { color: colorText },
style() {
return this.bought.value ? "" : { color: colorText };
},
visibility: () => showIf(unlockBonfire.bought.value)
}));
const betterFertilizer: Upgrade<BetterFertilizerUpgOptions> = createUpgrade(() => ({
@ -434,7 +448,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
{formatWhole(1e5)} {ash.displayName}
</>
)),
style: { color: colorText },
style() {
return this.bought.value ? "" : { color: colorText };
},
visibility: () => showIf(unlockBonfire.bought.value)
}));
@ -445,7 +461,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Efficient Fires",
description: "Move the fires underground to keep the coal from turning to ash"
},
style: { color: colorText },
style() {
return this.bought.value ? "" : { color: colorText };
},
visibility: () => showIf(unlockBonfire.bought.value)
}));
const row2upgrades = [dedicatedCutters, dedicatedPlanters, betterFertilizer, unlockKiln];
@ -457,7 +475,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Efficient Crucibles",
description: "Double auto smelting speed and triple metal gain from auto smelting"
},
style: { color: colorText },
style() {
return this.bought.value ? "" : { color: colorText };
},
visibility: () => showIf(oil.depthMilestones[4].earned.value)
}));
const arsonistAssistance = createUpgrade(() => ({
@ -467,7 +487,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Arsonist Assistance",
description: "Every elf at or above level 5 doubles ash gain"
},
style: { color: colorText },
style() {
return this.bought.value ? "" : { color: colorText };
},
visibility: () =>
showIf(management.elfTraining.coalDrillElfTraining.milestones[3].earned.value)
}));
@ -478,7 +500,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Refined Coal",
description: "Refineries boost coal gain"
},
style: { color: colorText },
style() {
return this.bought.value ? "" : { color: colorText };
},
visibility: () =>
showIf(management.elfTraining.coalDrillElfTraining.milestones[3].earned.value)
}));
@ -489,7 +513,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Colored Fire",
description: "Green dye also affects small fire synergy"
},
style: { color: colorText },
style() {
return this.bought.value ? "" : { color: colorText };
},
visibility: () =>
showIf(management.elfTraining.coalDrillElfTraining.milestones[3].earned.value)
}));
@ -785,6 +811,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: "Refined Coal",
enabled: refinedCoal.bought
})),
reindeer.reindeer.dancer.modifier,
createExponentialModifier(() => ({
exponent: 1.05,
description: "Jack Level 2",

View file

@ -37,6 +37,7 @@ import paper from "./paper";
import trees from "./trees";
import toys from "./toys";
import factory from "./factory";
import reindeer from "./reindeer";
interface Dye {
name: string;
@ -201,6 +202,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
enabled: boxes.row3Upgrades.dyeUpgrade.bought
}))
);
modifiers.push(reindeer.reindeer.rudolph.modifier);
return modifiers;
}) as WithRequired<Modifier, "description" | "revert">;
const computedToGenerate = computed(() => toGenerate.apply(0));

View file

@ -876,7 +876,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
name: "Bell",
description:
"Bell will automatically purchase all box buyables you can afford, without actually spending any boxes.",
buyable: [...Object.values(boxes.buyables), ...Object.values(boxes.buyables2)],
buyable: [
...Object.values(boxes.buyables),
...Object.values(boxes.buyables2),
...Object.values(boxes.buyables3)
],
cooldownModifier: boxCooldown,
visibility: () => showIf(plastic.elfUpgrades.boxElf.bought.value)
});

View file

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="50"
height="50"
viewBox="0 0 13.229166 13.229167"
version="1.1"
id="svg5"
sodipodi:docname="advent.svg"
inkscape:version="1.2.1 (9c6d41e4, 2022-07-14)"
inkscape:export-filename="advent/boxmaker.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="3.0909964"
inkscape:cx="3.0734426"
inkscape:cy="59.527731"
inkscape:window-width="1309"
inkscape:window-height="804"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" /><defs
id="defs2" /><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"><rect
style="fill:#e6e6e6;fill-opacity:1;stroke:#838390;stroke-width:0.764057;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:6;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
id="rect28545-6"
width="12.46511"
height="12.46511"
x="0.38202849"
y="0.38202882"
rx="1.246511" /><image
width="11.600364"
height="11.600364"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,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
"
id="image727"
x="0.74370372"
y="0.35876995" /></g></svg>

After

Width:  |  Height:  |  Size: 6.9 KiB

File diff suppressed because it is too large Load diff

View file

@ -76,10 +76,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
if (Decimal.lt(processingProgress.value, computedProcessingCooldown.value)) {
return;
}
const amount = Decimal.div(
processingProgress.value,
computedProcessingCooldown.value
).floor();
const amount = Decimal.div(processingProgress.value, computedProcessingCooldown.value)
.floor()
.max(1);
letters.value = Decimal.times(amount, computedLettersGain.value)
.add(letters.value)
.min(8e9);

View file

@ -37,6 +37,7 @@ import plastic from "./plastic";
import workshop from "./workshop";
import wrappingPaper from "./wrapping-paper";
import toys from "./toys";
import reindeer from "./reindeer";
const id = "metal";
const day = 7;
@ -105,6 +106,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: "Twinkle Level 1",
enabled: management.elfTraining.metalElfTraining.milestones[0].earned
})),
reindeer.reindeer.comet.modifier,
createExponentialModifier(() => ({
exponent: 1.1,
description: "Mary Level 2",

View file

@ -43,6 +43,7 @@ import { WithRequired } from "util/common";
import { ElfBuyable } from "./elves";
import toys from "./toys";
import factory from "./factory";
import reindeer from "./reindeer";
const id = "oil";
const day = 9;
@ -625,7 +626,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: "Increase drill power by +4% per Coal Drill owned.",
effectDisplay: jsx(() => <>x{format(row1UpgradeEffects[0].value)}</>)
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: metal.metal,
@ -635,7 +638,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: "Increase drill power by +4% per Metal Drill owned.",
effectDisplay: jsx(() => <>x{format(row1UpgradeEffects[1].value)}</>)
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: coal.coal,
@ -645,7 +650,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: "Increase drill power by +6% per OoM of coal owned.",
effectDisplay: jsx(() => <>x{format(row1UpgradeEffects[2].value)}</>)
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: metal.metal,
@ -655,7 +662,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: "Increase drill power by +10% per OoM of metal ingot owned.",
effectDisplay: jsx(() => <>x{format(row1UpgradeEffects[3].value)}</>)
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: noPersist(oil),
@ -667,7 +676,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
<>+{format(Decimal.mul(row1UpgradeEffects[4].value, 100))}%</>
))
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
}))
];
const row1UpgradeEffects: ComputedRef<DecimalSource>[] = [
@ -706,7 +717,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Oil the Oil Pump",
description: "Double oil gain."
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: noPersist(oil),
@ -716,7 +729,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
description:
"Double ore mining speed and square the coal drill amount in its effect."
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: noPersist(oil),
@ -725,7 +740,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Blaster Burner",
description: "The Oil Burner can now increase your auto smelting multi."
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: noPersist(oil),
@ -734,7 +751,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Oil Integration",
description: "Reduce Oil Pump's coal consumption multipler from 5 to 4"
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: noPersist(oil),
@ -748,7 +767,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
</>
))
},
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
}))
];
const row3Upgrades = [
@ -761,7 +782,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
},
visibility: () =>
showIf(management.elfTraining.oilElfTraining.milestones[4].earned.value),
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: noPersist(oil),
@ -772,7 +795,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
},
visibility: () =>
showIf(management.elfTraining.oilElfTraining.milestones[4].earned.value),
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: noPersist(oil),
@ -788,7 +813,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
},
visibility: () =>
showIf(management.elfTraining.oilElfTraining.milestones[4].earned.value),
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: noPersist(oil),
@ -799,7 +826,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
},
visibility: () =>
showIf(management.elfTraining.oilElfTraining.milestones[4].earned.value),
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
})),
createUpgrade(() => ({
resource: noPersist(oil),
@ -810,7 +839,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
},
visibility: () =>
showIf(management.elfTraining.oilElfTraining.milestones[4].earned.value),
style: { color: colorText }
style() {
return this.bought.value ? "" : { color: colorText };
}
}))
];
const coalConsumption = createSequentialModifier(() => [
@ -964,7 +995,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: 50,
description: "350 toys",
enabled: toys.milestones.milestone4.earned
}))
})),
reindeer.reindeer.donner.modifier
]) as WithRequired<Modifier, "description" | "revert">;
const computedOilSpeed = computed(() => oilSpeed.apply(0));

View file

@ -27,6 +27,7 @@ import dyes from "./dyes";
import elves, { ElfBuyable } from "./elves";
import management from "./management";
import plastic from "./plastic";
import reindeer from "./reindeer";
import ribbon from "./ribbon";
import trees from "./trees";
import workshop from "./workshop";
@ -423,7 +424,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: wrappingPaper.boosts.sunshine1,
description: "Sunshine Wrapping Paper",
enabled: () => Decimal.gte(wrappingPaper.boosts.sunshine1.value, 2)
}))
})),
reindeer.reindeer.prancer.modifier
]) as WithRequired<Modifier, "description" | "revert">;
const ashCost = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({

View file

@ -37,6 +37,7 @@ import oil from "./oil";
import paper from "./paper";
import workshop from "./workshop";
import toys from "./toys";
import reindeer from "./reindeer";
const id = "plastic";
const day = 10;
@ -383,7 +384,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
createMultiplicativeModifier(() => ({
multiplier: () => dyes.boosts.white1.value,
description: "White Dye Boost"
}))
})),
reindeer.reindeer.blitzen.modifier
]);
const computedPlasticGain = computed(() => plasticGain.apply(0));

View file

@ -0,0 +1,592 @@
/**
* @module
* @hidden
*/
import HotkeyVue from "components/Hotkey.vue";
import Spacer from "components/layout/Spacer.vue";
import Modal from "components/Modal.vue";
import { createCollapsibleModifierSections } from "data/common";
import { main } from "data/projEntry";
import { createBar, GenericBar } from "features/bars/bar";
import { createClickable } from "features/clickables/clickable";
import { jsx } from "features/feature";
import { createHotkey, GenericHotkey } from "features/hotkey";
import { createUpgrade } from "features/upgrades/upgrade";
import { globalBus } from "game/events";
import { BaseLayer, createLayer } from "game/layers";
import {
createAdditiveModifier,
createMultiplicativeModifier,
createSequentialModifier
} from "game/modifiers";
import { persistent } from "game/persistence";
import Decimal, { DecimalSource, format, formatTime, formatWhole } from "util/bignum";
import { Direction } from "util/common";
import { render, renderGrid } from "util/vue";
import { computed, ref, unref, watchEffect } from "vue";
import boxes from "./boxes";
import cloth from "./cloth";
import coal from "./coal";
import dyes from "./dyes";
import metal from "./metal";
import oil from "./oil";
import paper from "./paper";
import plastic from "./plastic";
import "./styles/reindeer.css";
import trees from "./trees";
const id = "reindeer";
const day = 21;
const layer = createLayer(id, function (this: BaseLayer) {
const name = "Reindeer";
const color = "saddlebrown";
const feedGoal = 1.5e3;
const timeSinceFocus = persistent<number>(0);
const currMultiplier = persistent<DecimalSource>(1);
const currTargets = persistent<Record<string, boolean>>({});
const currCooldown = persistent<number>(0);
const crit = persistent<number>(0);
const maxMultiplier = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "Carry food in boxes",
enabled: upgrade4.bought
}))
]);
const computedMaxMultiplier = computed(() => maxMultiplier.apply(2));
const targetsCount = createSequentialModifier(() => [
createAdditiveModifier(() => ({
addend: 1,
description: "Guide to Reindeer Handling",
enabled: upgrade3.bought
})),
createAdditiveModifier(() => ({
addend: crit,
description: "Metal clapper",
enabled: upgrade5.bought
}))
]);
const computedTargetsCount = computed(() => targetsCount.apply(1));
const computedMaxCooldown = computed(() => 10);
function focus() {
let targetsSelected = 0;
currTargets.value = {};
timeSinceFocus.value = 0;
while (Decimal.gt(computedTargetsCount.value, targetsSelected)) {
const selectedReindeer =
Object.values(reindeer)[Math.floor(Math.random() * Object.values(reindeer).length)];
const roll = selectedReindeer?.name ?? "";
if (!currTargets.value[roll]) {
currTargets.value[roll] = true;
targetsSelected++;
if (upgrade8.bought.value) {
selectedReindeer.onClick();
}
}
}
}
const focusMeter = createBar(() => ({
direction: Direction.Right,
width: 476,
height: 50,
style: `border-radius: 0`,
borderStyle: `border-radius: 0`,
fillStyle: () => ({
background: currCooldown.value > 0 ? color : "#7f7f00",
animation: currCooldown.value > 0 ? "1s focused-eating-bar linear infinite" : "",
opacity: currCooldown.value > 0 ? currCooldown.value / 10 : 1,
transition: "none"
}),
progress: () =>
Decimal.sub(currMultiplier.value, 1)
.div(Decimal.sub(computedMaxMultiplier.value, 1))
.toNumber(),
display: jsx(() => (
<>
{format(currMultiplier.value)}x
{currCooldown.value > 0 ? (
<>
{" "}
to {Object.keys(currTargets.value).join(", ")} for{" "}
{formatTime(currCooldown.value)}
</>
) : (
""
)}
</>
))
})) as GenericBar;
const focusButton = createClickable(() => ({
display: {
title: "Focus",
description: jsx(() => (
<>
Motivate reindeer to eat, multiplying {formatWhole(computedTargetsCount.value)}{" "}
random reindeer's eating rate by up to {format(computedMaxMultiplier.value)}x
for {formatTime(computedMaxCooldown.value)}, equal to the focus bar's effect.
</>
))
},
style: {
width: "480px",
minHeight: "80px",
zIndex: 4
},
canClick: () => Decimal.eq(currCooldown.value, 0),
onClick() {
currCooldown.value = Decimal.fromValue(computedMaxCooldown.value).toNumber();
focus();
}
}));
const cooldown = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: 0.5,
description: "Pile of coal",
enabled: upgrade2.bought
}))
]);
const computedCooldown = computed(() => cooldown.apply(10));
function createReindeer(options: {
name: string;
key: string;
boostDescription: string;
boostAmount: DecimalSource;
}) {
const timesFed = persistent<DecimalSource>(0);
const progress = persistent<DecimalSource>(0);
const hotkey = createHotkey(() => ({
key: "Numpad " + options.key,
description: "Feed " + options.name,
enabled: main.days[day - 1].opened,
onPress: clickable.onClick
})) as GenericHotkey;
const clickable = createClickable(() => {
const progressBar = createBar(() => ({
direction: Direction.Right,
width: 140,
height: 10,
style: "margin-top: 8px",
borderStyle: "border-color: black",
baseStyle: "margin-top: -1px",
fillStyle: () => ({
marginTop: "-1px",
transitionDuration: "0s",
background: "black",
animation:
currTargets.value[options.name] && currCooldown.value > 0
? ".5s focused-eating-bar linear infinite"
: ""
}),
progress: () => Decimal.div(progress.value, computedCooldown.value)
}));
const modifier = createMultiplicativeModifier(() => ({
multiplier: effect,
description: options.name,
enabled: () => Decimal.gt(timesFed.value, 0)
}));
const effect = computed(() =>
Decimal.times(options.boostAmount, timesFed.value)
.add(1)
.pow(upgrade9.bought.value ? 1.1 : 1)
);
return {
...options,
hotkey,
timesFed,
progress,
effect,
modifier,
display: {
title: jsx(() => (
<h3>
Feed {options.name} <HotkeyVue hotkey={hotkey} />
</h3>
)),
description: jsx(() => (
<>
<br />
Each time you feed {options.name} will increase your{" "}
{options.boostDescription} by +{format(options.boostAmount)}x
<Spacer />
Currently {format(effect.value)}x
<br />
{render(progressBar)}
</>
))
},
style: {
width: "160px",
height: "160px"
},
canClick() {
return Decimal.gte(progress.value, computedCooldown.value);
},
onClick() {
if (!unref(clickable.canClick)) {
return;
}
let amount = Decimal.div(progress.value, computedCooldown.value);
if (upgrade1.bought.value) {
amount = Decimal.times(amount, 2);
}
timesFed.value = Decimal.add(timesFed.value, amount);
progress.value = 0;
},
update(diff: number) {
if (Decimal.gte(progress.value, computedCooldown.value)) {
progress.value = computedCooldown.value;
} else {
let amount: DecimalSource = diff;
const isFocused = currTargets.value[options.name] && currCooldown.value > 0;
if (isFocused) {
amount = Decimal.times(amount, currMultiplier.value);
}
progress.value = Decimal.add(progress.value, amount);
if (clickable.isHolding.value || (upgrade8.bought.value && isFocused)) {
clickable.onClick();
}
}
}
};
});
return clickable;
}
const dasher = createReindeer({
name: "Dasher",
key: "7",
boostDescription: "log gain",
boostAmount: 1
});
const dancer = createReindeer({
name: "Dancer",
key: "8",
boostDescription: "coal gain",
boostAmount: 0.1
});
const prancer = createReindeer({
name: "Prancer",
key: "9",
boostDescription: "paper gain",
boostAmount: 0.1
});
const vixen = createReindeer({
name: "Vixen",
key: "4",
boostDescription: "boxes gain",
boostAmount: 0.1
});
const comet = createReindeer({
name: "Comet",
key: "5",
boostDescription: "metal gain",
boostAmount: 0.1
});
const cupid = createReindeer({
name: "Cupid",
key: "6",
boostDescription: "cloth actions",
boostAmount: 0.1
});
const donner = createReindeer({
name: "Donner",
key: "1",
boostDescription: "oil gain",
boostAmount: 0.01
});
const blitzen = createReindeer({
name: "Blitzen",
key: "2",
boostDescription: "plastic gain",
boostAmount: 0.1
});
const rudolph = createReindeer({
name: "Rudolph",
key: "3",
boostDescription: "dye gain",
boostAmount: 0.01
});
// order is designed so hotkeys appear 1-9, even though they're displayed in numpad order in the layer itself
const reindeer = { donner, blitzen, rudolph, vixen, comet, cupid, dasher, dancer, prancer };
const sumTimesFed = computed(() =>
Object.values(reindeer)
.map(r => r.timesFed.value)
.reduce(Decimal.add, Decimal.dZero)
);
const upgrade1 = createUpgrade(() => ({
resource: trees.logs,
cost: 1e97,
style: {
width: "160px"
},
display: {
title: "Sawdust?",
description:
"Adding some sawdust to the feed allows you to make more of it. Each feed action counts twice"
}
}));
const upgrade2 = createUpgrade(() => ({
resource: coal.coal,
cost: 1e167,
style: {
width: "160px"
},
display: {
title: "Pile of coal",
description:
"Building a threatening pile of coal encourages the reindeer to behave. Each reindeer eats twice as fast"
}
}));
const upgrade3 = createUpgrade(() => ({
resource: paper.paper,
cost: 1e117,
style: {
width: "160px"
},
display: {
title: "Guide to Reindeer Handling",
description:
"Written reindeer handling instructions allow you to help more focus at once. Increase focus targets by one"
}
}));
const upgrade4 = createUpgrade(() => ({
resource: boxes.boxes,
cost: 1e102,
style: {
width: "160px"
},
display: {
title: "Carry food in boxes",
description:
"Carrying reindeer food in boxes allows you to distribute it faster. Double the maximum focus multiplier"
}
}));
const upgrade5 = createUpgrade(() => ({
resource: metal.metal,
cost: 1e67,
style: {
width: "160px"
},
display: {
title: "Metal clapper",
description:
'Striking two rods of metal can help get more reindeer\'s attention when done right. "Critical" focuses now affect up to two additional reindeer'
}
}));
const upgrade6 = createUpgrade(() => ({
resource: cloth.cloth,
cost: 1e20,
style: {
width: "160px"
},
display: {
title: "Focus bar padding",
description:
"Adding padding to the focus bar lets you slow it down when it's closer to the max value"
}
}));
const upgrade7 = createUpgrade(() => ({
resource: oil.oil,
cost: 4e25,
style: {
width: "160px"
},
display: {
title: "Oil can do that?",
description:
"Using a lot of oil somehow let's reindeers focus themselves with a random value when left un-focused for 10s"
}
}));
const upgrade8 = createUpgrade(() => ({
resource: plastic.plastic,
cost: 1e22,
style: {
width: "160px"
},
display: {
title: "Autoamted feeder",
description: "An automated feeder let's focused reindeer eat automatically"
}
}));
const upgrade9 = createUpgrade(() => ({
resource: dyes.dyes.white.amount,
cost: 7.5e7,
style: {
width: "160px"
},
display: {
title: "Colorful food",
description:
"Adding some non-toxic dyes to the food makes them more powerful. Raise each reindeer's effect to the ^1.1"
}
}));
const upgrades = {
upgrade1,
upgrade2,
upgrade3,
upgrade4,
upgrade5,
upgrade6,
upgrade7,
upgrade8,
upgrade9
};
const [generalTab, generalTabCollapsed] = createCollapsibleModifierSections(() => [
{
title: "Max Focus Multiplier",
modifier: maxMultiplier,
base: 2
},
{
title: "Focus Targets",
modifier: targetsCount,
base: 1
},
{
title: "Eating duration",
modifier: cooldown,
base: 10
}
]);
const showModifiersModal = ref(false);
const modifiersModal = jsx(() => (
<Modal
modelValue={showModifiersModal.value}
onUpdate:modelValue={(value: boolean) => (showModifiersModal.value = value)}
v-slots={{
header: () => <h2>{name} Modifiers</h2>,
body: generalTab
}}
/>
));
globalBus.on("update", diff => {
if (Decimal.lt(main.day.value, day)) {
return;
}
Object.values(reindeer).forEach(reindeer => reindeer.update(diff));
currCooldown.value = Math.max(currCooldown.value - diff, 0);
let auto = false;
if (upgrade7.bought.value) {
timeSinceFocus.value += diff;
if (timeSinceFocus.value > 10) {
auto = true;
}
}
if (Decimal.eq(currCooldown.value, 0)) {
let speed = 1000;
if (auto) {
speed = Math.random() * 1000;
}
let stoppedAt = 1 - Math.abs(Math.sin((Date.now() / speed) * 2));
if (upgrade6.bought.value) {
stoppedAt = 1 - (1 - stoppedAt) ** 2;
}
crit.value = stoppedAt > 0.975 ? 2 : stoppedAt > 0.9 ? 1 : 0;
currMultiplier.value = Decimal.pow(computedMaxMultiplier.value, stoppedAt);
if (auto) {
focus();
}
}
});
const dayProgress = createBar(() => ({
direction: Direction.Right,
width: 600,
height: 25,
fillStyle: `backgroundColor: ${color}`,
progress: () => (main.day.value === day ? Decimal.div(sumTimesFed.value, feedGoal) : 1),
display: jsx(() =>
main.day.value === day ? (
<>
{formatWhole(sumTimesFed.value)}/{formatWhole(feedGoal)}
</>
) : (
""
)
)
})) as GenericBar;
watchEffect(() => {
if (main.day.value === day && Decimal.gte(sumTimesFed.value, feedGoal)) {
main.completeDay();
}
});
return {
name,
day,
color,
reindeer,
generalTabCollapsed,
timeSinceFocus,
currMultiplier,
currTargets,
currCooldown,
upgrades,
crit,
minWidth: 700,
display: jsx(() => (
<>
<div>
{main.day.value === day
? `Feed reindeer ${formatWhole(feedGoal)} times to complete the day`
: `${name} Complete!`}{" "}
-{" "}
<button
class="button"
style="display: inline-block;"
onClick={() => (showModifiersModal.value = true)}
>
Check Modifiers
</button>
</div>
{render(dayProgress)}
{render(modifiersModal)}
<Spacer />
<div>You have fed reindeer {formatWhole(sumTimesFed.value)} times</div>
<Spacer />
{renderGrid(
[focusButton],
[focusMeter],
[dasher, dancer, prancer],
[vixen, comet, cupid],
[donner, blitzen, rudolph]
)}
<Spacer />
{renderGrid(
[upgrade1, upgrade2, upgrade3],
[upgrade4, upgrade5, upgrade6],
[upgrade7, upgrade8, upgrade9]
)}
</>
)),
minimizedDisplay: jsx(() => (
<div>
{name} <span class="desc">{format(sumTimesFed.value)} times fed</span>
</div>
))
};
});
export default layer;

View file

@ -93,7 +93,6 @@ const layer = createLayer(id, () => {
if (!unref(makeRibbon.canClick)) {
return;
}
currentDyeType.value.amount.value = 0;
currentDyeType.value.buyable.amount.value = 0;
cloth.cloth.value = Decimal.sub(cloth.cloth.value, 1e9);
ribbon.value = Decimal.add(ribbon.value, 1);

225
src/data/layers/sleigh.tsx Normal file
View file

@ -0,0 +1,225 @@
/**
* @module
* @hidden
*/
import Spacer from "components/layout/Spacer.vue";
import { createCollapsibleMilestones} from "data/common";
import { main } from "data/projEntry";
import { createBar } from "features/bars/bar";
import { jsx, showIf } from "features/feature";
import { createMilestone } from "features/milestones/milestone";
import { BaseLayer, createLayer } from "game/layers";
import Decimal, { DecimalSource, format, formatWhole } from "util/bignum";
import { Direction} from "util/common";
import { render } from "util/vue";
import { computed, watchEffect } from "vue";
import management from "./management";
import trees from "./trees";
import metal from "./metal";
import plastic from "./plastic"
import { createBuyable, GenericBuyable } from "features/buyable";
import { Resource } from "features/resources/resource";
import { isArray } from "@vue/shared";
const id = "sleigh";
const day = 22;
const layer = createLayer(id, function (this: BaseLayer) {
const name = "Sleigh";
const color = "#D71830";
const colorDark = "#A01020";
function displayCost(
res: Resource<DecimalSource> | Resource<DecimalSource>[],
cost: DecimalSource,
label: string
) {
const affordable = (isArray(res) ? res : [res]).every(res => Decimal.gte(res.value, cost));
return (
<span class={affordable ? "" : "unaffordable"}>
{format(cost)} {label}
</span>
);
}
const sleighProgress = computed(() => sleigh.amount)
const sleighCost = computed(() => {
let v = sleighProgress.value.value;
return {
wood: Decimal.mul(1e60, Decimal.pow(1.2, v)),
metal: Decimal.mul(1e40, Decimal.pow(1.1, v)),
plastic: Decimal.mul(1e10, Decimal.pow(1.05, v))
};
});
const sleigh = createBuyable(() => ({
display: jsx(() => (
<>
<b style="font-size: x-large">Fix 1% of the sleigh</b>
<br />
<br />
<span style="font-size: large">
Cost: {displayCost(trees.logs, sleighCost.value.wood, "logs")},
{displayCost(metal.metal, sleighCost.value.metal, "metal")},
{displayCost(plastic.plastic, sleighCost.value.plastic, "plastic")}
</span>
</>
)),
canPurchase(): boolean {
return (
sleighCost.value.wood.lte(trees.logs.value) &&
sleighCost.value.metal.lte(metal.metal.value) &&
sleighCost.value.plastic.lte(plastic.plastic.value)
);
},
onPurchase() {
this.amount.value = Decimal.add(this.amount.value, 1);
},
visibility: () => showIf(Decimal.lt(sleighProgress.value.value, 100)),
style: "width: 600px"
})) as GenericBuyable;
const shouldShowPopups = computed(() => true);
const milestone1 = createMilestone(() => ({
display: {
requirement: "1% Sleigh Fixed",
effectDisplay: "Ore gives 5% more metal for each % of sleigh fixed"
},
shouldEarn: () => Decimal.gte(sleighProgress.value.value, 1),
showPopups: shouldShowPopups
}));
const milestone2 = createMilestone(() => ({
display: {
requirement: "10% Sleigh Fixed",
effectDisplay: "Gain an additional 5% more wood for each 5% of sleigh fixed"
},
shouldEarn: () => Decimal.gte(sleighProgress.value.value, 10),
showPopups: shouldShowPopups
}));
const milestone3 = createMilestone(() => ({
display: {
requirement: "20% Sleigh Fixed",
effectDisplay: "Gain an additional 5% more plastic for each 5% of sleigh fixed"
},
shouldEarn: () => Decimal.gte(sleighProgress.value.value, 20),
showPopups: shouldShowPopups
}));
const milestone4 = createMilestone(() => ({
display: {
requirement: "30% Sleigh Fixed",
effectDisplay: "All automatic metal actions are doubled"
},
shouldEarn: () => Decimal.gte(sleighProgress.value.value, 30),
showPopups: shouldShowPopups
}));
const milestone5 = createMilestone(() => ({
display: {
requirement: "40% Sleigh Fixed",
effectDisplay: "Plastic gain is doubled"
},
shouldEarn: () => Decimal.gte(sleighProgress.value.value, 40),
showPopups: shouldShowPopups
}));
const milestone6 = createMilestone(() => ({
display: {
requirement: "50% Sleigh Fixed",
effectDisplay: "Trees give 10x as many logs"
},
shouldEarn: () => Decimal.gte(sleighProgress.value.value, 50),
showPopups: shouldShowPopups
}));
const milestone7 = createMilestone(() => ({
display: {
requirement: "75% Sleigh Fixed",
effectDisplay: "Gain 10 extra refineries for every 2% of sleigh fixed"
},
shouldEarn: () => Decimal.gte(sleighProgress.value.value, 75),
showPopups: shouldShowPopups
}));
const milestone8 = createMilestone(() => ({
display: {
requirement: "100% Sleigh Fixed",
effectDisplay: "Metal per ore is raised to the 1.2th power"
},
shouldEarn: () => Decimal.gte(sleighProgress.value.value, 100),
showPopups: shouldShowPopups
}));
const milestones = {
milestone1,
milestone2,
milestone3,
milestone4,
milestone5,
milestone6,
milestone7,
milestone8
};
const { collapseMilestones, display: milestonesDisplay } =
createCollapsibleMilestones(milestones);
const dayProgress = createBar(() => ({
direction: Direction.Right,
width: 600,
height: 25,
fillStyle: `backgroundColor: ${colorDark}`,
progress: () =>
main.day.value === day || main.currentlyMastering.value?.name === name
? Decimal.div(sleighProgress.value.value, 100)
: 1,
display: jsx(() =>
main.day.value === day || main.currentlyMastering.value?.name === name ? (
<>{formatWhole(sleighProgress.value.value)}%</>
) : (
""
)
)
}));
watchEffect(() => {
if (main.day.value === day && Decimal.gte(sleighProgress.value.value, 100)) {
main.completeDay();
}
});
return {
name,
day,
color,
sleighProgress,
milestones,
collapseMilestones,
minWidth: 700,
sleigh,
display: jsx(() => (
<>
<div>
{main.day.value === day
? `Fix the sleigh to complete the day`
: `${name} Complete!`}
</div>
{render(dayProgress)}
<Spacer />
<div>
<span>The sleigh is </span>
<h2 style={`color: ${color}; text-shadow: 0 0 10px ${color}`}>
{formatWhole(sleighProgress.value.value)}
</h2>
% fixed
</div>
{Decimal.lt(sleighProgress.value.value, 100) ||
management.elfTraining.expandersElfTraining.milestones[2].earned.value ? (
<Spacer />
) : null}
{render(sleigh)}
<Spacer />
{milestonesDisplay()}
</>
)),
minimizedDisplay: jsx(() => (
<div>
{name}{" "}
<span class="desc">
{formatWhole(sleighProgress.value.value)}% sleigh
</span>
</div>
)),
};
});
export default layer;

View file

@ -64,7 +64,7 @@
left: 0px;
right: 0px;
position: absolute;
background-color: var(--raised-background);
background-color: snow;
overflow: hidden;
z-index: 1;
}
@ -109,7 +109,7 @@
.comp-info {
position: absolute;
top: 0;
right: -10px;
right: 0px;
padding: 5px 10px;
width: max-content;
@ -125,13 +125,14 @@
pointer-events: none;
transition: transform 0.3s;
z-index: -1;
z-index: -2;
}
.comp-list .comp:nth-child(2n - 1) .comp-info {
right: -85px;
right: -75px;
}
.comp-list .comp:hover .comp-info {
transform: translateX(calc(20px + 100%));
z-index: -1;
}
.comp-list {
@ -150,8 +151,10 @@
justify-content: space-evenly;
align-items: flex-start;
align-content: flex-start;
justify-content: flex-start;
width: 148px;
direction: ltr;
text-align: left;
}
.comp-list::after {
@ -159,6 +162,7 @@
position: absolute;
border-right: solid 2px var(--locked);
background: var(--raised-background);
box-shadow: 0 2px 10px #0007;
top: 0;
bottom: 0;
left: 0;
@ -174,6 +178,11 @@
pointer-events: all;
}
.comp-list .comp > img:first-child {
width: 50px;
height: 50px;
}
.comp-list .comp:nth-child(3)::after,
.comp-list .comp:nth-child(4)::after {
content: "";
@ -190,7 +199,7 @@
.comp-list .comp:nth-child(4)::after {
left: -50px;
}
.comp-list .comp img.selected:not(.producedItem) {
.comp-list .comp img.selected, .comp-list .comp img.selected + img {
transform: translate(-5px, -5px);
filter: drop-shadow(2px 2px 0 var(--foreground)) drop-shadow(5px 5px 5px #0007);
}

View file

@ -0,0 +1,10 @@
@keyframes focused-eating-bar {
from {
background: 0 0 / 28px 28px repeat
repeating-linear-gradient(-45deg, brown 0 10px, saddlebrown 10px 20px);
}
to {
background: 28px 0px / 28px 28px repeat
repeating-linear-gradient(-45deg, brown 0 10px, saddlebrown 10px 20px);
}
}

View file

@ -40,6 +40,7 @@ import workshop from "./workshop";
import wrappingPaper from "./wrapping-paper";
import toys from "./toys";
import factory from "./factory";
import reindeer from "./reindeer";
const id = "trees";
const day = 1;
@ -557,6 +558,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: "Haul wood in trucks",
enabled: factory.upgrades[0][2].bought
})),
reindeer.reindeer.dasher.modifier,
createExponentialModifier(() => ({
exponent: 1.2,
description: "100% Foundation Completed",

View file

@ -30,6 +30,7 @@ import {
import { noPersist, persistent } from "game/persistence";
import Decimal, { DecimalSource, formatWhole } from "util/bignum";
import { Direction, WithRequired } from "util/common";
import { loadingSave } from "util/save";
import { render } from "util/vue";
import { computed, ref, unref, watchEffect } from "vue";
import elves from "./elves";
@ -143,6 +144,15 @@ const layer = createLayer(id, function (this: BaseLayer) {
style: "width: 600px; min-height: unset"
}));
watchEffect(() => {
if (
!loadingSave.value &&
Decimal.lt(computedMaxFoundation.value, foundationProgress.value)
) {
foundationProgress.value = Decimal.min(0, computedMaxFoundation.value);
}
});
const buildFoundationHK = createHotkey(() => ({
key: "w",
description: "Build foundation",

View file

@ -31,10 +31,12 @@ import metal from "./layers/metal";
import oil from "./layers/oil";
import paper from "./layers/paper";
import plastic from "./layers/plastic";
import reindeer from "./layers/reindeer";
import ribbon from "./layers/ribbon";
import toys from "./layers/toys";
import trees from "./layers/trees";
import workshop from "./layers/workshop";
import sleigh from "./layers/sleigh";
import wrappingPaper from "./layers/wrapping-paper";
import boxesSymbol from "./symbols/cardboardBox.png";
import clothSymbol from "./symbols/cloth.png";
@ -48,11 +50,13 @@ import metalSymbol from "./symbols/metal.png";
import oilSymbol from "./symbols/oil.png";
import paperSymbol from "./symbols/paperStacks.png";
import plasticSymbol from "./symbols/plastic.png";
import presentsSymbol from "./symbols/presents.png";
import reindeerSymbol from "./symbols/reindeer.png";
import ribbonsSymbol from "./symbols/ribbons.png";
import workshopSymbol from "./symbols/sws.png";
import advFactorySymbol from "./symbols/teddyBear.png";
import treeSymbol from "./symbols/tree.png";
import toysSymbol from "./symbols/truck.png";
import advFactorySymbol from "./symbols/teddyBear.png";
import advManagementSymbol from "./symbols/workshopMansion.png";
import wrappingPaperSymbol from "./symbols/wrappingPaper.png";
import snowflakeSymbol from "./symbols/snowflake.svg";
@ -585,27 +589,29 @@ export const main = createLayer("main", function (this: BaseLayer) {
createDay(() => ({
day: 20,
shouldNotify: false,
layer: null, // "presents"
symbol: wrappingPaperSymbol,
story: "",
completedStory: "",
layer: "factory",
symbol: presentsSymbol,
story: "Santa comes by again, and tells you that just toys may not be appealing enough. He tells you that you should probably wrap them in some wrapping paper so that it's more of a surprise. You try to argue that you've already done too much for him and deserve a day off, but Santa argues that it's for the benefit of everyone and that you'll get your vacation soon. Oh well, time to get back to the factory and expand it even more. Here we go again!",
completedStory:
"That was a lot of work, but it certainly felt worth actually using all those decorative supplies you'd previously made. One more sleepless night down, just a handful more to go. Good Job!",
masteredStory: ""
})),
createDay(() => ({
day: 21,
shouldNotify: false,
layer: null, // "reindeer"
symbol: "",
story: "",
completedStory: "",
layer: "reindeer",
symbol: reindeerSymbol,
story: "Now that the toys are being taken care of, it's time to make sure everything is prepped for the big night. One immediate concern is the reindeer, who are going to have to be in tip-top shape. Fortunately, Santa has a recipe to a very strong vitamin-filled kibble that'll get them pumped in no time!",
completedStory:
"Alright, now that the reindeer have been given all their ste- vitamins, I mean, they should be prepared for Christmas. Good Job!",
masteredStory: ""
})),
createDay(() => ({
day: 22,
shouldNotify: false,
layer: null, // "sleigh"
layer: "sleigh", // "sleigh"
symbol: "",
story: "",
story: "default body",
completedStory: "",
masteredStory: ""
})),
@ -749,7 +755,9 @@ export const getInitialLayers = (
wrappingPaper,
ribbon,
toys,
factory
factory,
reindeer,
sleigh
];
/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View file

@ -89,6 +89,9 @@ document.onkeydown = function (e) {
if (e.ctrlKey) {
key = "ctrl+" + key;
}
if (e.code.startsWith("Numpad") && `Numpad ${key}` in hotkeys) {
key = "Numpad " + key;
}
const hotkey = hotkeys[key];
if (hotkey && unref(hotkey.enabled)) {
e.preventDefault();

View file

@ -21,7 +21,7 @@ import type {
} from "util/computed";
import { processComputable } from "util/computed";
import { createLazyProxy } from "util/proxies";
import type { InjectionKey, Ref } from "vue";
import { computed, InjectionKey, Ref } from "vue";
import { ref, shallowReactive, unref } from "vue";
/** A feature's node in the DOM that has its size tracked. */
@ -231,6 +231,8 @@ export function createLayer<T extends LayerOptions>(
processComputable(layer as T, "color");
processComputable(layer as T, "display");
processComputable(layer as T, "classes");
processComputable(layer as T, "style");
processComputable(layer as T, "name");
setDefault(layer, "name", layer.id);
processComputable(layer as T, "minWidth");
@ -239,6 +241,34 @@ export function createLayer<T extends LayerOptions>(
setDefault(layer, "minimizable", true);
processComputable(layer as T, "minimizedDisplay");
const style = layer.style as ProcessedComputable<StyleValue> | undefined;
layer.style = computed(() => {
let width = unref(layer.minWidth as ProcessedComputable<number | string>);
if (typeof width === "number" || !Number.isNaN(parseInt(width))) {
width = width + "px";
}
return [
unref(style) ?? "",
layer.minimized?.value
? {
flexGrow: "0",
flexShrink: "0",
width: "60px",
minWidth: "",
flexBasis: "",
margin: "0"
}
: {
flexGrow: "",
flexShrink: "",
width: "",
minWidth: width,
flexBasis: width,
margin: ""
}
];
}) as Ref<StyleValue>;
return layer as unknown as Layer<T>;
});
}

View file

@ -14,7 +14,8 @@ export const {
formatSmall,
formatLimit,
invertOOM,
formatGain
formatGain,
formatList
} = numberUtils;
export type DecimalSource = RawDecimalSource;
@ -34,6 +35,7 @@ declare global {
formatLimit: (list: [DecimalSource, string][], unit: string) => string;
invertOOM: (x: DecimalSource) => Decimal;
formatGain: (x: DecimalSource) => string;
formatList: (x: string[]) => string;
}
}
window.Decimal = Decimal;
@ -48,5 +50,6 @@ window.formatSmall = formatSmall;
window.formatLimit = formatLimit;
window.invertOOM = invertOOM;
window.formatGain = formatGain;
window.formatList = formatList;
export default Decimal;

View file

@ -219,3 +219,9 @@ export function formatGain(gain: DecimalSource) {
1: `+${format(gain)}/s`
}[Decimal.compare(gain, 0)];
}
export function formatList(list: string[]) {
if (list.length <= 0) return "";
if (list.length == 1) return list[0];
return list.slice(0, -1).join(", ") + " and " + list[list.length - 1];
}