Merge branch 'main' into day-24-packing
1
saves/Day 19 Complete.txt
Normal file
1
saves/Day 20 Complete.txt
Normal file
1
saves/Day 21 Complete.txt
Normal file
|
@ -66,9 +66,8 @@ 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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -6,13 +6,25 @@
|
|||
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"
|
||||
class="scene-item"
|
||||
style="left: 26%; bottom: 12%; width: 40px; height: 40px"
|
||||
/>
|
||||
<img
|
||||
v-if="day >= 21"
|
||||
:src="sleigh"
|
||||
class="scene-item"
|
||||
style="left: 10%; bottom: 56%; transform: rotate(24deg); width: 100px; height: 100px"
|
||||
/>
|
||||
<img
|
||||
v-if="day >= 12"
|
||||
:src="advManagement"
|
||||
|
@ -46,6 +58,12 @@
|
|||
class="scene-item"
|
||||
style="left: 72%; bottom: 8%; width: 40px; height: 40px"
|
||||
/>
|
||||
<img
|
||||
v-if="day >= 22"
|
||||
:src="routing"
|
||||
class="scene-item"
|
||||
style="left: 76%; bottom: 4%; width: 40px; height: 40px"
|
||||
/>
|
||||
<img v-if="day >= 8" :src="oil" class="scene-item" style="left: 80%; bottom: 6%" />
|
||||
<div
|
||||
v-if="day >= 4"
|
||||
|
@ -69,6 +87,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 +112,10 @@ 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";
|
||||
import sleigh from "./symbols/sleigh.png";
|
||||
import routing from "./symbols/gps.png";
|
||||
|
||||
defineProps<{
|
||||
day: number;
|
||||
|
|
|
@ -247,9 +247,9 @@ export function createLayerTreeNode<T extends LayerTreeNodeOptions>(
|
|||
/** An option object for a modifier display as a single section. **/
|
||||
export interface Section {
|
||||
/** The header for this modifier. **/
|
||||
title: string;
|
||||
title: Computable<string>;
|
||||
/** A subtitle for this modifier, e.g. to explain the context for the modifier. **/
|
||||
subtitle?: string;
|
||||
subtitle?: Computable<string>;
|
||||
/** The modifier to be displaying in this section. **/
|
||||
modifier: WithRequired<Modifier, "description">;
|
||||
/** The base value being modified. **/
|
||||
|
@ -276,6 +276,8 @@ export function createCollapsibleModifierSections(
|
|||
base: ProcessedComputable<DecimalSource | undefined>[];
|
||||
baseText: ProcessedComputable<CoercableComponent | undefined>[];
|
||||
visible: ProcessedComputable<boolean | undefined>[];
|
||||
title: ProcessedComputable<string | undefined>[];
|
||||
subtitle: ProcessedComputable<string | undefined>[];
|
||||
}
|
||||
| Record<string, never> = {};
|
||||
let calculated = false;
|
||||
|
@ -285,6 +287,8 @@ export function createCollapsibleModifierSections(
|
|||
processed.base = sections.map(s => convertComputable(s.base));
|
||||
processed.baseText = sections.map(s => convertComputable(s.baseText));
|
||||
processed.visible = sections.map(s => convertComputable(s.visible));
|
||||
processed.title = sections.map(s => convertComputable(s.title));
|
||||
processed.subtitle = sections.map(s => convertComputable(s.subtitle));
|
||||
calculated = true;
|
||||
}
|
||||
return sections;
|
||||
|
@ -307,8 +311,10 @@ export function createCollapsibleModifierSections(
|
|||
>
|
||||
▼
|
||||
</span>
|
||||
{s.title}
|
||||
{s.subtitle != null ? <span class="subtitle"> ({s.subtitle})</span> : null}
|
||||
{unref(processed.title[i])}
|
||||
{unref(processed.subtitle[i]) != null ? (
|
||||
<span class="subtitle"> ({unref(processed.subtitle[i])})</span>
|
||||
) : null}
|
||||
</h3>
|
||||
);
|
||||
|
||||
|
|
|
@ -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(() => (
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
});
|
||||
|
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
123
src/data/layers/factory-components/boxmaker.svg
Normal 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,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAABHNCSVQICAgIfAhkiAAADmZJREFU
|
||||
eJzt3VtsHFcZB/B/bG9sbzxjx04czzgmTVIn2dlce0ENhKIkEpUQfQAJRHkp4gEBDyBAXAS8FIHo
|
||||
CxeJBxAPiL4gcXsBxKUiqYCWVvSWNNnZpG6SpolnHCd2vbO+Zn3hYXGbuN6z38zO2R03/5+0ause
|
||||
z3673v+enZkz3wJERERERERERERERERERERERERERERERERERERERERERERERGuZ3egCwmhudAF0
|
||||
R3kfgByAjwHYBWA9gKsASo0siigpvgZgaZXbSQDfRjlAFBOr0QVQaH/F6gG59TYG4HcAPg9gd2PK
|
||||
XJvaAXwEwA8BnEL5yXx/QyuiMJoB3ET1gKy8vQrg5wA+AWBT3atOuMMAvgXgBFZ/8r7euNIopA8h
|
||||
fDhWuz0L4PsAjgNYV9dHkAC7AHwOwG8B3ED1J+tvjSmTIvgB4gnIrbcZAH8G8FUAB+v3UOqnB8DH
|
||||
AfwMwHmEf4JKAFrqXjVF8V/EH5CVt6sAngDwaQADdXlUGhwD8D0A/0E8T8pD9S2fIuiF/nCsdjsN
|
||||
4McAHgaQ1v4oIzoA4CsA/gRgGvE/CY/X76FQRI+gMQFZeTsJ4Dto8OHkrQAeBfArAFeg/0E/X5dH
|
||||
RbX4BRofjpW3cZQPJ38Bmg8nLx9+/RHePvxa79sWnQ+QanYB1f+Gi4IxOm9DKB9OfhSAUesDPozy
|
||||
mc9Kh1/rfftUrQ+ItMmg8a+PsLfPLhcvPQK0C+Xjzkf//89u4e/Vy1EAv250EbSq48Jxoz/55IHF
|
||||
l9+YGMr7xVTOC/ZMzc13aa2ssieX/6VSQDpQXlB2GOUHOFiHoipZQvUTQtI/AtXfUcmgB3b0XNiY
|
||||
Xn/42J7evmN7egEAF0ancq4f3HC9wHT94JDWKt+WA/D68n9UCsgjKO9YJYHkbOl2AA4AV3MtFJ7o
|
||||
zStjGfMrf7azd0N2Z+8GPHzAwvzC0pzrFc7k/GDa9YK+N8ZndsVfKoDybsNbKgXkyQo/1y7d2lLI
|
||||
WkY+Y5ulQwNdd3/5N6ebINsJPw4GJGmOAOiUDHRsc5vq/7c0r2vdP9B13/6B8qeuienSyNnh4ELe
|
||||
D+D6hR3jU6W4Fq8+ddv9Vhh0GcBZAHtjulOljGWeylpGwbHNnp29HXsBPLD8/x7Y0fPscxfHJAE5
|
||||
CuCn2oqkKI5JBlld7Zd6jdbtYTbclU71HRns6Tsy2AMAuDo+M5TzCp7rF9OuH+y7Ob/YFqFeQDiD
|
||||
LA/UEpCB7vYhxzJ9xzbbs7a5L9XcVHEdjWMbC89dHJNslvshySMKSNYyrqL8MTmyrd3tg1u72wcf
|
||||
2tsHADjnF0/lvKAwNDrZmfeDgwDmUf2g1L8AFG/9geoXngLwpRpqfsvGdGrEsc0LjmUi22/u3Jhe
|
||||
Pwjhjr9jqafeW5gAPgDg31HrpFgZAD4oGejY5vq473yPZRzcY5VPZ3zj92cujwSzktfRiZU/qDaD
|
||||
RJJqbppzbOOMY5lTWdu0BrrTuwD0RdnWZqN1wO5qv+hNzOwQDD8GBiQpRLMHAGRsM6OriOvFuSvC
|
||||
cAAr9j8AdUAmAfwT1d8F5gG0ZPqMU4NbjIJjm50ZyzgI4D5hUVU5tnk1REAei+t+qSaigAxu6TiT
|
||||
TjXv01VEzgteh2xlbwGrvLlW+0x2AtUD0rLFbLv8zQ/v0bYe37GMtn+41yRDH0T5o1agqxYSE+5/
|
||||
mOM6i8j7RenJ8JOr/bCpyi+9Y8pZzbVgdttoce4NYSGhOba5J8Rw8dRO2twF4QEexza1ni3PeYH0
|
||||
fEmkgDwNYEKyddcLLgsLCa091Wzu2tLxinA4A9J4or9Ba0vT9O4+44CuIi7dmMoXZ0s9wuGRAlLx
|
||||
F1cKMZVF4tjmm8KhDEjjif4Gjt15VmcRrlccFQ69iAonmWMLSG64oHVNvWObG4VDs6jxmDrVTBYQ
|
||||
y5jVWUTOL0iXrVd8jccWkOLcfPelG1Palnrs3mLsb0s1TwmHcxZpnHsh7FmW7Te1tSFdWFyazw2L
|
||||
FzjWFJA8yhe8VJXzguvCgiJxbDMnHMqANI7oue/pWO/1d7XfrasI1wtOQ94WqKaAKDdwK9cPar4S
|
||||
SyXElMyANI7w8G7nRZ1FuH4wKRz6PICK5xBiDUhuOLhnYXFJWyPirG32C4f2IcYTlSTWDGFAMrah
|
||||
telbzgukl2ErX9uxBgQAcl4gPRwbmt3VvnNTx/ph4XDOIvV3HOWO7VVlbVPbRXjBzPz1y2PT0nNn
|
||||
sQRkFOXGX1W5nnhqiyRrd14SDmVA6k909eC2nvT5zvZUr64icl5hSDi0hJgCgmobWub6QaRFiVIZ
|
||||
y5DWfAzsulhvoksOsrY5orMI1ysuCoeeQHktYUWxB+Ty2PTuwkxJeoImtKzdKZ2aU+A1IvXUC+B+
|
||||
ycCMZXboLMT1C9LzYFWXUoUNyE3JwJwXSKe40Mz2ls3betLnhMNFUz7FQvpmtJS1zf26ivAmZi7c
|
||||
mLwpPZhT9ZKOMAFZkGwQAFxf72LavXanaGkvOIPUk+jNKNtvvtzctC6lq4icF0gP4owAeLHaoDAB
|
||||
AYSre10v0LrUI2MZ0in6PrDrYr2I3owcyyxWHxWd6xel16KL3uzDBkS00bHJm/bwxMxrIbct5tjm
|
||||
AZRbVUpwFtEvA0ByQRuytrlZZyGuF2SFQ0Vv9mED8hIAXzIwNxx4Ibct1ty0riXbb54SDud+iH6i
|
||||
NyGjLTW2fdMGR1cR568VX5ktLWwQDtcyg4g3HGKqiyRrdUqnas4g+sn2P2zzVZ1FuF4gvSTitu6J
|
||||
KlECItwPKWjtqeXYhvRE03LXRdIncvfEOLleIL0kQrwyRNsMMje/mD4/UjwdYfsi2zdtyJhtqRvC
|
||||
4ZxF9Imte2ItZkoLwavXJqWHj7UGZLnrYlWuF4gu143KsU3p+Rbuh+gTpnvie3QV4XqB9NwYEKKl
|
||||
VZSAANLVvX6g9WsSHNtYEA7lDKJPmO6J2rh+UXopxDu6J6poDcjQtcl906UFbWcNI3RdpHh1oIHd
|
||||
E2/lesFW4VDRPvSyqAERT1F5L8hHvI+qlrsuCodzFomf+DnV3T1R2FgQCNkxNGpAlrsuVuV6gWj9
|
||||
VlSObUqnbu6HxC9M90RTVxGuL245FSBka9qoAQHE+yFF6dQXiWMZ0vMtDyKGL2ek2ySie6LrFZuF
|
||||
Q0P3m9YeEH9iZnuCui7yY1Z8tiEh3RNdL5BeAhFq/wOoLSBPo9zwtyp2XXxXEr3Z1KN7YjBb2iQc
|
||||
XtcZRHyH7Lr4riTap0tQ98RLiPAVfbUGRDRlhWggHEnIrot3aSzlTiJc3p6Y7omRvu+mLjNIcbbU
|
||||
k6Cui9wPqd09SE73ROnXboTe/wBqD0ge5ca/VSWo6yIP99ZO9CZTp+6J0tdwQ2YQ8R0nqOsiZ5Da
|
||||
Cfc/TGmLpkjyflHaYuoFKLonqsQRENl+yHBwKEFdF+/VVccdoBnyy2u1FnLWK0gvp478fZt1m0EA
|
||||
rEtQ10XOItEdw9rrnhhp/wOIJyCjKDcAriovbygciWOJuy5yPyQ60aHyhHVPbOgMAmkBOU9v10XH
|
||||
FnddPA52XYxK+OU4ersn5n1x98STqNI9USWugIimsIR1XeRJw/B6AbxXMtCx9XZPzHni7oniqwdX
|
||||
E+cMsta6LjIg4YmfswR1T0xEQBakheS94lJM97mqrG1KD+cxIOHJVu/2my8lqHviC7XcV1wBAcTL
|
||||
3wvSC1siceSNke8Huy6GJd3/SEr3xJpmD6ABAalT10XpLMVZRC4DYKdkYIK6JyYqIC8iOV0XXxYO
|
||||
Z0DkRM+V0doynqDuiYkKCCD+kp3EdF1kQOSE+x+d53UWEbJ7Ys1LXRoTkOR0XdwBdl2Ukn055xrs
|
||||
nqjSkIDUo+ui0ZYaEw7nLFLdEQCiy2bXYvdElbgD8joS0nUxRKNkBqQ60dKcLWbb5QR1T0xkQAB5
|
||||
10VRw7GoMpZxWDj0oygf9eKt8u27kifyWjC77fG/nMMfXhxG3o//SK/rF0Vn8VHunhhLw0Id65FO
|
||||
AvhitUFD1yYxXVpAOiXt2BJO1ta71JpWlx8pIj9SxB9Pe0g1N8GxDTiWiaxtYqA7XdO2XU/8mo9l
|
||||
9gD0BUQk7wW4d5t0nyuczUYr+sw2jARaL4kmhdLCIk5fKeD0lXLzm43pFBzbLAem38TGtLwb6fXi
|
||||
HLyJGenwRAekiHLXxaofoVwNATnnF5HzAgyNTjIcCfPmdAnPvDaGZ14rHz8Z6G6HY5lw7PIMk2qu
|
||||
/Ik/xBfDhu6eqKJryfdJCAKSi+Fz6tXxGeS8Aly/CNcPcHNeugqaGu3K+AyujM/g77ny8rmMZSJr
|
||||
GXBsEzt7b18x5Hri10rkaz9WozMgj1Ub5E/MYLQ4h16jVbzhiekSzg4HyPsBXL+A8SltV/FSneX9
|
||||
8t8VLw0j3dqCrGUgY5s4NNCF5y5Kj9pHv3pwNevi3NgKExB+8xBRjLKI0CCuEh2HeZfFOtURCcXa
|
||||
f01nQGKd6ogagTMIkYLOfRBAeF3GE5+5X3MZtNY9+ktR4xwg5te0zhmEaM1jQIgUGBAiBQaESIEB
|
||||
IVJgQIgUGBAiBQaESIEBIVJgQIgUGBAiBQaESIEBIVJgQIgUGBAiBQaESIEBIVJgQIgUGBAiBQaE
|
||||
SIEBIVJgQIgUGBAiBQaESIEBIVJgQIgUGBAiBQaESIEBIVJgQIgUGBAiBQaESIEBIVJgQIgUGBAi
|
||||
BQaESIEBIVJgQIgUGBAiBQaESIEBIVJgQIgUGBAiBQaESIEBIVJgQIgUGBAiBQaESIEBIVJgQIgU
|
||||
GBAiBQaESIEBIVJgQIgUGBAiBQaESIEBIVJgQIgUGBAiBQaESIEBIVJgQIgUGBAiBQaESIEBIVJg
|
||||
QIgUGBAiBQaESIEBIVJYp3n7S5q3T7RSrK9pziBECgwIkQIDQqTAgBApMCBECgwIkQIDQqTAgBAp
|
||||
MCBEREREREREREREREREREREREREREREREREREREdIf7Hyed5/3C5bPrAAAAAElFTkSuQmCC
|
||||
"
|
||||
id="image727"
|
||||
x="0.74370372"
|
||||
y="0.35876995" /></g></svg>
|
After Width: | Height: | Size: 6.9 KiB |
|
@ -40,9 +40,11 @@ import _plastic from "../symbols/plastic.png";
|
|||
import boxes from "./boxes";
|
||||
import coal from "./coal";
|
||||
import dyes from "./dyes";
|
||||
import _box from "../symbols/cardboardBox.png";
|
||||
import _bear from "./factory-components/bear.svg";
|
||||
import _bearMaker from "./factory-components/bearmaker.svg";
|
||||
import _block from "./factory-components/block.svg";
|
||||
import _boxMaker from "./factory-components/boxmaker.svg";
|
||||
import _blockMaker from "./factory-components/blockmaker.svg";
|
||||
import _bucket from "./factory-components/bucket.svg";
|
||||
import _bucketMaker from "./factory-components/bucketmaker.svg";
|
||||
|
@ -75,6 +77,8 @@ import _truck from "./factory-components/truck.svg";
|
|||
import _truckMaker from "./factory-components/truckmaker.svg";
|
||||
import _wheel from "./factory-components/wheel.svg";
|
||||
import _wheelMaker from "./factory-components/wheelmaker.svg";
|
||||
import _present from "./factory-components/present.svg";
|
||||
import _presentMaker from "./factory-components/presentmaker.svg";
|
||||
import Factory from "./Factory.vue";
|
||||
import metal from "./metal";
|
||||
import oil from "./oil";
|
||||
|
@ -85,6 +89,7 @@ import Toy from "./Toy.vue";
|
|||
import toys from "./toys";
|
||||
import trees from "./trees";
|
||||
import workshop from "./workshop";
|
||||
import ribbon from "./ribbon";
|
||||
|
||||
const id = "factory";
|
||||
|
||||
|
@ -94,9 +99,7 @@ const presentsDay = 20;
|
|||
|
||||
const toyGoal = 750;
|
||||
const advancedToyGoal = 1500;
|
||||
|
||||
// 20x20 block size
|
||||
// TODO: unhardcode stuff
|
||||
const presentsGoal = 8e9;
|
||||
|
||||
function roundDownTo(num: number, multiple: number) {
|
||||
return Math.floor((num + multiple / 2) / multiple) * multiple;
|
||||
|
@ -138,6 +141,16 @@ const factory = createLayer(id, () => {
|
|||
const bears = createResource<DecimalSource>(0, "teddy bears");
|
||||
const bucketAndShovels = createResource<DecimalSource>(0, "shovel and pails");
|
||||
const consoles = createResource<DecimalSource>(0, "consoles");
|
||||
const presents = createResource<DecimalSource>(0, "presents");
|
||||
|
||||
const allToys = {
|
||||
clothes: toys.clothes,
|
||||
woodenBlocks: toys.woodenBlocks,
|
||||
trucks: toys.trucks,
|
||||
bears,
|
||||
bucketAndShovels,
|
||||
consoles
|
||||
};
|
||||
|
||||
function getRelativeCoords(e: MouseEvent) {
|
||||
const rect = (e.target as HTMLElement).getBoundingClientRect();
|
||||
|
@ -172,6 +185,11 @@ const factory = createLayer(id, () => {
|
|||
multiplier: 1.4,
|
||||
description: "6000 toys",
|
||||
enabled: toys.milestones.milestone6.earned
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () => Decimal.log10(trees.logs.value).div(100).add(1),
|
||||
description: "Burn some logs",
|
||||
enabled: betterLighting.bought
|
||||
}))
|
||||
]) as WithRequired<Modifier, "revert" | "description">;
|
||||
const computedEnergy = computed(() => energy.apply(0));
|
||||
|
@ -227,9 +245,33 @@ const factory = createLayer(id, () => {
|
|||
addend: expandFactory.amount,
|
||||
description: "Expand Factory",
|
||||
enabled: () => Decimal.gt(expandFactory.amount.value, 0)
|
||||
})),
|
||||
createAdditiveModifier(() => ({
|
||||
addend: 5,
|
||||
description: "Factory eXPerience",
|
||||
enabled: betterFactory.bought
|
||||
}))
|
||||
]);
|
||||
const computedFactorySize = computed(() => new Decimal(factorySize.apply(7)).toNumber());
|
||||
const presentMultipliers = createSequentialModifier(() => [
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: computedToyMultiplier,
|
||||
description: "Tickspeed overflow",
|
||||
enabled: () => computedToyMultiplier.value.gt(1)
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () =>
|
||||
Decimal.div(boxes.buyables3.presentBuyable.amount.value, 10).add(1).pow(2),
|
||||
description: "Carry presents in boxes",
|
||||
enabled: carryPresents.bought
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () => Decimal.add(ribbon.ribbon.value, 1),
|
||||
description: "With a bow",
|
||||
enabled: bowUpgrade.bought
|
||||
}))
|
||||
]);
|
||||
const computedPresentMultipliers = computed(() => presentMultipliers.apply(1));
|
||||
|
||||
const energyBar = createBar(() => ({
|
||||
width: 680,
|
||||
|
@ -317,6 +359,10 @@ const factory = createLayer(id, () => {
|
|||
return str;
|
||||
}
|
||||
|
||||
// this keeps track of which toy the present factory has consumed
|
||||
// it cycles around, so each toy is used evenly
|
||||
let toysIndex = 0;
|
||||
|
||||
const FACTORY_COMPONENTS = {
|
||||
cursor: {
|
||||
imageSrc: _cursor,
|
||||
|
@ -604,6 +650,26 @@ const factory = createLayer(id, () => {
|
|||
},
|
||||
visible: main.days[advancedDay - 1].opened
|
||||
} as FactoryComponentDeclaration,
|
||||
boxMaker: {
|
||||
imageSrc: _boxMaker,
|
||||
key: "shift+9",
|
||||
name: "Box Maker",
|
||||
type: "processor",
|
||||
description: computed(() => generateComponentDescription(FACTORY_COMPONENTS.boxMaker)),
|
||||
energyCost: 3,
|
||||
tick: 1,
|
||||
inputs: {
|
||||
plank: {
|
||||
amount: 2
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
box: {
|
||||
amount: 2
|
||||
}
|
||||
},
|
||||
visible: main.days[presentsDay - 1].opened
|
||||
} as FactoryComponentDeclaration,
|
||||
blocks: {
|
||||
imageSrc: _blockMaker,
|
||||
key: "ctrl+1",
|
||||
|
@ -755,6 +821,93 @@ const factory = createLayer(id, () => {
|
|||
}
|
||||
},
|
||||
visible: main.days[advancedDay - 1].opened
|
||||
} as FactoryComponentDeclaration,
|
||||
present: {
|
||||
imageSrc: _presentMaker,
|
||||
type: "processor",
|
||||
// idk about this
|
||||
key: "ctrl+7",
|
||||
name: "Present Wrapper",
|
||||
description: computed(
|
||||
() =>
|
||||
`Takes in 4 dye, 4 plastic, 1 cloth, 2 boxes, and ${formatWhole(
|
||||
computedToyMultiplier.value
|
||||
)} toys of any type (from storage) to produce ${formatWhole(
|
||||
computedPresentMultipliers.value
|
||||
)} presents every tick.` +
|
||||
(catalysts.bought.value
|
||||
? " You can feed it wheels, buttons, stuffing, and circuit boards to increase its output."
|
||||
: "")
|
||||
),
|
||||
tick: 1,
|
||||
energyCost: 50,
|
||||
inputs: {
|
||||
dye: {
|
||||
amount: 4
|
||||
},
|
||||
plastic: {
|
||||
amount: 4
|
||||
},
|
||||
cloth: {
|
||||
amount: 1
|
||||
},
|
||||
box: {
|
||||
amount: 2
|
||||
}
|
||||
},
|
||||
catalysts: computed(() => {
|
||||
if (!catalysts.bought.value) return [] as ResourceNames[];
|
||||
return {
|
||||
wheel: {
|
||||
amount: 1
|
||||
},
|
||||
buttons: {
|
||||
amount: 1
|
||||
},
|
||||
stuffing: {
|
||||
amount: 1
|
||||
},
|
||||
circuitBoard: {
|
||||
amount: 1
|
||||
}
|
||||
};
|
||||
}),
|
||||
canProduce: computed(() => {
|
||||
return Object.values(allToys).some(i =>
|
||||
Decimal.gte(i.value, computedToyMultiplier.value)
|
||||
);
|
||||
}),
|
||||
onProduce(times, stock) {
|
||||
const value = Object.values(allToys);
|
||||
|
||||
let sumCatalysts: DecimalSource = catalysts.bought.value
|
||||
? (["wheel", "buttons", "stuffing", "circuitBoard"] as const)
|
||||
.map(c => stock?.[c] ?? 0)
|
||||
.reduce(Decimal.add, Decimal.dZero)
|
||||
.add(1)
|
||||
: 1;
|
||||
if (stock) {
|
||||
(["wheel", "buttons", "stuffing", "circuitBoard"] as const).forEach(
|
||||
c => delete stock[c]
|
||||
);
|
||||
}
|
||||
|
||||
while (times > 0) {
|
||||
while (Decimal.lt(value[toysIndex].value, computedToyMultiplier.value)) {
|
||||
toysIndex = (toysIndex + 1) % value.length;
|
||||
}
|
||||
const toyToPick = Object.values(allToys)[toysIndex];
|
||||
toysIndex = (toysIndex + 1) % value.length;
|
||||
toyToPick.value = Decimal.sub(toyToPick.value, computedToyMultiplier.value);
|
||||
times--;
|
||||
presents.value = Decimal.add(
|
||||
presents.value,
|
||||
Decimal.times(computedPresentMultipliers.value, sumCatalysts)
|
||||
);
|
||||
sumCatalysts = 1;
|
||||
}
|
||||
},
|
||||
visible: main.days[presentsDay - 1].opened
|
||||
} as FactoryComponentDeclaration
|
||||
} as Record<string, FactoryComponentDeclaration>;
|
||||
const RESOURCES = {
|
||||
|
@ -784,6 +937,10 @@ const factory = createLayer(id, () => {
|
|||
name: "Planks",
|
||||
imageSrc: _plank
|
||||
},
|
||||
box: {
|
||||
name: "Boxes",
|
||||
imageSrc: _box
|
||||
},
|
||||
thread: {
|
||||
name: "Thread",
|
||||
imageSrc: _thread
|
||||
|
@ -901,9 +1058,13 @@ const factory = createLayer(id, () => {
|
|||
inputs?: Stock;
|
||||
/** amount it produces */
|
||||
outputs?: Stock;
|
||||
catalysts?: ProcessedComputable<Stock>;
|
||||
|
||||
/** on produce, do something */
|
||||
onProduce?: (times: number) => void;
|
||||
onProduce?: (
|
||||
times: number,
|
||||
stock: Partial<Record<ResourceNames, number>> | undefined
|
||||
) => void;
|
||||
/** can it produce? (in addtion to the stock check) */
|
||||
canProduce?: ComputedRef<boolean>;
|
||||
}
|
||||
|
@ -956,10 +1117,21 @@ const factory = createLayer(id, () => {
|
|||
|
||||
// trained elves
|
||||
|
||||
const costCheapener = createSequentialModifier(() => [
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () => Decimal.add(presents.value, 1).log10().add(1),
|
||||
description: "Excitment Upgrade",
|
||||
enabled: excitmentUpgrade.bought
|
||||
}))
|
||||
]);
|
||||
const computedCostCheapeners = computed(() => costCheapener.apply(1));
|
||||
|
||||
const clothesBuyable = createBuyable(() => ({
|
||||
resource: toys.clothes,
|
||||
cost() {
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5));
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5)).div(
|
||||
computedCostCheapeners.value
|
||||
);
|
||||
},
|
||||
display: {
|
||||
title: "Train elves to make clothes",
|
||||
|
@ -970,7 +1142,9 @@ const factory = createLayer(id, () => {
|
|||
const blocksBuyable = createBuyable(() => ({
|
||||
resource: toys.woodenBlocks,
|
||||
cost() {
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5));
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5)).div(
|
||||
computedCostCheapeners.value
|
||||
);
|
||||
},
|
||||
display: {
|
||||
title: "Train elves to make wooden blocks",
|
||||
|
@ -981,7 +1155,9 @@ const factory = createLayer(id, () => {
|
|||
const trucksBuyable = createBuyable(() => ({
|
||||
resource: toys.trucks,
|
||||
cost() {
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5));
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5)).div(
|
||||
computedCostCheapeners.value
|
||||
);
|
||||
},
|
||||
display: {
|
||||
title: "Train elves to make toy trucks",
|
||||
|
@ -992,7 +1168,9 @@ const factory = createLayer(id, () => {
|
|||
const bearsBuyable = createBuyable(() => ({
|
||||
resource: noPersist(bears),
|
||||
cost() {
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5));
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5)).div(
|
||||
computedCostCheapeners.value
|
||||
);
|
||||
},
|
||||
display: {
|
||||
title: "Train elves to make bears",
|
||||
|
@ -1004,7 +1182,9 @@ const factory = createLayer(id, () => {
|
|||
const bucketBuyable = createBuyable(() => ({
|
||||
resource: noPersist(bucketAndShovels),
|
||||
cost() {
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5));
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5)).div(
|
||||
computedCostCheapeners.value
|
||||
);
|
||||
},
|
||||
display: {
|
||||
title: "Train elves to make shovel and pails",
|
||||
|
@ -1016,7 +1196,9 @@ const factory = createLayer(id, () => {
|
|||
const consolesBuyable = createBuyable(() => ({
|
||||
resource: noPersist(consoles),
|
||||
cost() {
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5));
|
||||
return Decimal.pow(2, Decimal.add(this.amount.value, 5)).div(
|
||||
computedCostCheapeners.value
|
||||
);
|
||||
},
|
||||
display: {
|
||||
title: "Train elves to make consoles",
|
||||
|
@ -1089,7 +1271,88 @@ const factory = createLayer(id, () => {
|
|||
style: "width: 200px",
|
||||
visibility: () => showIf(main.days[advancedDay - 1].opened.value)
|
||||
})) as GenericBuyable;
|
||||
|
||||
const betterFactory = createUpgrade(() => ({
|
||||
resource: noPersist(presents),
|
||||
cost: 100,
|
||||
display: {
|
||||
title: "Factory eXPerience",
|
||||
description: "Factory size is increased by 5."
|
||||
},
|
||||
visibility: () => showIf(main.days[presentsDay - 1].opened.value)
|
||||
}));
|
||||
const betterLighting = createUpgrade(() => ({
|
||||
resource: noPersist(presents),
|
||||
cost: 300,
|
||||
display: {
|
||||
title: "Burn some logs",
|
||||
description: "More energy needed? Let's burn some logs! Logs boosts maximum energy.",
|
||||
effectDisplay: jsx(() => (
|
||||
<>x{format(Decimal.log10(trees.logs.value).div(100).add(1))}</>
|
||||
))
|
||||
},
|
||||
visibility: () => showIf(betterFactory.bought.value)
|
||||
}));
|
||||
const excitmentUpgrade = createUpgrade(() => ({
|
||||
resource: noPersist(presents),
|
||||
cost: 1000,
|
||||
display: {
|
||||
title: "Faster Elf Training",
|
||||
description:
|
||||
"Apparently elves like presents. Let's use it to train them to work on the factory faster! Presents divides the requirement for factory elf training.",
|
||||
effectDisplay: jsx(() => <>/{format(Decimal.add(presents.value, 1).log10().add(1))}</>)
|
||||
},
|
||||
visibility: () => showIf(betterLighting.bought.value)
|
||||
}));
|
||||
const carryPresents = createUpgrade(() => ({
|
||||
resource: noPersist(presents),
|
||||
cost: 5000,
|
||||
display: {
|
||||
title: "Carrying more stuff in boxes",
|
||||
description:
|
||||
"Boxes seem really useful for carrying stuff. Why don't we use them to carry presents as well? Unlocks 2 new buyables (one of them is in the boxes layer)."
|
||||
},
|
||||
visibility: () => showIf(excitmentUpgrade.bought.value)
|
||||
}));
|
||||
const carryBoxes = createBuyable(() => ({
|
||||
resource: noPersist(presents),
|
||||
cost() {
|
||||
return Decimal.add(carryBoxes.amount.value, 1)
|
||||
.pow(1.5)
|
||||
.mul(Decimal.pow(2, carryBoxes.amount.value))
|
||||
.mul(1000);
|
||||
},
|
||||
style: "width: 400px",
|
||||
display: {
|
||||
title: "Carry boxes in... presents?",
|
||||
description:
|
||||
"Presents are made out of boxes, so shouldn't they be able to hold boxes as well? Apparently it makes the boxes more durable. Each level multiplies boxes gain by 1.5.",
|
||||
effectDisplay: jsx(() => <>x{format(Decimal.pow(1.5, carryBoxes.amount.value))}</>)
|
||||
},
|
||||
visibility: () => showIf(carryPresents.bought.value)
|
||||
})) as GenericBuyable;
|
||||
const catalysts = createUpgrade(() => ({
|
||||
resource: noPersist(presents),
|
||||
cost: 10000,
|
||||
display: {
|
||||
title: "Better Presents",
|
||||
description:
|
||||
"Instead of trying to make more presents, how about we make the ones we make better? Unlocks catalysts for the present maker."
|
||||
},
|
||||
visibility: () => showIf(carryPresents.bought.value)
|
||||
}));
|
||||
const bowUpgrade = createUpgrade(() => ({
|
||||
resource: noPersist(presents),
|
||||
cost: 1e7,
|
||||
display: {
|
||||
title: "With a bow",
|
||||
description:
|
||||
"These presents need ribbon to make the bows, right? Multiply present gain by the amount of ribbon you have"
|
||||
},
|
||||
visibility: () => showIf(catalysts.bought.value)
|
||||
}));
|
||||
const factoryBuyables = { expandFactory, oilFuel, carryToys };
|
||||
const factoryBuyables2 = { carryBoxes };
|
||||
const upgrades = [
|
||||
[
|
||||
createUpgrade(() => ({
|
||||
|
@ -1205,7 +1468,9 @@ const factory = createLayer(id, () => {
|
|||
},
|
||||
visibility: () => showIf(main.days[advancedDay - 1].opened.value)
|
||||
}))
|
||||
]
|
||||
],
|
||||
[betterFactory, betterLighting, excitmentUpgrade, carryPresents],
|
||||
[catalysts, bowUpgrade]
|
||||
];
|
||||
|
||||
// pixi
|
||||
|
@ -1314,8 +1579,6 @@ const factory = createLayer(id, () => {
|
|||
|
||||
const factoryTicks = Decimal.times(computedActualTickRate.value, diff).toNumber();
|
||||
|
||||
//debugger
|
||||
// make them produce
|
||||
for (const id in components.value) {
|
||||
const [x, y] = id.split("x").map(p => +p);
|
||||
const _data = components.value[id];
|
||||
|
@ -1375,10 +1638,11 @@ const factory = createLayer(id, () => {
|
|||
const compData = _compData as FactoryInternalProcessor;
|
||||
// factory part
|
||||
// PRODUCTION
|
||||
data.ticksDone += factoryTicks;
|
||||
if (data.ticksDone >= factoryData.tick) {
|
||||
if (compData.canProduce.value) {
|
||||
const cyclesDone = Math.floor(data.ticksDone / factoryData.tick);
|
||||
factoryData.onProduce?.(cyclesDone);
|
||||
factoryData.onProduce?.(cyclesDone, data.inputStock);
|
||||
if (factoryData.inputs !== undefined) {
|
||||
if (data.inputStock === undefined) data.inputStock = {};
|
||||
for (const [key, val] of Object.entries(factoryData.inputs)) {
|
||||
|
@ -1412,8 +1676,6 @@ const factory = createLayer(id, () => {
|
|||
if (compData.lastProdTimes.length > 10) compData.lastProdTimes.shift();
|
||||
compData.lastFactoryProd = now;
|
||||
}
|
||||
} else {
|
||||
data.ticksDone += factoryTicks;
|
||||
}
|
||||
// now look at each component direction and see if it accepts items coming in
|
||||
// components are 1x1 so simple math for now
|
||||
|
@ -1825,6 +2087,20 @@ const factory = createLayer(id, () => {
|
|||
function togglePaused() {
|
||||
paused.value = !paused.value;
|
||||
}
|
||||
function handleDrag(drag: DragEvent, name: FactoryCompNames) {
|
||||
drag.dataTransfer!.setData("name", name);
|
||||
}
|
||||
function handleDrop(drag: DragEvent) {
|
||||
drag.preventDefault();
|
||||
const { tx, ty } = spriteContainer.localTransform;
|
||||
let { x, y } = getRelativeCoords(drag);
|
||||
x = roundDownTo(x - tx, blockSize) / blockSize;
|
||||
y = roundDownTo(y - ty, blockSize) / blockSize;
|
||||
const name = drag.dataTransfer!.getData("name");
|
||||
if (components.value[x + "x" + y] == null) {
|
||||
addFactoryComp(x, y, { type: name });
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------- Tabs
|
||||
|
||||
|
@ -1850,6 +2126,8 @@ const factory = createLayer(id, () => {
|
|||
src={item.imageSrc}
|
||||
class={{ selected: compSelected.value === key }}
|
||||
onClick={() => onCompClick(key)}
|
||||
draggable="true"
|
||||
onDragstart={drag => handleDrag(drag, key)}
|
||||
/>
|
||||
{item.extraImage == null ? null : (
|
||||
<img src={item.extraImage} class="producedItem" />
|
||||
|
@ -1885,7 +2163,7 @@ const factory = createLayer(id, () => {
|
|||
});
|
||||
|
||||
function showStockAmount(
|
||||
stocks: Partial<Record<ResourceNames, number>> | undefined,
|
||||
stocks: Partial<Record<ResourceNames, number>> | undefined | Record<string, never>,
|
||||
stockData: Stock | undefined,
|
||||
title: string,
|
||||
showAmount = true
|
||||
|
@ -1944,7 +2222,11 @@ const factory = createLayer(id, () => {
|
|||
<>
|
||||
{showStockAmount(
|
||||
(compHovered.value as FactoryComponentProcessor).inputStock,
|
||||
FACTORY_COMPONENTS[compHovered.value.type].inputs,
|
||||
{
|
||||
...(FACTORY_COMPONENTS[compHovered.value.type].inputs ?? {}),
|
||||
...(unref(FACTORY_COMPONENTS[compHovered.value.type].catalysts) ??
|
||||
{})
|
||||
},
|
||||
"Inputs:"
|
||||
)}
|
||||
{showStockAmount(
|
||||
|
@ -1961,12 +2243,12 @@ const factory = createLayer(id, () => {
|
|||
style={{
|
||||
color:
|
||||
(compInternalHovered.value as FactoryInternalProcessor)
|
||||
.average.value! > 1
|
||||
? "purple"
|
||||
.average.value! >= 0.995
|
||||
? "fuchsia"
|
||||
: (
|
||||
compInternalHovered.value as FactoryInternalProcessor
|
||||
).average.value! >= 0.9
|
||||
? "green"
|
||||
? "lime"
|
||||
: (
|
||||
compInternalHovered.value as FactoryInternalProcessor
|
||||
).average.value! >= 0.5
|
||||
|
@ -2002,6 +2284,8 @@ const factory = createLayer(id, () => {
|
|||
? `Reach ${format(
|
||||
advancedToyGoal
|
||||
)} for each toy to complete the day`
|
||||
: main.day.value === presentsDay
|
||||
? `Reach ${format(presentsGoal)} presents`
|
||||
: `${name} Complete!`}{" "}
|
||||
-{" "}
|
||||
<button
|
||||
|
@ -2022,7 +2306,7 @@ const factory = createLayer(id, () => {
|
|||
color="cornflowerblue"
|
||||
/>
|
||||
<Toy resource={toys.trucks} image={_truck} color="cadetblue" />
|
||||
{main.days[advancedDay - 1].opened.value ? (
|
||||
{main.days[advancedDay - 1].opened.value === true ? (
|
||||
<>
|
||||
<Toy resource={bears} image={_bear} color="teal" />
|
||||
<Toy
|
||||
|
@ -2037,6 +2321,11 @@ const factory = createLayer(id, () => {
|
|||
/>
|
||||
</>
|
||||
) : null}
|
||||
{main.days[presentsDay - 1].opened.value === true ? (
|
||||
<>
|
||||
<Toy resource={presents} image={_present} color="green" />
|
||||
</>
|
||||
) : undefined}
|
||||
</Row>
|
||||
<Spacer />
|
||||
<MainDisplay
|
||||
|
@ -2048,7 +2337,11 @@ const factory = createLayer(id, () => {
|
|||
/>
|
||||
{renderRow(...Object.values(elfBuyables))}
|
||||
<Spacer />
|
||||
{renderRow(...Object.values(factoryBuyables))}
|
||||
{renderGrid(
|
||||
Object.values(factoryBuyables),
|
||||
Object.values(factoryBuyables2)
|
||||
)}
|
||||
<Spacer />
|
||||
<Spacer />
|
||||
{renderGrid(...(upgrades as VueFeature[][]))}
|
||||
</>
|
||||
|
@ -2069,6 +2362,8 @@ const factory = createLayer(id, () => {
|
|||
onPointerenter={onFactoryMouseEnter}
|
||||
onPointerleave={onFactoryMouseLeave}
|
||||
onContextmenu={(e: MouseEvent) => e.preventDefault()}
|
||||
onDrop={(e: DragEvent) => handleDrop(e)}
|
||||
onDragover={(e: DragEvent) => e.preventDefault()}
|
||||
/>
|
||||
{componentsList()}
|
||||
{hoveredComponent()}
|
||||
|
@ -2095,6 +2390,11 @@ const factory = createLayer(id, () => {
|
|||
modifier: tickRate,
|
||||
base: 1,
|
||||
unit: "/s"
|
||||
},
|
||||
{
|
||||
title: "Present Multipliers",
|
||||
modifier: presentMultipliers,
|
||||
base: 1
|
||||
}
|
||||
]);
|
||||
const showModifiersModal = ref(false);
|
||||
|
@ -2111,7 +2411,10 @@ const factory = createLayer(id, () => {
|
|||
<>
|
||||
<br />
|
||||
Note: the actual tick rate is capped at 5 TPS, but you'll gain extra
|
||||
toys based on excessive tick rate as a compensation.
|
||||
toys based on excessive tick rate as compensation.{" "}
|
||||
{main.days[presentsDay - 1].opened.value === true
|
||||
? "Present maker's toy requirement and production is also affected by tick overflow."
|
||||
: undefined}
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
|
@ -2127,6 +2430,7 @@ const factory = createLayer(id, () => {
|
|||
width: 600,
|
||||
height: 25,
|
||||
fillStyle: `animation: 15s factory-bar linear infinite`,
|
||||
textStyle: `color: var(--feature-foreground)`,
|
||||
progress: () =>
|
||||
main.day.value === day
|
||||
? Decimal.div(toys.clothes.value, toyGoal)
|
||||
|
@ -2139,6 +2443,8 @@ const factory = createLayer(id, () => {
|
|||
.map(r => Decimal.div(r.value, advancedToyGoal).clampMax(1))
|
||||
.reduce(Decimal.add, Decimal.dZero)
|
||||
.div(6)
|
||||
: main.day.value === presentsDay
|
||||
? Decimal.div(presents.value, presentsGoal).clampMax(1)
|
||||
: 1,
|
||||
display: jsx(() =>
|
||||
main.day.value === day ? (
|
||||
|
@ -2164,6 +2470,10 @@ const factory = createLayer(id, () => {
|
|||
}{" "}
|
||||
/ 6
|
||||
</>
|
||||
) : main.day.value === presentsDay ? (
|
||||
<>
|
||||
{formatWhole(presents.value)}/{formatWhole(presentsGoal)} presents
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
)
|
||||
|
@ -2190,6 +2500,8 @@ const factory = createLayer(id, () => {
|
|||
].filter(d => Decimal.gte(d.value, advancedToyGoal)).length >= 6
|
||||
) {
|
||||
main.completeDay();
|
||||
} else if (main.day.value === presentsDay && Decimal.gte(presents.value, presentsGoal)) {
|
||||
main.completeDay();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2206,8 +2518,11 @@ const factory = createLayer(id, () => {
|
|||
bears,
|
||||
bucketAndShovels,
|
||||
consoles,
|
||||
presents,
|
||||
tabs,
|
||||
factoryBuyables,
|
||||
factoryBuyables2,
|
||||
carryBoxes,
|
||||
generalTabCollapsed,
|
||||
hotkeys,
|
||||
upgrades,
|
||||
|
|
|
@ -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);
|
||||
|
@ -339,7 +338,6 @@ const layer = createLayer(id, function (this: BaseLayer) {
|
|||
) : null}
|
||||
<MainDisplay resource={letters} color={color} />
|
||||
{render(process)}
|
||||
If your letters are stuck, try holding L
|
||||
{Decimal.lt(totalLetters.value, 8e9) ? (
|
||||
<div>
|
||||
The more letters you process, the more you'll improve at processing letters.
|
||||
|
|
|
@ -37,6 +37,8 @@ import plastic from "./plastic";
|
|||
import workshop from "./workshop";
|
||||
import wrappingPaper from "./wrapping-paper";
|
||||
import toys from "./toys";
|
||||
import reindeer from "./reindeer";
|
||||
import sleigh from "./sleigh";
|
||||
|
||||
const id = "metal";
|
||||
const day = 7;
|
||||
|
@ -105,10 +107,16 @@ 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",
|
||||
enabled: management.elfTraining.heatedPlanterElfTraining.milestones[1].earned
|
||||
})),
|
||||
createExponentialModifier(() => ({
|
||||
exponent: 1.2,
|
||||
description: "100% Sleigh Fixed",
|
||||
enabled: sleigh.milestones.milestone8.earned
|
||||
}))
|
||||
]);
|
||||
const computedOrePurity = computed(() => orePurity.apply(0.1));
|
||||
|
@ -180,6 +188,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
|
|||
description: "Jazzy Wrapping Paper",
|
||||
enabled: computed(() => Decimal.gt(wrappingPaper.boosts.jazzy1.value, 1))
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: 2,
|
||||
description: "30% Sleigh Fixed",
|
||||
enabled: sleigh.milestones.milestone4.earned
|
||||
})),
|
||||
createAdditiveModifier(() => ({
|
||||
addend: () => Decimal.sub(lastOreGained.value, lastOreSmelted.value).max(0),
|
||||
description: "Metal Decoration",
|
||||
|
@ -289,6 +302,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
|
|||
description: "1000 Letters Processed",
|
||||
enabled: letters.milestones.miningMilestone.earned
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: 2,
|
||||
description: "30% Sleigh Fixed",
|
||||
enabled: sleigh.milestones.milestone4.earned
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () => Decimal.add(toys.clothes.value, 1),
|
||||
description: "Give elves clothes to wear",
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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(() => ({
|
||||
|
|
|
@ -37,6 +37,8 @@ import oil from "./oil";
|
|||
import paper from "./paper";
|
||||
import workshop from "./workshop";
|
||||
import toys from "./toys";
|
||||
import reindeer from "./reindeer";
|
||||
import sleigh from "./sleigh";
|
||||
|
||||
const id = "plastic";
|
||||
const day = 10;
|
||||
|
@ -319,6 +321,14 @@ const layer = createLayer(id, function (this: BaseLayer) {
|
|||
description: "Oil Refinery",
|
||||
enabled: () => Decimal.gt(activeRefinery.value, 0)
|
||||
})),
|
||||
createAdditiveModifier(() => ({
|
||||
addend: () =>
|
||||
management.elfTraining.oilElfTraining.milestones[3].earned.value
|
||||
? Decimal.times(Decimal.div(sleigh.sleighProgress.value.value,2).floor(), 200)
|
||||
: Decimal.times(activeRefinery.value, 40),
|
||||
description: "75% Sleigh Fixed",
|
||||
enabled: sleigh.milestones.milestone7.earned
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: 2,
|
||||
description: "Paper Elf Recruitment",
|
||||
|
@ -383,7 +393,18 @@ const layer = createLayer(id, function (this: BaseLayer) {
|
|||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () => dyes.boosts.white1.value,
|
||||
description: "White Dye Boost"
|
||||
}))
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () => Decimal.div(sleigh.sleighProgress.value.value, 5).floor().mul(0.05).add(1),
|
||||
description: "20% Sleigh Fixed",
|
||||
enabled: sleigh.milestones.milestone3.earned
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: 4,
|
||||
description: "40% Sleigh Fixed",
|
||||
enabled: sleigh.milestones.milestone5.earned
|
||||
})),
|
||||
reindeer.reindeer.blitzen.modifier
|
||||
]);
|
||||
const computedPlasticGain = computed(() => plasticGain.apply(0));
|
||||
|
||||
|
|
592
src/data/layers/reindeer.tsx
Normal 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() {
|
||||
currCooldown.value = Decimal.fromValue(computedMaxCooldown.value).toNumber();
|
||||
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() {
|
||||
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: "Automated feeder",
|
||||
description: "An automated feeder lets 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 > 20) {
|
||||
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: `animation: 15s reindeer-bar linear infinite`,
|
||||
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;
|
|
@ -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);
|
||||
|
|
870
src/data/layers/routing.tsx
Normal file
|
@ -0,0 +1,870 @@
|
|||
/**
|
||||
* @module
|
||||
* @hidden
|
||||
*/
|
||||
import Spacer from "components/layout/Spacer.vue";
|
||||
import Modal from "components/Modal.vue";
|
||||
import { createCollapsibleMilestones, createCollapsibleModifierSections } from "data/common";
|
||||
import { main } from "data/projEntry";
|
||||
import { createBar, GenericBar } from "features/bars/bar";
|
||||
import { BoardNode, BoardNodeLink, createBoard, Shape } from "features/boards/board";
|
||||
import { createClickable } from "features/clickables/clickable";
|
||||
import { jsx, showIf } from "features/feature";
|
||||
import { createMilestone } from "features/milestones/milestone";
|
||||
import MainDisplay from "features/resources/MainDisplay.vue";
|
||||
import { createResource } from "features/resources/resource";
|
||||
import { globalBus } from "game/events";
|
||||
import { BaseLayer, createLayer } from "game/layers";
|
||||
import {
|
||||
createAdditiveModifier,
|
||||
createExponentialModifier,
|
||||
createMultiplicativeModifier,
|
||||
createSequentialModifier
|
||||
} from "game/modifiers";
|
||||
import { persistent } from "game/persistence";
|
||||
import Decimal, { DecimalSource, format, formatWhole } from "util/bignum";
|
||||
import { Direction } from "util/common";
|
||||
import { render, renderRow } from "util/vue";
|
||||
import { computed, ComputedRef, ref, unref, watchEffect } from "vue";
|
||||
import "./styles/routing.css";
|
||||
|
||||
const alpha = [
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z"
|
||||
];
|
||||
|
||||
const id = "routing";
|
||||
const day = 23;
|
||||
const layer = createLayer(id, function (this: BaseLayer) {
|
||||
const name = "Routing";
|
||||
const color = "navajowhite";
|
||||
|
||||
const citiesGoal = 10;
|
||||
|
||||
const citiesCompleted = createResource<DecimalSource>(0, "countries solved");
|
||||
const currentCity = persistent<number[][]>([]);
|
||||
const routeIndex = persistent<number>(0);
|
||||
const checkRouteProgress = persistent<number>(0);
|
||||
const redundanciesRemoved = persistent<number>(0);
|
||||
|
||||
const currentRoutes = computed(() => {
|
||||
// Manually check milestone req here due to calling generateCity() before milestones get earned
|
||||
if (Decimal.gte(citiesCompleted.value, 7)) {
|
||||
return Decimal.factorial(currentCity.value.length).div(2).toNumber();
|
||||
}
|
||||
// Permutation code from https://stackoverflow.com/a/37580979
|
||||
const length = currentCity.value.length;
|
||||
const permutation = new Array(length).fill(0).map((_, i) => i);
|
||||
const result = [permutation.slice()];
|
||||
const c = new Array(length).fill(0);
|
||||
let i = 1;
|
||||
|
||||
while (i < length) {
|
||||
if (c[i] < i) {
|
||||
const k = i % 2 && c[i];
|
||||
const p = permutation[i];
|
||||
permutation[i] = permutation[k];
|
||||
permutation[k] = p;
|
||||
++c[i];
|
||||
i = 1;
|
||||
result.push(permutation.slice());
|
||||
} else {
|
||||
c[i] = 0;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
const redundantRoutes = computed(() => {
|
||||
const routes = currentRoutes.value;
|
||||
if (typeof routes === "number") {
|
||||
return [];
|
||||
}
|
||||
const redundancies = [];
|
||||
for (let i = 0; i < routes.length; i++) {
|
||||
if (routes[i][0] > routes[i][1]) {
|
||||
redundancies.push(i);
|
||||
}
|
||||
}
|
||||
return redundancies;
|
||||
});
|
||||
const routesToSkip = persistent<number[]>([]);
|
||||
|
||||
const currentRoute: ComputedRef<number[] | number | undefined> = computed(() =>
|
||||
typeof currentRoutes.value === "number"
|
||||
? currentCity.value.length
|
||||
: currentRoutes.value[routeIndex.value]
|
||||
);
|
||||
|
||||
const currentRouteDuration = computed(() => {
|
||||
const route = currentRoute.value;
|
||||
if (route == null) {
|
||||
return 0;
|
||||
} else if (typeof route === "number") {
|
||||
return Decimal.times(route, computedMinWeight.value).floor().toNumber();
|
||||
}
|
||||
let duration = 0;
|
||||
for (let i = 0; i < route.length - 1; i++) {
|
||||
duration += currentCity.value[route[i]][route[i + 1]];
|
||||
}
|
||||
return duration;
|
||||
});
|
||||
|
||||
globalBus.on("onLoad", () => {
|
||||
if (currentCity.value.length === 0) {
|
||||
generateCity();
|
||||
}
|
||||
});
|
||||
|
||||
function stringifyRoute(route: number[]) {
|
||||
return route
|
||||
.map(h => (city.types.house.title as (node: BoardNode) => string)(city.nodes.value[h]))
|
||||
.join("->");
|
||||
}
|
||||
|
||||
function generateCity() {
|
||||
const numHouses = new Decimal(computedHouses.value).clampMin(3).toNumber();
|
||||
const min = computedMinWeight.value;
|
||||
const max = milestone6.earned.value ? min : computedMaxWeight.value;
|
||||
const diff = Decimal.sub(max, min);
|
||||
const city: number[][] = [];
|
||||
for (let i = 0; i < numHouses; i++) {
|
||||
const house: number[] = [];
|
||||
for (let j = 0; j < numHouses; j++) {
|
||||
if (i === j) {
|
||||
house.push(0);
|
||||
} else if (j < i) {
|
||||
house.push(city[j][i]);
|
||||
} else {
|
||||
house.push(Decimal.times(diff, Math.random()).add(min).floor().toNumber());
|
||||
}
|
||||
}
|
||||
city.push(house);
|
||||
}
|
||||
currentCity.value = city;
|
||||
routeIndex.value = 0;
|
||||
redundanciesRemoved.value = Decimal.gte(citiesCompleted.value, 7)
|
||||
? Decimal.factorial(currentCity.value.length).div(2).toNumber()
|
||||
: 0;
|
||||
routesToSkip.value = [];
|
||||
getNextRoute();
|
||||
}
|
||||
|
||||
function getNextRoute() {
|
||||
const numRoutes =
|
||||
typeof currentRoutes.value === "number"
|
||||
? currentRoutes.value
|
||||
: currentRoutes.value.length;
|
||||
while (routeIndex.value <= numRoutes && routesToSkip.value.includes(routeIndex.value)) {
|
||||
routeIndex.value++;
|
||||
}
|
||||
if (routeIndex.value >= numRoutes) {
|
||||
citiesCompleted.value = Decimal.add(citiesCompleted.value, 1);
|
||||
generateCity();
|
||||
} else {
|
||||
if (redundantRoutes.value.includes(routeIndex.value)) {
|
||||
routesToSkip.value = [...routesToSkip.value, routeIndex.value];
|
||||
}
|
||||
checkRouteProgress.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const newCityProgress = persistent<DecimalSource>(0);
|
||||
const newCityProgressBar = createBar(() => ({
|
||||
direction: Direction.Right,
|
||||
width: 100,
|
||||
height: 10,
|
||||
style: "margin-top: 8px",
|
||||
borderStyle: "border-color: black",
|
||||
baseStyle: "margin-top: -1px",
|
||||
fillStyle: "margin-top: -1px; transition-duration: 0s; background: black",
|
||||
progress: () => Decimal.div(newCityProgress.value, 10)
|
||||
}));
|
||||
const getNewCity = createClickable(() => ({
|
||||
display: {
|
||||
description: jsx(() => (
|
||||
<>
|
||||
Generate New Country
|
||||
<br />
|
||||
{render(newCityProgressBar)}
|
||||
</>
|
||||
))
|
||||
},
|
||||
style: {
|
||||
minHeight: "40px",
|
||||
"--layer-color": "var(--danger)"
|
||||
},
|
||||
canClick: () => Decimal.gte(newCityProgress.value, 10),
|
||||
onClick() {
|
||||
if (!unref(getNewCity.canClick)) {
|
||||
return;
|
||||
}
|
||||
generateCity();
|
||||
newCityProgress.value = 0;
|
||||
}
|
||||
}));
|
||||
|
||||
const boostProgress = persistent<DecimalSource>(0);
|
||||
const boostProgressBar = createBar(() => ({
|
||||
direction: Direction.Right,
|
||||
width: 100,
|
||||
height: 10,
|
||||
style: "margin-top: 8px",
|
||||
borderStyle: "border-color: black",
|
||||
baseStyle: "margin-top: -1px",
|
||||
fillStyle: "margin-top: -1px; transition-duration: 0s; background: black",
|
||||
progress: () => Decimal.div(boostProgress.value, computedManualCooldown.value)
|
||||
}));
|
||||
const boost = createClickable(() => ({
|
||||
display: {
|
||||
description: jsx(() => (
|
||||
<>
|
||||
Perform {formatWhole(computedManualBoost.value)} units of work
|
||||
<br />
|
||||
{render(boostProgressBar)}
|
||||
</>
|
||||
))
|
||||
},
|
||||
style: {
|
||||
minHeight: "40px"
|
||||
},
|
||||
canClick: () => Decimal.gte(boostProgress.value, computedManualCooldown.value),
|
||||
onClick() {
|
||||
if (!unref(boost.canClick)) {
|
||||
return;
|
||||
}
|
||||
checkRouteProgress.value = Decimal.add(
|
||||
checkRouteProgress.value,
|
||||
computedManualBoost.value
|
||||
).toNumber();
|
||||
boostProgress.value = 0;
|
||||
}
|
||||
}));
|
||||
|
||||
const redundantProgress = persistent<DecimalSource>(0);
|
||||
const redundantProgressBar = createBar(() => ({
|
||||
direction: Direction.Right,
|
||||
width: 100,
|
||||
height: 10,
|
||||
style: "margin-top: 8px",
|
||||
borderStyle: "border-color: black",
|
||||
baseStyle: "margin-top: -1px",
|
||||
fillStyle: "margin-top: -1px; transition-duration: 0s; background: black",
|
||||
progress: () => Decimal.div(redundantProgress.value, computedRedundantCooldown.value)
|
||||
}));
|
||||
const removeRedundantRoute = createClickable(() => ({
|
||||
display: {
|
||||
description: jsx(() => (
|
||||
<>
|
||||
Remove a redundant route from the list to check
|
||||
<br />
|
||||
{render(redundantProgressBar)}
|
||||
</>
|
||||
))
|
||||
},
|
||||
style: {
|
||||
minHeight: "40px"
|
||||
},
|
||||
visibility: () => showIf(!milestone7.earned.value),
|
||||
canClick: () =>
|
||||
Decimal.gte(redundantProgress.value, computedRedundantCooldown.value) &&
|
||||
routesToSkip.value.length < redundantRoutes.value.length,
|
||||
onClick() {
|
||||
if (!unref(removeRedundantRoute.canClick)) {
|
||||
return;
|
||||
}
|
||||
routesToSkip.value = [
|
||||
...routesToSkip.value,
|
||||
redundantRoutes.value[routesToSkip.value.length]
|
||||
];
|
||||
redundantProgress.value = 0;
|
||||
redundanciesRemoved.value++;
|
||||
}
|
||||
}));
|
||||
|
||||
const city = createBoard(() => ({
|
||||
startNodes: () => [],
|
||||
types: {
|
||||
house: {
|
||||
shape: Shape.Circle,
|
||||
fillColor: "var(--highlighted)",
|
||||
outlineColor: "var(--accent1)",
|
||||
size: 20,
|
||||
title(node) {
|
||||
let letter = node.state as number;
|
||||
let name = "";
|
||||
while (true) {
|
||||
if (letter < 26) {
|
||||
name += alpha[letter];
|
||||
break;
|
||||
}
|
||||
let thisLetter = letter;
|
||||
let iterations = 0;
|
||||
while (Math.floor(thisLetter / 26) - 1 >= 0) {
|
||||
thisLetter = Math.floor(thisLetter / 26) - 1;
|
||||
iterations++;
|
||||
}
|
||||
name += alpha[thisLetter];
|
||||
|
||||
let amountToDecrement = thisLetter + 1;
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
amountToDecrement *= 26;
|
||||
}
|
||||
letter -= amountToDecrement;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
},
|
||||
width: "600px",
|
||||
height: "600px",
|
||||
style: {
|
||||
background: "var(--raised-background)",
|
||||
borderRadius: "var(--border-radius) var(--border-radius) 0 0",
|
||||
boxShadow: "0 2px 10px rgb(0 0 0 / 50%)"
|
||||
},
|
||||
state: computed(() => {
|
||||
const nodes: BoardNode[] = [];
|
||||
const city = currentCity.value;
|
||||
const rows = Math.ceil(Math.sqrt(city.length));
|
||||
const cols = Math.ceil(city.length / rows);
|
||||
for (let i = 0; i < city.length; i++) {
|
||||
const row = Math.floor(i / rows);
|
||||
const col = Math.floor(i % rows);
|
||||
const randomOffsetIndex = i + new Decimal(citiesCompleted.value).toNumber();
|
||||
nodes.push({
|
||||
id: i,
|
||||
position: {
|
||||
x: 160 * (-(cols - 1) / 2 + col) + Math.cos(randomOffsetIndex) * 40,
|
||||
y: 160 * (-(rows - 1) / 2 + row) + Math.sin(randomOffsetIndex) * 40
|
||||
},
|
||||
type: "house",
|
||||
state: i
|
||||
});
|
||||
}
|
||||
return {
|
||||
nodes,
|
||||
selectedNode: null,
|
||||
selectedAction: null
|
||||
};
|
||||
}),
|
||||
links() {
|
||||
const links: BoardNodeLink[] = [];
|
||||
const route = currentRoute.value;
|
||||
if (route == null) {
|
||||
return links;
|
||||
}
|
||||
const citySize = currentCity.value.length;
|
||||
let completedLegs = 0;
|
||||
let progress = 0;
|
||||
let partialLeg = 0;
|
||||
if (typeof route !== "number") {
|
||||
for (let i = 0; i < route.length - 1; i++) {
|
||||
const weight = progress + currentCity.value[route[i]][route[i + 1]];
|
||||
if (checkRouteProgress.value > weight) {
|
||||
completedLegs++;
|
||||
progress = weight;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
partialLeg =
|
||||
(checkRouteProgress.value - progress) /
|
||||
currentCity.value[route[completedLegs]][route[completedLegs + 1]];
|
||||
}
|
||||
for (let i = 0; i < citySize; i++) {
|
||||
for (let j = 0; j < citySize; j++) {
|
||||
if (i !== j) {
|
||||
let progress = 0;
|
||||
if (typeof route !== "number") {
|
||||
const iIndex = route.indexOf(i);
|
||||
const jIndex = route.indexOf(j);
|
||||
if (
|
||||
iIndex >= 0 &&
|
||||
jIndex >= 0 &&
|
||||
(route[iIndex + 1] === j || route[jIndex + 1] === i)
|
||||
) {
|
||||
if (jIndex < completedLegs || iIndex < completedLegs) {
|
||||
progress = 1;
|
||||
} else if (jIndex === completedLegs || iIndex === completedLegs) {
|
||||
progress = partialLeg;
|
||||
}
|
||||
}
|
||||
}
|
||||
links.push({
|
||||
style: "transition-duration: 0s",
|
||||
startNode: city.nodes.value[i],
|
||||
endNode: city.nodes.value[j],
|
||||
stroke: `rgb(${progress * 255}, 0, 0)`,
|
||||
"stroke-width": 2 * progress + 2,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
weight: i < j ? null : currentCity.value[i][j]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return links;
|
||||
}
|
||||
}));
|
||||
|
||||
const checkRouteProgressBar = createBar(() => ({
|
||||
direction: Direction.Right,
|
||||
width: 597,
|
||||
height: 24,
|
||||
style: {
|
||||
borderRadius: "0 0 var(--border-radius) var(--border-radius)",
|
||||
background: "var(--raised-background)",
|
||||
marginTop: "-24px"
|
||||
},
|
||||
borderStyle: {
|
||||
borderRadius: "0 0 var(--border-radius) var(--border-radius)",
|
||||
borderColor: "var(--outline)",
|
||||
marginTop: "unset"
|
||||
},
|
||||
fillStyle: {
|
||||
background: "black",
|
||||
marginTop: "unset"
|
||||
},
|
||||
progress() {
|
||||
return Decimal.div(checkRouteProgress.value, currentRouteDuration.value);
|
||||
},
|
||||
display: jsx(() => (
|
||||
<>
|
||||
{Math.floor(checkRouteProgress.value)}/{currentRouteDuration.value}
|
||||
</>
|
||||
))
|
||||
}));
|
||||
|
||||
const milestone1 = createMilestone(() => ({
|
||||
display: {
|
||||
requirement: "1 Country Solved",
|
||||
effectDisplay: "Each country solved doubles manual and auto processing speed"
|
||||
},
|
||||
shouldEarn() {
|
||||
return Decimal.gte(citiesCompleted.value, 1);
|
||||
}
|
||||
}));
|
||||
const milestone2 = createMilestone(() => ({
|
||||
display: {
|
||||
requirement: "2 Countries Solved",
|
||||
effectDisplay:
|
||||
"Manually checking routes does additional work based on number of routes checked in this country"
|
||||
},
|
||||
shouldEarn() {
|
||||
return Decimal.gte(citiesCompleted.value, 2);
|
||||
},
|
||||
visibility: () => showIf(milestone1.earned.value)
|
||||
}));
|
||||
const milestone3 = createMilestone(() => ({
|
||||
display: {
|
||||
requirement: "3 Countries Solved",
|
||||
effectDisplay:
|
||||
"Each country solved makes the cooldown for removing a redundant route 25% shorter"
|
||||
},
|
||||
shouldEarn() {
|
||||
return Decimal.gte(citiesCompleted.value, 3);
|
||||
},
|
||||
visibility: () => showIf(milestone2.earned.value)
|
||||
}));
|
||||
const milestone4 = createMilestone(() => ({
|
||||
display: {
|
||||
requirement: "4 Countries Solved",
|
||||
effectDisplay:
|
||||
"Automatic processing speed is multiplied by the amount of redundant routes removed from this country"
|
||||
},
|
||||
shouldEarn() {
|
||||
return Decimal.gte(citiesCompleted.value, 4);
|
||||
},
|
||||
visibility: () => showIf(milestone3.earned.value)
|
||||
}));
|
||||
const milestone5 = createMilestone(() => ({
|
||||
display: {
|
||||
requirement: "5 Countries Solved",
|
||||
effectDisplay: "Remove 1 city"
|
||||
},
|
||||
shouldEarn() {
|
||||
return Decimal.gte(citiesCompleted.value, 5);
|
||||
},
|
||||
onComplete() {
|
||||
generateCity();
|
||||
},
|
||||
visibility: () => showIf(milestone4.earned.value)
|
||||
}));
|
||||
const milestone6 = createMilestone(() => ({
|
||||
display: {
|
||||
requirement: "6 Countries Solved",
|
||||
effectDisplay:
|
||||
"Lower max weight to the min weight, and uncap amount of routes that can be checked per tick"
|
||||
},
|
||||
shouldEarn() {
|
||||
return Decimal.gte(citiesCompleted.value, 6);
|
||||
},
|
||||
visibility: () => showIf(milestone5.earned.value)
|
||||
}));
|
||||
const milestone7 = createMilestone(() => ({
|
||||
display: {
|
||||
requirement: "7 Countries Solved",
|
||||
effectDisplay: "All redundancies are removed"
|
||||
},
|
||||
shouldEarn() {
|
||||
return Decimal.gte(citiesCompleted.value, 7);
|
||||
},
|
||||
visibility: () => showIf(milestone6.earned.value)
|
||||
}));
|
||||
const milestones = {
|
||||
milestone1,
|
||||
milestone2,
|
||||
milestone3,
|
||||
milestone4,
|
||||
milestone5,
|
||||
milestone6,
|
||||
milestone7
|
||||
};
|
||||
const { collapseMilestones, display: milestonesDisplay } =
|
||||
createCollapsibleMilestones(milestones);
|
||||
|
||||
const houses = createSequentialModifier(() => [
|
||||
createAdditiveModifier(() => ({
|
||||
addend: citiesCompleted,
|
||||
description: "Countries Completed"
|
||||
})),
|
||||
createAdditiveModifier(() => ({
|
||||
addend: 1,
|
||||
description: "5 Countries Completed",
|
||||
enabled: milestone5.earned
|
||||
}))
|
||||
]);
|
||||
const computedHouses = computed(() => houses.apply(3));
|
||||
const maxWeight = createSequentialModifier(() => [
|
||||
createAdditiveModifier(() => ({
|
||||
addend: () => Decimal.pow(citiesCompleted.value, 1.1),
|
||||
description: "Countries Completed"
|
||||
}))
|
||||
]);
|
||||
const computedMaxWeight = computed(() => maxWeight.apply(10));
|
||||
const minWeight = createSequentialModifier(() => [
|
||||
createAdditiveModifier(() => ({
|
||||
addend: citiesCompleted,
|
||||
description: "Countries Completed"
|
||||
})),
|
||||
createExponentialModifier(() => ({
|
||||
exponent: 3,
|
||||
description: "Countries Completed",
|
||||
enabled: milestone7.earned
|
||||
}))
|
||||
]);
|
||||
const computedMinWeight = computed(() => minWeight.apply(2));
|
||||
const manualBoost = createSequentialModifier(() => [
|
||||
createAdditiveModifier(() => ({
|
||||
addend: () => Decimal.add(routeIndex.value, 1).sqrt(),
|
||||
description: "2 Countries Solved",
|
||||
enabled: milestone2.earned
|
||||
}))
|
||||
]);
|
||||
const computedManualBoost = computed(() => manualBoost.apply(1));
|
||||
const manualCooldown = createSequentialModifier(() => [
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () => Decimal.pow(0.5, citiesCompleted.value),
|
||||
description: "1 Country Solved",
|
||||
enabled: milestone1.earned
|
||||
}))
|
||||
]);
|
||||
const computedManualCooldown = computed(() => manualCooldown.apply(1));
|
||||
const redundantCooldown = createSequentialModifier(() => [
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () => Decimal.pow(0.75, citiesCompleted.value),
|
||||
description: "3 Countries Solved",
|
||||
enabled: milestone3.earned
|
||||
}))
|
||||
]);
|
||||
const computedRedundantCooldown = computed(() => redundantCooldown.apply(10));
|
||||
const autoProcessing = createSequentialModifier(() => [
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () => Decimal.pow(2, citiesCompleted.value),
|
||||
description: "1 Country Solved",
|
||||
enabled: milestone1.earned
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () => Decimal.add(redundanciesRemoved.value, 1),
|
||||
description: "4 Countries Solved",
|
||||
enabled: milestone4.earned
|
||||
}))
|
||||
]);
|
||||
const computedAutoProcessing = computed(() => autoProcessing.apply(1));
|
||||
|
||||
const [generalTab, generalTabCollapsed] = createCollapsibleModifierSections(() => [
|
||||
{
|
||||
title: "Cities/country",
|
||||
modifier: houses,
|
||||
base: 3
|
||||
},
|
||||
{
|
||||
title: () => (milestone6.earned.value ? "Weight" : "Minimum Weight"),
|
||||
modifier: minWeight,
|
||||
base: 2
|
||||
},
|
||||
{
|
||||
title: "Maximum Weight",
|
||||
modifier: maxWeight,
|
||||
base: 10,
|
||||
visible: () => !milestone6.earned.value
|
||||
},
|
||||
{
|
||||
title: "Manual Processing Amount",
|
||||
modifier: manualBoost,
|
||||
base: 1
|
||||
},
|
||||
{
|
||||
title: "Manual Processing Cooldown",
|
||||
modifier: manualCooldown,
|
||||
base: 1,
|
||||
unit: "s"
|
||||
},
|
||||
{
|
||||
title: "Remove Redundant Route Cooldown",
|
||||
modifier: redundantCooldown,
|
||||
base: 10,
|
||||
unit: "s"
|
||||
},
|
||||
{
|
||||
title: "Auto Processing Speed",
|
||||
modifier: autoProcessing,
|
||||
base: 1,
|
||||
unit: "/s"
|
||||
}
|
||||
]);
|
||||
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;
|
||||
}
|
||||
|
||||
if (Decimal.gte(newCityProgress.value, 10)) {
|
||||
newCityProgress.value = 10;
|
||||
} else {
|
||||
newCityProgress.value = Decimal.add(newCityProgress.value, diff);
|
||||
if (getNewCity.isHolding.value) {
|
||||
getNewCity.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
if (Decimal.gte(boostProgress.value, computedManualCooldown.value)) {
|
||||
boostProgress.value = computedManualCooldown.value;
|
||||
} else {
|
||||
boostProgress.value = Decimal.add(boostProgress.value, diff);
|
||||
if (boost.isHolding.value) {
|
||||
boost.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
if (Decimal.gte(redundantProgress.value, computedRedundantCooldown.value)) {
|
||||
redundantProgress.value = computedRedundantCooldown.value;
|
||||
} else {
|
||||
redundantProgress.value = Decimal.add(redundantProgress.value, diff);
|
||||
if (removeRedundantRoute.isHolding.value) {
|
||||
removeRedundantRoute.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
checkRouteProgress.value = Decimal.times(diff, computedAutoProcessing.value)
|
||||
.add(checkRouteProgress.value)
|
||||
.toNumber();
|
||||
if (checkRouteProgress.value > currentRouteDuration.value) {
|
||||
const overflow = checkRouteProgress.value - currentRouteDuration.value;
|
||||
routeIndex.value++;
|
||||
if (milestone6.earned.value && currentRoute.value != null) {
|
||||
const length =
|
||||
typeof currentRoute.value === "number"
|
||||
? currentRoute.value
|
||||
: currentRoute.value.length;
|
||||
const extraRoutes = Decimal.div(
|
||||
overflow,
|
||||
Decimal.times(length, computedMinWeight.value)
|
||||
)
|
||||
.floor()
|
||||
.toNumber();
|
||||
routeIndex.value += extraRoutes;
|
||||
}
|
||||
getNextRoute();
|
||||
}
|
||||
});
|
||||
|
||||
const dayProgress = createBar(() => ({
|
||||
direction: Direction.Right,
|
||||
width: 600,
|
||||
height: 25,
|
||||
fillStyle: `backgroundColor: ${color}`,
|
||||
textStyle: {
|
||||
color: "var(--feature-foreground)"
|
||||
},
|
||||
progress: () =>
|
||||
main.day.value === day ? Decimal.div(citiesCompleted.value, citiesGoal) : 1,
|
||||
display: jsx(() =>
|
||||
main.day.value === day ? (
|
||||
<>
|
||||
{formatWhole(citiesCompleted.value)}/{formatWhole(citiesGoal)}
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
)
|
||||
)
|
||||
})) as GenericBar;
|
||||
|
||||
watchEffect(() => {
|
||||
if (main.day.value === day && Decimal.gte(citiesCompleted.value, citiesGoal)) {
|
||||
main.completeDay();
|
||||
}
|
||||
});
|
||||
|
||||
function displayRoutes() {
|
||||
if (currentRoute.value == null) {
|
||||
return "";
|
||||
}
|
||||
if (typeof currentRoutes.value === "number") {
|
||||
return (
|
||||
<div class="routes-list">
|
||||
{routeIndex.value > 0 ? (
|
||||
<div class="checked">{formatWhole(routeIndex.value)} already checked</div>
|
||||
) : null}
|
||||
<div>
|
||||
{formatWhole(currentRoutes.value - routeIndex.value)} routes left to check
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (typeof currentRoutes.value === "number") {
|
||||
console.error("Something went horribly wrong");
|
||||
return;
|
||||
}
|
||||
const routes = currentRoutes.value.slice();
|
||||
let showPrevious = false;
|
||||
let showNext = 0;
|
||||
if (routes.length > 6) {
|
||||
routes.splice(0, routeIndex.value);
|
||||
showPrevious = true;
|
||||
if (routes.length > 6) {
|
||||
showNext = routes.length - 5;
|
||||
routes.splice(5);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div class="routes-list">
|
||||
{showPrevious && routeIndex.value > 0 ? (
|
||||
<div class="checked">{formatWhole(routeIndex.value)} already checked</div>
|
||||
) : null}
|
||||
{routes.map((route, i) => {
|
||||
const index = i + (showPrevious ? routeIndex.value : 0);
|
||||
return (
|
||||
<div
|
||||
class={{
|
||||
redundant: route[0] > route[1],
|
||||
checked: routeIndex.value > index,
|
||||
processing: routeIndex.value === index,
|
||||
skipped:
|
||||
routeIndex.value < index && routesToSkip.value.includes(index)
|
||||
}}
|
||||
>
|
||||
{stringifyRoute(route)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{showNext > 0 ? <div>+ {formatWhole(showNext)} more</div> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
day,
|
||||
color,
|
||||
citiesCompleted,
|
||||
currentCity,
|
||||
routeIndex,
|
||||
checkRouteProgress,
|
||||
newCityProgress,
|
||||
boostProgress,
|
||||
redundantProgress,
|
||||
generalTabCollapsed,
|
||||
currentRoutes,
|
||||
redundantRoutes,
|
||||
routesToSkip,
|
||||
redundanciesRemoved,
|
||||
city,
|
||||
milestones,
|
||||
collapseMilestones,
|
||||
minWidth: 700,
|
||||
display: jsx(() => (
|
||||
<>
|
||||
<div>
|
||||
{main.day.value === day
|
||||
? `Solve ${formatWhole(citiesGoal)} countries 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 />
|
||||
<MainDisplay resource={citiesCompleted} color={color} />
|
||||
{renderRow(getNewCity, boost, removeRedundantRoute)}
|
||||
{render(city)}
|
||||
{render(checkRouteProgressBar)}
|
||||
<Spacer />
|
||||
<h3>Checking Routes...</h3>
|
||||
{displayRoutes()}
|
||||
<Spacer />
|
||||
{milestonesDisplay()}
|
||||
</>
|
||||
)),
|
||||
minimizedDisplay: jsx(() => (
|
||||
<div>
|
||||
{name} <span class="desc">{format(citiesCompleted.value)} countries solved</span>
|
||||
</div>
|
||||
))
|
||||
};
|
||||
});
|
||||
|
||||
export default layer;
|
225
src/data/layers/sleigh.tsx
Normal 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(1e97, Decimal.pow(1.2, v)),
|
||||
metal: Decimal.mul(1e67, Decimal.pow(1.1, v)),
|
||||
plastic: Decimal.mul(1e22, 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">
|
||||
Requires: {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 quadrupled"
|
||||
},
|
||||
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 40 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;
|
|
@ -94,4 +94,15 @@
|
|||
rgb(76, 76, 255) 40px 50px, white 50px 60px
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes reindeer-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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,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 {
|
||||
|
@ -176,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: "";
|
||||
|
@ -192,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);
|
||||
}
|
||||
|
|
10
src/data/layers/styles/reindeer.css
Normal 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);
|
||||
}
|
||||
}
|
20
src/data/layers/styles/routing.css
Normal file
|
@ -0,0 +1,20 @@
|
|||
.routes-list .checked {
|
||||
color: var(--bought);
|
||||
}
|
||||
|
||||
.routes-list .processing {
|
||||
color: var(--layer-color);
|
||||
}
|
||||
|
||||
.routes-list .redundant:not(.checked):not(.processing) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.routes-list .skipped {
|
||||
text-decoration: line-through;
|
||||
text-decoration-thickness: 5px;
|
||||
}
|
||||
|
||||
.routes-list > * {
|
||||
flex: 1 1 33%;
|
||||
}
|
|
@ -40,6 +40,8 @@ import workshop from "./workshop";
|
|||
import wrappingPaper from "./wrapping-paper";
|
||||
import toys from "./toys";
|
||||
import factory from "./factory";
|
||||
import reindeer from "./reindeer";
|
||||
import sleigh from "./sleigh";
|
||||
const id = "trees";
|
||||
const day = 1;
|
||||
|
||||
|
@ -557,6 +559,17 @@ const layer = createLayer(id, function (this: BaseLayer) {
|
|||
description: "Haul wood in trucks",
|
||||
enabled: factory.upgrades[0][2].bought
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: () => Decimal.div(sleigh.sleighProgress.value.value, 5).floor().mul(0.05).add(1),
|
||||
description: "10% Sleigh Fixed",
|
||||
enabled: sleigh.milestones.milestone2.earned
|
||||
})),
|
||||
createMultiplicativeModifier(() => ({
|
||||
multiplier: 10,
|
||||
description: "50% Sleigh Fixed",
|
||||
enabled: sleigh.milestones.milestone6.earned
|
||||
})),
|
||||
reindeer.reindeer.dasher.modifier,
|
||||
createExponentialModifier(() => ({
|
||||
exponent: 1.2,
|
||||
description: "100% Foundation Completed",
|
||||
|
|
|
@ -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";
|
||||
|
@ -123,9 +124,6 @@ const layer = createLayer(id, function (this: BaseLayer) {
|
|||
)),
|
||||
visibility: () => showIf(Decimal.lt(foundationProgress.value, computedMaxFoundation.value)),
|
||||
canClick: () => {
|
||||
if (Decimal.gt(computedMaxFoundation.value, foundationProgress.value)){
|
||||
foundationProgress.value = Decimal.min(0, computedMaxFoundation.value)
|
||||
}
|
||||
if (Decimal.lt(trees.logs.value, foundationConversion.nextAt.value)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -146,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",
|
||||
|
|
|
@ -31,10 +31,13 @@ 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 routing from "./layers/routing";
|
||||
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,14 +51,18 @@ 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 packing from "./layers/packing";
|
||||
import sleighSymbol from "./symbols/sleigh.png";
|
||||
import routingSymbol from "./symbols/gps.png";
|
||||
|
||||
export interface Day extends VueFeature {
|
||||
day: number;
|
||||
|
@ -465,37 +472,41 @@ 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"
|
||||
symbol: "",
|
||||
story: "",
|
||||
completedStory: "",
|
||||
layer: "sleigh",
|
||||
symbol: sleighSymbol,
|
||||
story: "You realize you haven't noticed a very important object since you've started working here. Where's the sleigh? You bring it up to Santa and he immediately becomes visibly stressed, mentioning it's been in disrepair and he completely forgot! You promise you'll get it back in shape in no time!",
|
||||
completedStory:
|
||||
"Crisis averted! The sleigh has been returned to it's full splendor. Santa is incredibly appreciative. Good Job!",
|
||||
masteredStory: ""
|
||||
})),
|
||||
createDay(() => ({
|
||||
day: 23,
|
||||
shouldNotify: false,
|
||||
layer: null, // "distribution route planning"
|
||||
symbol: "",
|
||||
story: "",
|
||||
completedStory: "",
|
||||
layer: "routing",
|
||||
symbol: routingSymbol,
|
||||
story: "You're almost ready for the big day! The next step is to find an optimal route to ensure you can get all the presents delivered before kids start waking up! This is like the travelling salesman problem on steroids. Good Luck!",
|
||||
completedStory:
|
||||
"Take that, math majors! Optimal route planned with time to spare. Good Job!",
|
||||
masteredStory: ""
|
||||
})),
|
||||
createDay(() => ({
|
||||
|
@ -617,6 +628,9 @@ export const getInitialLayers = (
|
|||
ribbon,
|
||||
toys,
|
||||
factory,
|
||||
reindeer,
|
||||
sleigh,
|
||||
routing,
|
||||
packing
|
||||
];
|
||||
|
||||
|
|
BIN
src/data/symbols/gps.png
Normal file
After Width: | Height: | Size: 112 KiB |
BIN
src/data/symbols/presents.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
src/data/symbols/reindeer.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
src/data/symbols/sleigh.png
Normal file
After Width: | Height: | Size: 67 KiB |
|
@ -8,6 +8,13 @@
|
|||
:x2="endPosition.x"
|
||||
:y2="endPosition.y"
|
||||
/>
|
||||
<text
|
||||
v-if="link.weight"
|
||||
:x="(startPosition.x + endPosition.x) / 2"
|
||||
:y="(startPosition.y + endPosition.y) / 2 + 4"
|
||||
style="text-anchor: middle; fill: var(--foreground)"
|
||||
>{{ link.weight }}</text
|
||||
>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -15,7 +22,7 @@ import type { BoardNodeLink } from "features/boards/board";
|
|||
import { computed, toRefs, unref } from "vue";
|
||||
|
||||
const _props = defineProps<{
|
||||
link: BoardNodeLink;
|
||||
link: BoardNodeLink & { weight?: number };
|
||||
}>();
|
||||
const props = toRefs(_props);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
Visibility
|
||||
} from "features/feature";
|
||||
import { globalBus } from "game/events";
|
||||
import type { Persistent, State } from "game/persistence";
|
||||
import { DefaultValue, deletePersistent, Persistent, State } from "game/persistence";
|
||||
import { persistent } from "game/persistence";
|
||||
import type { Unsubscribe } from "nanoevents";
|
||||
import { isFunction } from "util/common";
|
||||
|
@ -167,12 +167,12 @@ export interface BoardOptions {
|
|||
style?: Computable<StyleValue>;
|
||||
startNodes: () => Omit<BoardNode, "id">[];
|
||||
types: Record<string, NodeTypeOptions>;
|
||||
state?: Computable<BoardData>;
|
||||
links?: Computable<BoardNodeLink[] | null>;
|
||||
}
|
||||
|
||||
export interface BaseBoard {
|
||||
id: string;
|
||||
state: Persistent<BoardData>;
|
||||
links: Ref<BoardNodeLink[] | null>;
|
||||
nodes: Ref<BoardNode[]>;
|
||||
selectedNode: Ref<BoardNode | null>;
|
||||
selectedAction: Ref<GenericBoardNodeAction | null>;
|
||||
|
@ -191,6 +191,8 @@ export type Board<T extends BoardOptions> = Replace<
|
|||
width: GetComputableType<T["width"]>;
|
||||
classes: GetComputableType<T["classes"]>;
|
||||
style: GetComputableType<T["style"]>;
|
||||
state: GetComputableTypeWithDefault<T["state"], Persistent<BoardData>>;
|
||||
links: GetComputableTypeWithDefault<T["links"], Ref<BoardNodeLink[] | null>>;
|
||||
}
|
||||
>;
|
||||
|
||||
|
@ -198,31 +200,46 @@ export type GenericBoard = Replace<
|
|||
Board<BoardOptions>,
|
||||
{
|
||||
visibility: ProcessedComputable<Visibility>;
|
||||
state: ProcessedComputable<BoardData>;
|
||||
links: ProcessedComputable<BoardNodeLink[] | null>;
|
||||
}
|
||||
>;
|
||||
|
||||
export function createBoard<T extends BoardOptions>(
|
||||
optionsFunc: OptionsFunc<T, BaseBoard, GenericBoard>
|
||||
): Board<T> {
|
||||
const state = persistent<BoardData>({
|
||||
nodes: [],
|
||||
selectedNode: null,
|
||||
selectedAction: null
|
||||
});
|
||||
|
||||
return createLazyProxy(() => {
|
||||
const board = optionsFunc();
|
||||
board.id = getUniqueID("board-");
|
||||
board.type = BoardType;
|
||||
board[Component] = BoardComponent;
|
||||
|
||||
board.state = persistent<BoardData>({
|
||||
nodes: board.startNodes().map((n, i) => {
|
||||
(n as BoardNode).id = i;
|
||||
return n as BoardNode;
|
||||
}),
|
||||
selectedNode: null,
|
||||
selectedAction: null
|
||||
});
|
||||
board.nodes = computed(() => processedBoard.state.value.nodes);
|
||||
if (board.state) {
|
||||
deletePersistent(state);
|
||||
processComputable(board as T, "state");
|
||||
} else {
|
||||
state[DefaultValue] = {
|
||||
nodes: board.startNodes().map((n, i) => {
|
||||
(n as BoardNode).id = i;
|
||||
return n as BoardNode;
|
||||
}),
|
||||
selectedNode: null,
|
||||
selectedAction: null
|
||||
};
|
||||
board.state = state;
|
||||
}
|
||||
|
||||
board.nodes = computed(() => unref(processedBoard.state).nodes);
|
||||
board.selectedNode = computed(
|
||||
() =>
|
||||
processedBoard.nodes.value.find(
|
||||
node => node.id === processedBoard.state.value.selectedNode
|
||||
node => node.id === unref(processedBoard.state).selectedNode
|
||||
) || null
|
||||
);
|
||||
board.selectedAction = computed(() => {
|
||||
|
@ -236,23 +253,30 @@ export function createBoard<T extends BoardOptions>(
|
|||
}
|
||||
return (
|
||||
type.actions.find(
|
||||
action => action.id === processedBoard.state.value.selectedAction
|
||||
action => action.id === unref(processedBoard.state).selectedAction
|
||||
) || null
|
||||
);
|
||||
});
|
||||
board.mousePosition = ref(null);
|
||||
board.links = computed(() => {
|
||||
if (processedBoard.selectedAction.value == null) {
|
||||
return null;
|
||||
}
|
||||
if (processedBoard.selectedAction.value.links && processedBoard.selectedNode.value) {
|
||||
return getNodeProperty(
|
||||
processedBoard.selectedAction.value.links,
|
||||
if (board.links) {
|
||||
processComputable(board as T, "links");
|
||||
} else {
|
||||
board.links = computed(() => {
|
||||
if (processedBoard.selectedAction.value == null) {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
processedBoard.selectedAction.value.links &&
|
||||
processedBoard.selectedNode.value
|
||||
);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
) {
|
||||
return getNodeProperty(
|
||||
processedBoard.selectedAction.value.links,
|
||||
processedBoard.selectedNode.value
|
||||
);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
processComputable(board as T, "visibility");
|
||||
setDefault(board, "visibility", Visibility.Visible);
|
||||
processComputable(board as T, "width");
|
||||
|
@ -286,10 +310,10 @@ export function createBoard<T extends BoardOptions>(
|
|||
processComputable(nodeType as NodeTypeOptions, "actionDistance");
|
||||
setDefault(nodeType, "actionDistance", Math.PI / 6);
|
||||
nodeType.nodes = computed(() =>
|
||||
processedBoard.state.value.nodes.filter(node => node.type === type)
|
||||
unref(processedBoard.state).nodes.filter(node => node.type === type)
|
||||
);
|
||||
setDefault(nodeType, "onClick", function (node: BoardNode) {
|
||||
processedBoard.state.value.selectedNode = node.id;
|
||||
unref(processedBoard.state).selectedNode = node.id;
|
||||
});
|
||||
|
||||
if (nodeType.actions) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -156,7 +156,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
.tab-family-container > :nth-child(2) {
|
||||
margin-top: 20px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.modal-body > .tab-family-container > :nth-child(2) {
|
||||
|
@ -222,8 +222,8 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
.showGoBack
|
||||
> .tab-family-container
|
||||
> .tab-buttons-container:not(.floating):first-child
|
||||
> .tab-family-container:first-child
|
||||
> .tab-buttons-container:not(.floating)
|
||||
.tab-buttons {
|
||||
padding-left: 70px;
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -268,6 +268,9 @@ globalBus.on("addLayer", (layer: GenericLayer, saveData: Record<string, unknown>
|
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
handleObject((layer as any)[ProxyState]);
|
||||
persistentRefs[layer.id].forEach(persistent => {
|
||||
if (persistent[Deleted]) {
|
||||
return;
|
||||
}
|
||||
console.error(
|
||||
`Created persistent ref in ${layer.id} without registering it to the layer! Make sure to include everything persistent in the returned object`,
|
||||
persistent,
|
||||
|
|