argh merge conflicts

This commit is contained in:
Chunkybanana 2022-12-13 22:18:50 +00:00
commit a8e52bba9e
34 changed files with 1343 additions and 349 deletions

View file

@ -6,7 +6,7 @@
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "esbenp.prettier-vscode",
"git.ignoreLimitWarning": true, "git.ignoreLimitWarning": true,
"[typescriptreact]": { "[typescriptreact]": {
"editor.defaultFormatter": "vscode.typescript-language-features" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"typescript.tsdk": "node_modules/typescript/lib" "typescript.tsdk": "node_modules/typescript/lib"
} }

View file

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

View file

@ -2,7 +2,8 @@
<div class="layer-container" :style="{ '--layer-color': unref(color) }"> <div class="layer-container" :style="{ '--layer-color': unref(color) }">
<button v-if="showGoBack" class="goBack" @click="goBack"></button> <button v-if="showGoBack" class="goBack" @click="goBack"></button>
<button class="layer-tab minimized" v-if="minimized.value" @click="minimized.value = false"> <button class="layer-tab minimized" v-if="minimized.value" @click="minimized.value = false">
<div>{{ unref(name) }}</div> <component v-if="minimizedComponent" :is="minimizedComponent" />
<div v-else>{{ unref(name) }}</div>
</button> </button>
<div class="layer-tab" :class="{ showGoBack }" v-else> <div class="layer-tab" :class="{ showGoBack }" v-else>
<Context @update-nodes="updateNodes"> <Context @update-nodes="updateNodes">
@ -21,7 +22,7 @@ import type { CoercableComponent } from "features/feature";
import type { FeatureNode } from "game/layers"; import type { FeatureNode } from "game/layers";
import type { Persistent } from "game/persistence"; import type { Persistent } from "game/persistence";
import player from "game/player"; import player from "game/player";
import { computeComponent, processedPropType, wrapRef } from "util/vue"; import { computeComponent, computeOptionalComponent, processedPropType, wrapRef } from "util/vue";
import type { PropType, Ref } from "vue"; import type { PropType, Ref } from "vue";
import { computed, defineComponent, nextTick, toRefs, unref, watch } from "vue"; import { computed, defineComponent, nextTick, toRefs, unref, watch } from "vue";
import Context from "./Context.vue"; import Context from "./Context.vue";
@ -41,6 +42,7 @@ export default defineComponent({
type: processedPropType<CoercableComponent>(Object, String, Function), type: processedPropType<CoercableComponent>(Object, String, Function),
required: true required: true
}, },
minimizedDisplay: processedPropType<CoercableComponent>(Object, String, Function),
minimized: { minimized: {
type: Object as PropType<Persistent<boolean>>, type: Object as PropType<Persistent<boolean>>,
required: true required: true
@ -61,9 +63,10 @@ export default defineComponent({
} }
}, },
setup(props) { setup(props) {
const { display, index, minimized, minWidth, tab } = toRefs(props); const { display, index, minimized, minWidth, tab, minimizedDisplay } = toRefs(props);
const component = computeComponent(display); const component = computeComponent(display);
const minimizedComponent = computeOptionalComponent(minimizedDisplay);
const showGoBack = computed( const showGoBack = computed(
() => projInfo.allowGoBack && index.value > 0 && !minimized.value () => projInfo.allowGoBack && index.value > 0 && !minimized.value
); );
@ -106,6 +109,7 @@ export default defineComponent({
return { return {
component, component,
minimizedComponent,
showGoBack, showGoBack,
updateNodes, updateNodes,
unref, unref,
@ -155,7 +159,7 @@ export default defineComponent({
background-color: transparent; background-color: transparent;
} }
.layer-tab.minimized div { .layer-tab.minimized > * {
margin: 0; margin: 0;
writing-mode: vertical-rl; writing-mode: vertical-rl;
padding-left: 10px; padding-left: 10px;

View file

@ -1,16 +1,31 @@
<template> <template>
<Modal v-model="isOpen"> <Modal v-model="isOpen">
<template v-slot:header> <template v-slot:header>
<h2>Options</h2> <h2>Settings</h2>
<div class="option-tabs">
<button :class="{ selected: isTab('behaviour') }" @click="setTab('behaviour')">
Behaviour
</button>
<button :class="{ selected: isTab('appearance') }" @click="setTab('appearance')">
Appearance
</button>
</div>
</template> </template>
<template v-slot:body> <template v-slot:body>
<Select title="Theme" :options="themes" v-model="theme" /> <div v-if="isTab('behaviour')">
<component :is="settingFieldsComponent" /> <Toggle :title="autosaveTitle" v-model="autosave" />
<Toggle title="Show TPS" v-model="showTPS" /> <FeedbackButton v-if="!autosave" class="button save-button" @click="save()"
<hr /> >Manually save</FeedbackButton
<Toggle :title="autosaveTitle" v-model="autosave" /> >
<Toggle v-if="projInfo.enablePausing" :title="isPausedTitle" v-model="isPaused" /> <Toggle v-if="projInfo.enablePausing" :title="isPausedTitle" v-model="isPaused" />
<Toggle :title="progressMethodTitle" v-model="usingLog" /> </div>
<div v-if="isTab('appearance')">
<Select :title="themeTitle" :options="themes" v-model="theme" />
<component :is="settingFieldsComponent" />
<Toggle :title="showTPSTitle" v-model="showTPS" />
<Toggle :title="progressMethodTitle" v-model="usingLog" />
<Toggle :title="alignModifierUnitsTitle" v-model="alignUnits" />
</div>
</template> </template>
</Modal> </Modal>
</template> </template>
@ -24,19 +39,36 @@ import Tooltip from "features/tooltips/Tooltip.vue";
import player from "game/player"; import player from "game/player";
import settings, { settingFields } from "game/settings"; import settings, { settingFields } from "game/settings";
import { camelToTitle } from "util/common"; import { camelToTitle } from "util/common";
import { save } from "util/save";
import { coerceComponent, render } from "util/vue"; import { coerceComponent, render } from "util/vue";
import { computed, ref, toRefs } from "vue"; import { computed, ref, toRefs } from "vue";
import Select from "./fields/Select.vue"; import Select from "./fields/Select.vue";
import Toggle from "./fields/Toggle.vue"; import Toggle from "./fields/Toggle.vue";
import FeedbackButton from "./fields/FeedbackButton.vue";
const isOpen = ref(false); const isOpen = ref(false);
const currentTab = ref("behaviour");
defineExpose({ defineExpose({
isTab,
setTab,
save() {
save();
},
open() { open() {
isOpen.value = true; isOpen.value = true;
} }
}); });
function isTab(tab: string): boolean {
return tab == currentTab.value;
}
function setTab(tab: string) {
currentTab.value = tab;
}
const themes = Object.keys(rawThemes).map(theme => ({ const themes = Object.keys(rawThemes).map(theme => ({
label: camelToTitle(theme), label: camelToTitle(theme),
value: theme value: theme
@ -46,8 +78,10 @@ const settingFieldsComponent = computed(() => {
return coerceComponent(jsx(() => <>{settingFields.map(render)}</>)); return coerceComponent(jsx(() => <>{settingFields.map(render)}</>));
}); });
const { showTPS, theme } = toRefs(settings); const { showTPS, theme, usingLog, alignUnits } = toRefs(settings);
const { autosave, usingLog } = toRefs(player);
const { autosave, autoPause } = toRefs(player);
const isPaused = computed({ const isPaused = computed({
get() { get() {
return player.devSpeed === 0; return player.devSpeed === 0;
@ -58,26 +92,86 @@ const isPaused = computed({
}); });
const autosaveTitle = jsx(() => ( const autosaveTitle = jsx(() => (
<span> <span class="option-title">
Autosave<Tooltip display="Save-specific">*</Tooltip> Autosave<Tooltip display="Save-specific">*</Tooltip>
<desc>Automatically save the game every second or when the game is closed.</desc>
</span> </span>
)); ));
const isPausedTitle = jsx(() => ( const isPausedTitle = jsx(() => (
<span> <span class="option-title">
Pause game<Tooltip display="Save-specific">*</Tooltip> Pause game<Tooltip display="Save-specific">*</Tooltip>
<desc>Stop everything from moving.</desc>
</span>
));
const autoPauseTitle = jsx(() => (
<span class="option-title">
Auto-pause<Tooltip display="Save-specific">*</Tooltip>
<desc>
Automatically pause the game when a day is completed. It is best to keep this on to
avoid over-grinding.
</desc>
</span>
));
const themeTitle = jsx(() => (
<span class="option-title">
Theme
<desc>How the game looks.</desc>
</span>
));
const showTPSTitle = jsx(() => (
<span class="option-title">
Show TPS
<desc>Show TPS meter at the bottom-left corner of the page.</desc>
</span> </span>
)); ));
const progressMethodTitle = jsx(() => ( const progressMethodTitle = jsx(() => (
<span> <span class="option-title">
Use log for progress bar<Tooltip display="Save-specific">*</Tooltip> Logarithmic progress bars
<desc>Whether progress bars should be normalized for exponential growth.</desc>
</span>
));
const alignModifierUnitsTitle = jsx(() => (
<span class="option-title">
Align modifier units
<desc>Align numbers to the beginning of the unit in modifier view.</desc>
</span> </span>
)); ));
</script> </script>
<style scoped> <style>
.option-tabs {
border-bottom: 2px solid var(--outline);
}
*:deep() .tooltip-container { .option-tabs button {
background-color: transparent;
color: var(--foreground);
margin-bottom: -2px;
font-size: 14px;
cursor: pointer;
padding: 5px 20px;
border: none;
border-bottom: 2px solid var(--foreground);
}
.option-tabs button:not(.selected) {
border-bottom-color: transparent;
}
.option-title .tooltip-container {
display: inline; display: inline;
margin-left: 5px; margin-left: 5px;
} }
.option-title desc {
display: block;
opacity: 0.6;
font-size: small;
width: 300px;
margin-left: 0;
}
.save-button {
text-align: right;
}
</style> </style>

View file

@ -8,10 +8,13 @@
} }
.modifier-amount { .modifier-amount {
flex-basis: 100px;
flex-shrink: 0; flex-shrink: 0;
text-align: right; text-align: right;
} }
:not(:first-of-type, :last-of-type) > .modifier-amount::after {
content: var(--unit);
opacity: 0;
}
.modifier-description { .modifier-description {
flex-grow: 1; flex-grow: 1;

View file

@ -87,6 +87,10 @@ function onUpdate(value: SelectOption) {
background-color: var(--bought); background-color: var(--bought);
} }
.vue-input input {
font-size: inherit;
}
.vue-input input::placeholder { .vue-input input::placeholder {
color: var(--link); color: var(--link);
} }

View file

@ -44,14 +44,16 @@ input {
span { span {
width: 100%; width: 100%;
padding-right: 41px;
position: relative; position: relative;
} }
/* track */ /* track */
input + span::before { input + span::before {
content: ""; content: "";
float: right; position: absolute;
margin: 5px 0 5px 10px; top: calc(50% - 7px);
right: 0px;
border-radius: 7px; border-radius: 7px;
width: 36px; width: 36px;
height: 14px; height: 14px;
@ -66,7 +68,7 @@ input + span::before {
input + span::after { input + span::after {
content: ""; content: "";
position: absolute; position: absolute;
top: 2px; top: calc(50% - 10px);
right: 16px; right: 16px;
border-radius: 50%; border-radius: 50%;
width: 20px; width: 20px;

View file

@ -7,7 +7,27 @@
style="left: 4%; bottom: 3%; width: 40px; height: 40px" 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: 10%; bottom: 10%" />
<img v-if="day >= 1" :src="workshop" class="scene-item" style="left: 40%; bottom: 12%" /> <img
v-if="day >= 12"
:src="advManagement"
class="scene-item"
style="left: 33%; bottom: 12%; width: 30%; height: 60%"
/>
<template v-else>
<img
v-if="day >= 11"
:src="management"
class="scene-item"
style="left: 28%; bottom: 12%"
/>
<img
v-if="day >= 1"
:src="workshop"
class="scene-item"
style="left: 40%; bottom: 12%"
/>
<img v-if="day >= 3" :src="elves" class="scene-item" style="left: 52%; bottom: 12%" />
</template>
<img <img
v-if="day >= 2" v-if="day >= 2"
:src="coal" :src="coal"
@ -21,8 +41,11 @@
style="left: 72%; bottom: 8%; width: 40px; height: 40px" style="left: 72%; bottom: 8%; width: 40px; height: 40px"
/> />
<img v-if="day >= 8" :src="oil" class="scene-item" style="left: 80%; bottom: 6%" /> <img v-if="day >= 8" :src="oil" class="scene-item" style="left: 80%; bottom: 6%" />
<img v-if="day >= 3" :src="elves" class="scene-item" style="left: 52%; bottom: 12%" /> <div
<div v-if="day >= 4" class="scene-bubble" style="left: 50%; bottom: 38%"> v-if="day >= 4"
class="scene-bubble"
:style="day >= 12 ? `left: 33%; bottom: 73%` : `left: 50%; bottom: 38%`"
>
<img v-if="day >= 4" :src="paper" class="scene-item" /> <img v-if="day >= 4" :src="paper" class="scene-item" />
<img v-if="day >= 5" :src="boxes" class="scene-item" /> <img v-if="day >= 5" :src="boxes" class="scene-item" />
<img v-if="day >= 9" :src="plastic" class="scene-item" /> <img v-if="day >= 9" :src="plastic" class="scene-item" />
@ -43,6 +66,8 @@ import cloth from "./symbols/cloth.png";
import oil from "./symbols/oil.png"; import oil from "./symbols/oil.png";
import plastic from "./symbols/plastic.png"; import plastic from "./symbols/plastic.png";
import dyes from "./symbols/dyes.png"; import dyes from "./symbols/dyes.png";
import management from "./symbols/elfManagement.png";
import advManagement from "./symbols/workshopMansion.png";
defineProps<{ defineProps<{
day: number; day: number;
@ -52,8 +77,9 @@ defineProps<{
<style scoped> <style scoped>
.scene { .scene {
width: 600px; width: 600px;
height: 300px;
position: relative; position: relative;
max-width: 95%;
aspect-ratio: 2/1;
} }
.scene::after { .scene::after {
@ -69,8 +95,8 @@ defineProps<{
} }
.scene-item { .scene-item {
width: 80px; width: 13.3%;
height: 80px; height: 26.6%;
position: absolute; position: absolute;
z-index: 1; z-index: 1;
} }
@ -78,7 +104,7 @@ defineProps<{
.scene-bubble { .scene-bubble {
position: absolute; position: absolute;
background: white; background: white;
height: 60px; height: 20%;
padding: 5px; padding: 5px;
border-radius: 10px; border-radius: 10px;
} }
@ -96,8 +122,9 @@ defineProps<{
} }
.scene-bubble .scene-item { .scene-bubble .scene-item {
height: 60px; height: calc(100% - 10px);
width: 60px; width: unset;
aspect-ratio: 1/1;
position: static; position: static;
} }
</style> </style>

View file

@ -20,6 +20,7 @@ import type { Modifier } from "game/modifiers";
import type { Persistent } from "game/persistence"; import type { Persistent } from "game/persistence";
import { DefaultValue, persistent } from "game/persistence"; import { DefaultValue, persistent } from "game/persistence";
import player from "game/player"; import player from "game/player";
import settings from "game/settings";
import type { DecimalSource } from "util/bignum"; import type { DecimalSource } from "util/bignum";
import Decimal, { format } from "util/bignum"; import Decimal, { format } from "util/bignum";
import { formatWhole } from "util/break_eternity"; import { formatWhole } from "util/break_eternity";
@ -333,7 +334,7 @@ export function createCollapsibleModifierSections(
return ( return (
<> <>
{hasPreviousSection ? <br /> : null} {hasPreviousSection ? <br /> : null}
<div> <div style={{"--unit": settings.alignUnits && s.unit ? "'" + s.unit + "'" : ""}}>
{header} {header}
<br /> <br />
{modifiers} {modifiers}
@ -424,7 +425,7 @@ export function setUpDailyProgressTracker(options: {
if (main.day.value !== options.day) return 1; if (main.day.value !== options.day) return 1;
let progress = Decimal.add(total.value, 1); let progress = Decimal.add(total.value, 1);
let requirement = options.goal; let requirement = options.goal;
if (options.usingLog?.value ?? player.usingLog) { if (options.usingLog?.value ?? settings.usingLog) {
progress = progress.log10(); progress = progress.log10();
requirement = Decimal.log10(requirement); requirement = Decimal.log10(requirement);
} }

View file

@ -15,7 +15,12 @@ import { createResource, displayResource, Resource } from "features/resources/re
import { createUpgrade, GenericUpgrade } from "features/upgrades/upgrade"; import { createUpgrade, GenericUpgrade } from "features/upgrades/upgrade";
import { globalBus } from "game/events"; import { globalBus } from "game/events";
import { BaseLayer, createLayer } from "game/layers"; import { BaseLayer, createLayer } from "game/layers";
import { createExponentialModifier, createSequentialModifier, Modifier } from "game/modifiers"; import {
createExponentialModifier,
createMultiplicativeModifier,
createSequentialModifier,
Modifier
} from "game/modifiers";
import { noPersist } from "game/persistence"; import { noPersist } from "game/persistence";
import Decimal, { DecimalSource, format, formatWhole } from "util/bignum"; import Decimal, { DecimalSource, format, formatWhole } from "util/bignum";
import { WithRequired } from "util/common"; import { WithRequired } from "util/common";
@ -26,8 +31,13 @@ import management from "./management";
import paper from "./paper"; import paper from "./paper";
import plastic from "./plastic"; import plastic from "./plastic";
import trees from "./trees"; import trees from "./trees";
import workshop from "./workshop";
export type BoxesBuyable = GenericBuyable & { resource: Resource; freeLevels: ComputedRef<DecimalSource>; totalAmount: ComputedRef<Decimal> }; export type BoxesBuyable = GenericBuyable & {
resource: Resource;
freeLevels: ComputedRef<DecimalSource>;
totalAmount: ComputedRef<Decimal>;
};
const id = "boxes"; const id = "boxes";
const day = 6; const day = 6;
@ -38,6 +48,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
const boxes = createResource<DecimalSource>(0, "boxes"); const boxes = createResource<DecimalSource>(0, "boxes");
const boxGain = createSequentialModifier(() => [ const boxGain = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "1000% Foundation Completed",
enabled: workshop.milestones.extraExpansionMilestone5.earned
})),
createExponentialModifier(() => ({ createExponentialModifier(() => ({
exponent: 1.1, exponent: 1.1,
description: "Bell Level 2", description: "Bell Level 2",
@ -164,7 +179,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Carry dye in boxes", title: "Carry dye in boxes",
description: "Double all dye gain" description: "Double all dye gain"
} }
})) as GenericUpgrade; })) as GenericUpgrade;
const xpUpgrade = createUpgrade(() => ({ const xpUpgrade = createUpgrade(() => ({
resource: noPersist(boxes), resource: noPersist(boxes),
cost: 1e18, cost: 1e18,
@ -178,7 +193,19 @@ const layer = createLayer(id, function (this: BaseLayer) {
const logBoxesBuyable = createBuyable(() => ({ const logBoxesBuyable = createBuyable(() => ({
display: { display: {
title: "Carry more logs", title: "Carry more logs",
description: jsx(() => <>Use boxes to carry even more logs, boosting their gain<br /><br /><div>Amount: {formatWhole(logBoxesBuyable.amount.value)}{Decimal.gt(logBoxesBuyable.freeLevels.value, 0) ? <> (+{formatWhole(logBoxesBuyable.freeLevels.value)})</> : null}</div></>), description: jsx(() => (
<>
Use boxes to carry even more logs, boosting their gain
<br />
<br />
<div>
Amount: {formatWhole(logBoxesBuyable.amount.value)}
{Decimal.gt(logBoxesBuyable.freeLevels.value, 0) ? (
<> (+{formatWhole(logBoxesBuyable.freeLevels.value)})</>
) : null}
</div>
</>
)),
effectDisplay: jsx(() => ( effectDisplay: jsx(() => (
<>{format(Decimal.div(logBoxesBuyable.totalAmount.value, 2).add(1))}x</> <>{format(Decimal.div(logBoxesBuyable.totalAmount.value, 2).add(1))}x</>
)), )),
@ -195,13 +222,34 @@ const layer = createLayer(id, function (this: BaseLayer) {
return Decimal.pow(scaling, v).times(100).div(dyes.boosts.orange2.value); return Decimal.pow(scaling, v).times(100).div(dyes.boosts.orange2.value);
}, },
visibility: () => showIf(logsUpgrade.bought.value), visibility: () => showIf(logsUpgrade.bought.value),
freeLevels: computed(() => management.elfTraining.boxElfTraining.milestones[0].earned.value ? Decimal.max(ashBoxesBuyable.amount.value, 1).sqrt().floor().add(Decimal.max(coalBoxesBuyable.amount.value, 1).sqrt().floor()) : 0), freeLevels: computed(() =>
totalAmount: computed(() => Decimal.add(logBoxesBuyable.amount.value, logBoxesBuyable.freeLevels.value)) management.elfTraining.boxElfTraining.milestones[0].earned.value
? Decimal.max(ashBoxesBuyable.amount.value, 1)
.sqrt()
.floor()
.add(Decimal.max(coalBoxesBuyable.amount.value, 1).sqrt().floor())
: 0
),
totalAmount: computed(() =>
Decimal.add(logBoxesBuyable.amount.value, logBoxesBuyable.freeLevels.value)
)
})) as BoxesBuyable; })) as BoxesBuyable;
const ashBoxesBuyable = createBuyable(() => ({ const ashBoxesBuyable = createBuyable(() => ({
display: { display: {
title: "Carry more ash", title: "Carry more ash",
description: jsx(() => <>Use boxes to carry even more ash, boosting its gain<br /><br /><div>Amount: {formatWhole(ashBoxesBuyable.amount.value)}{Decimal.gt(ashBoxesBuyable.freeLevels.value, 0) ? <> (+{formatWhole(ashBoxesBuyable.freeLevels.value)})</> : null}</div></>), description: jsx(() => (
<>
Use boxes to carry even more ash, boosting its gain
<br />
<br />
<div>
Amount: {formatWhole(ashBoxesBuyable.amount.value)}
{Decimal.gt(ashBoxesBuyable.freeLevels.value, 0) ? (
<> (+{formatWhole(ashBoxesBuyable.freeLevels.value)})</>
) : null}
</div>
</>
)),
effectDisplay: jsx(() => ( effectDisplay: jsx(() => (
<>{format(Decimal.div(ashBoxesBuyable.totalAmount.value, 2).add(1))}x</> <>{format(Decimal.div(ashBoxesBuyable.totalAmount.value, 2).add(1))}x</>
)), )),
@ -218,13 +266,34 @@ const layer = createLayer(id, function (this: BaseLayer) {
return Decimal.pow(scaling, v).times(1000).div(dyes.boosts.orange2.value); return Decimal.pow(scaling, v).times(1000).div(dyes.boosts.orange2.value);
}, },
visibility: () => showIf(ashUpgrade.bought.value), visibility: () => showIf(ashUpgrade.bought.value),
freeLevels: computed(() => management.elfTraining.boxElfTraining.milestones[0].earned.value ? Decimal.max(logBoxesBuyable.amount.value, 1).sqrt().floor().add(Decimal.max(coalBoxesBuyable.amount.value, 1).sqrt().floor()) : 0), freeLevels: computed(() =>
totalAmount: computed(() => Decimal.add(ashBoxesBuyable.amount.value, ashBoxesBuyable.freeLevels.value)) management.elfTraining.boxElfTraining.milestones[0].earned.value
? Decimal.max(logBoxesBuyable.amount.value, 1)
.sqrt()
.floor()
.add(Decimal.max(coalBoxesBuyable.amount.value, 1).sqrt().floor())
: 0
),
totalAmount: computed(() =>
Decimal.add(ashBoxesBuyable.amount.value, ashBoxesBuyable.freeLevels.value)
)
})) as BoxesBuyable; })) as BoxesBuyable;
const coalBoxesBuyable = createBuyable(() => ({ const coalBoxesBuyable = createBuyable(() => ({
display: { display: {
title: "Carry more coal", title: "Carry more coal",
description: jsx(() => <>Use boxes to carry even more coal, boosting its gain<br /><br /><div>Amount: {formatWhole(coalBoxesBuyable.amount.value)}{Decimal.gt(coalBoxesBuyable.freeLevels.value, 0) ? <> (+{formatWhole(coalBoxesBuyable.freeLevels.value)})</> : null}</div></>), description: jsx(() => (
<>
Use boxes to carry even more coal, boosting its gain
<br />
<br />
<div>
Amount: {formatWhole(coalBoxesBuyable.amount.value)}
{Decimal.gt(coalBoxesBuyable.freeLevels.value, 0) ? (
<> (+{formatWhole(coalBoxesBuyable.freeLevels.value)})</>
) : null}
</div>
</>
)),
effectDisplay: jsx(() => ( effectDisplay: jsx(() => (
<>{format(Decimal.div(coalBoxesBuyable.totalAmount.value, 2).add(1))}x</> <>{format(Decimal.div(coalBoxesBuyable.totalAmount.value, 2).add(1))}x</>
)), )),
@ -241,8 +310,17 @@ const layer = createLayer(id, function (this: BaseLayer) {
return Decimal.pow(scaling, v).times(1000).div(dyes.boosts.orange2.value); return Decimal.pow(scaling, v).times(1000).div(dyes.boosts.orange2.value);
}, },
visibility: () => showIf(coalUpgrade.bought.value), visibility: () => showIf(coalUpgrade.bought.value),
freeLevels: computed(() => management.elfTraining.boxElfTraining.milestones[0].earned.value ? Decimal.max(logBoxesBuyable.amount.value, 1).sqrt().floor().add(Decimal.max(ashBoxesBuyable.amount.value, 1).sqrt().floor()) : 0), freeLevels: computed(() =>
totalAmount: computed(() => Decimal.add(coalBoxesBuyable.amount.value, coalBoxesBuyable.freeLevels.value)) management.elfTraining.boxElfTraining.milestones[0].earned.value
? Decimal.max(logBoxesBuyable.amount.value, 1)
.sqrt()
.floor()
.add(Decimal.max(ashBoxesBuyable.amount.value, 1).sqrt().floor())
: 0
),
totalAmount: computed(() =>
Decimal.add(coalBoxesBuyable.amount.value, coalBoxesBuyable.freeLevels.value)
)
})) as BoxesBuyable; })) as BoxesBuyable;
const buyables = { logBoxesBuyable, ashBoxesBuyable, coalBoxesBuyable }; const buyables = { logBoxesBuyable, ashBoxesBuyable, coalBoxesBuyable };
@ -261,7 +339,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
{ {
title: "Boxes Gain", title: "Boxes Gain",
modifier: boxGain, modifier: boxGain,
base: 1 base: () => boxesConversion.scaling.currentGain(boxesConversion)
} }
]); ]);
const showModifiersModal = ref(false); const showModifiersModal = ref(false);
@ -300,6 +378,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
row3Upgrades, row3Upgrades,
buyables, buyables,
minWidth: 700, minWidth: 700,
generalTabCollapsed,
display: jsx(() => ( display: jsx(() => (
<> <>
{render(trackerDisplay)} {render(trackerDisplay)}
@ -308,10 +387,19 @@ const layer = createLayer(id, function (this: BaseLayer) {
<Spacer /> <Spacer />
{render(makeBoxes)} {render(makeBoxes)}
<Spacer /> <Spacer />
{renderGrid(Object.values(upgrades), Object.values(row2Upgrades), Object.values(row3Upgrades))} {renderGrid(
Object.values(upgrades),
Object.values(row2Upgrades),
Object.values(row3Upgrades)
)}
<Spacer /> <Spacer />
{renderRow(...Object.values(buyables))} {renderRow(...Object.values(buyables))}
</> </>
)),
minimizedDisplay: jsx(() => (
<div>
{name} - {format(boxes.value)} {boxes.displayName}
</div>
)) ))
}; };
}); });

View file

@ -23,7 +23,7 @@ import {
createSequentialModifier createSequentialModifier
} from "game/modifiers"; } from "game/modifiers";
import { noPersist, persistent } from "game/persistence"; import { noPersist, persistent } from "game/persistence";
import Decimal, { DecimalSource } from "util/bignum"; import Decimal, { DecimalSource, format } from "util/bignum";
import { formatWhole } from "util/break_eternity"; import { formatWhole } from "util/break_eternity";
import { Direction } from "util/common"; import { Direction } from "util/common";
import { render, renderCol, renderRow } from "util/vue"; import { render, renderCol, renderRow } from "util/vue";
@ -34,6 +34,7 @@ import metal from "./metal";
import paper from "./paper"; import paper from "./paper";
import plastic from "./plastic"; import plastic from "./plastic";
import trees from "./trees"; import trees from "./trees";
import workshop from "./workshop";
const id = "cloth"; const id = "cloth";
const day = 8; const day = 8;
@ -331,7 +332,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
})); }));
const paperUpgrades = { paperUpgrade4, paperUpgrade3, paperUpgrade2, paperUpgrade1 }; const paperUpgrades = { paperUpgrade4, paperUpgrade3, paperUpgrade2, paperUpgrade1 };
const hollyEffect = computed(() => Decimal.add(trees.computedAutoCuttingAmount.value, 1).log10().add(1)); const hollyEffect = computed(() =>
Decimal.add(trees.computedAutoCuttingAmount.value, 1).root(9)
);
const gingersnapEffect = computed(() => Decimal.add(dyes.dyeSum.value, 10).log10()); const gingersnapEffect = computed(() => Decimal.add(dyes.dyeSum.value, 10).log10());
const sheepGain = createSequentialModifier(() => [ const sheepGain = createSequentialModifier(() => [
@ -358,6 +361,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: hollyEffect, multiplier: hollyEffect,
description: "Holly Level 3", description: "Holly Level 3",
enabled: management.elfTraining.cutterElfTraining.milestones[2].earned enabled: management.elfTraining.cutterElfTraining.milestones[2].earned
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "1000% Foundation Completed",
enabled: workshop.milestones.extraExpansionMilestone5.earned
})) }))
]); ]);
const computedSheepGain = computed(() => sheepGain.apply(1)); const computedSheepGain = computed(() => sheepGain.apply(1));
@ -388,6 +396,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: hollyEffect, multiplier: hollyEffect,
description: "Holly Level 3", description: "Holly Level 3",
enabled: management.elfTraining.cutterElfTraining.milestones[2].earned enabled: management.elfTraining.cutterElfTraining.milestones[2].earned
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "1000% Foundation Completed",
enabled: workshop.milestones.extraExpansionMilestone5.earned
})) }))
]); ]);
const computedShearingAmount = computed(() => shearingAmount.apply(1)); const computedShearingAmount = computed(() => shearingAmount.apply(1));
@ -418,6 +431,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: hollyEffect, multiplier: hollyEffect,
description: "Holly Level 3", description: "Holly Level 3",
enabled: management.elfTraining.cutterElfTraining.milestones[2].earned enabled: management.elfTraining.cutterElfTraining.milestones[2].earned
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "1000% Foundation Completed",
enabled: workshop.milestones.extraExpansionMilestone5.earned
})) }))
]); ]);
const computedSpinningAmount = computed(() => spinningAmount.apply(1)); const computedSpinningAmount = computed(() => spinningAmount.apply(1));
@ -557,6 +575,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
{renderCol(...Object.values(paperUpgrades))} {renderCol(...Object.values(paperUpgrades))}
</Row> </Row>
</> </>
)),
minimizedDisplay: jsx(() => (
<div>
{name} - {format(cloth.value)} {cloth.displayName}
</div>
)) ))
}; };
}); });

View file

@ -82,13 +82,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
const activeFires = persistent<DecimalSource>(0); const activeFires = persistent<DecimalSource>(0);
const fireLogs = computed(() => Decimal.times(activeFires.value, 1000)); const fireLogs = computed(() => Decimal.times(activeFires.value, 1000));
const fireCoal = computed(() => { const fireCoal = computed(() => Decimal.times(activeFires.value, 0.1));
let gain = Decimal.times(activeFires.value, 0.1);
if (management.elfTraining.smallfireElfTraining.milestones[0].earned.value) {
gain = gain.times(5);
}
return gain;
});
const fireAsh = computed(() => { const fireAsh = computed(() => {
let gain = Decimal.times(activeFires.value, 50); let gain = Decimal.times(activeFires.value, 50);
if (management.elfTraining.smallfireElfTraining.milestones[0].earned.value) { if (management.elfTraining.smallfireElfTraining.milestones[0].earned.value) {
@ -263,10 +257,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
Decimal.times( Decimal.times(
Decimal.pow(activeDrills.value, oil.row2Upgrades[1].bought.value ? 2 : 1), Decimal.pow(activeDrills.value, oil.row2Upgrades[1].bought.value ? 2 : 1),
5e7 5e7
).times(metal.efficientDrill.bought.value ? 2 : 1) )
.times(management.elfTraining.smallfireElfTraining.milestones[2].earned.value ? 2 : 1) .times(metal.efficientDrill.bought.value ? 2 : 1)
.times(management.elfTraining.bonfireElfTraining.milestones[2].earned.value ? 2 : 1) .times(management.elfTraining.smallfireElfTraining.milestones[2].earned.value ? 2 : 1)
.times(management.elfTraining.kilnElfTraining.milestones[2].earned.value ? 2 : 1) .times(management.elfTraining.bonfireElfTraining.milestones[2].earned.value ? 2 : 1)
.times(management.elfTraining.kilnElfTraining.milestones[2].earned.value ? 2 : 1)
); );
const buildDrill = createBuyable(() => ({ const buildDrill = createBuyable(() => ({
resource: metal.metal, resource: metal.metal,
@ -431,6 +426,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
if (Decimal.gte(v, 200)) v = Decimal.pow(v, 2).div(200); if (Decimal.gte(v, 200)) v = Decimal.pow(v, 2).div(200);
if (Decimal.gte(v, 2e6)) v = Decimal.pow(v, 2).div(2e6); if (Decimal.gte(v, 2e6)) v = Decimal.pow(v, 2).div(2e6);
v = Decimal.pow(0.95, paper.books.heatedCuttersBook.amount.value).times(v); v = Decimal.pow(0.95, paper.books.heatedCuttersBook.amount.value).times(v);
if (management.elfTraining.heatedCutterElfTraining.milestones[0].earned.value) {
v = Decimal.pow(0.95, paper.books.heatedCuttersBook.amount.value).times(v);
}
return Decimal.add(v, 1).pow(2.5).times(10); return Decimal.add(v, 1).pow(2.5).times(10);
}, },
display: { display: {
@ -451,7 +449,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
if (Decimal.gte(v, 200)) v = Decimal.pow(v, 2).div(200); if (Decimal.gte(v, 200)) v = Decimal.pow(v, 2).div(200);
if (Decimal.gte(v, 2e6)) v = Decimal.pow(v, 2).div(2e6); if (Decimal.gte(v, 2e6)) v = Decimal.pow(v, 2).div(2e6);
v = Decimal.pow(0.95, paper.books.heatedPlantersBook.amount.value).times(v); v = Decimal.pow(0.95, paper.books.heatedPlantersBook.amount.value).times(v);
if (management.elfTraining.heatedPlantersElfTraining.milestones[0].earned.value) { if (management.elfTraining.heatedPlanterElfTraining.milestones[0].earned.value) {
v = Decimal.pow(0.95, paper.books.heatedPlantersBook.amount.value).times(v); v = Decimal.pow(0.95, paper.books.heatedPlantersBook.amount.value).times(v);
} }
return Decimal.add(v, 1).pow(2.5).times(10); return Decimal.add(v, 1).pow(2.5).times(10);
@ -593,7 +591,13 @@ const layer = createLayer(id, function (this: BaseLayer) {
enabled: boxes.upgrades.coalUpgrade.bought enabled: boxes.upgrades.coalUpgrade.bought
})), })),
createMultiplicativeModifier(() => ({ createMultiplicativeModifier(() => ({
multiplier: () => Decimal.div(buildFire.amount.value, 10000).add(1), multiplier: () => {
let v = buildFire.amount.value;
if (management.elfTraining.smallfireElfTraining.milestones[0].earned.value) {
v = Decimal.div(buildBonfire.amount.value, 10).add(v);
}
return Decimal.div(v, 10000).add(1);
},
description: "Small Fires Synergy", description: "Small Fires Synergy",
enabled: elves.elves.smallFireElf.bought enabled: elves.elves.smallFireElf.bought
})), })),
@ -643,6 +647,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: oil.extractorCoal, multiplier: oil.extractorCoal,
description: "Heavy Extractor", description: "Heavy Extractor",
enabled: () => Decimal.gt(oil.activeExtractor.value, 0) enabled: () => Decimal.gt(oil.activeExtractor.value, 0)
})),
createExponentialModifier(() => ({
exponent: 1.05,
description: "Jack Level 2",
enabled: management.elfTraining.heatedCutterElfTraining.milestones[1].earned
})) }))
]) as WithRequired<Modifier, "description" | "revert">; ]) as WithRequired<Modifier, "description" | "revert">;
const computedCoalGain = computed(() => coalGain.apply(0)); const computedCoalGain = computed(() => coalGain.apply(0));
@ -686,7 +695,13 @@ const layer = createLayer(id, function (this: BaseLayer) {
enabled: boxes.upgrades.ashUpgrade.bought enabled: boxes.upgrades.ashUpgrade.bought
})), })),
createMultiplicativeModifier(() => ({ createMultiplicativeModifier(() => ({
multiplier: () => Decimal.div(buildFire.amount.value, 1000).add(1), multiplier: () => {
let v = buildFire.amount.value;
if (management.elfTraining.smallfireElfTraining.milestones[0].earned.value) {
v = Decimal.div(buildBonfire.amount.value, 100).add(v);
}
return Decimal.div(v, 1000).add(1);
},
description: "Small Fires Synergy", description: "Small Fires Synergy",
enabled: elves.elves.smallFireElf.bought enabled: elves.elves.smallFireElf.bought
})), })),
@ -870,7 +885,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
<MainDisplay <MainDisplay
resource={coal} resource={coal}
color={colorCoal} color={colorCoal}
style="margin-bottom: 0" style={{marginBottom: 0}}
resourceStyle={{textShadow: 'grey 0px 0px 10px'}}
effectDisplay={ effectDisplay={
Decimal.gt(computedCoalGain.value, 0) Decimal.gt(computedCoalGain.value, 0)
? `+${format(computedCoalGain.value)}/s` ? `+${format(computedCoalGain.value)}/s`
@ -942,6 +958,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
{renderGrid(row1upgrades, row2upgrades, row3upgrades)} {renderGrid(row1upgrades, row2upgrades, row3upgrades)}
{renderRow(...row3buyables)} {renderRow(...row3buyables)}
</> </>
)),
minimizedDisplay: jsx(() => (
<div>
{name} - {format(coal.value)} {coal.displayName}
</div>
)) ))
}; };
}); });

View file

@ -29,6 +29,8 @@ import boxes from "./boxes";
import cloth from "./cloth"; import cloth from "./cloth";
import coal from "./coal"; import coal from "./coal";
import management from "./management"; import management from "./management";
import metal from "./metal";
import oil from "./oil";
import paper from "./paper"; import paper from "./paper";
import plastic from "./plastic"; import plastic from "./plastic";
import trees from "./trees"; import trees from "./trees";
@ -310,6 +312,74 @@ const layer = createLayer(id, function (this: BaseLayer) {
enabled: elvesMilestone2.earned enabled: elvesMilestone2.earned
})) }))
]); ]);
const miningDrillCooldown = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "6 Elves Trained",
enabled: elvesMilestone.earned
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.times(paper.books.miningDrillBook.amount.value, 0.1).add(1),
description: "Drills and Mills",
enabled: () => Decimal.gt(paper.books.miningDrillBook.amount.value, 0)
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "10 Elves Trained",
enabled: elvesMilestone2.earned
}))
]);
const heavyDrillCooldown = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "6 Elves Trained",
enabled: elvesMilestone.earned
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.times(paper.books.heavyDrillBook.amount.value, 0.1).add(1),
description: "Deep in the Earth",
enabled: () => Decimal.gt(paper.books.heavyDrillBook.amount.value, 0)
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "10 Elves Trained",
enabled: elvesMilestone2.earned
}))
]);
const oilCooldown = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "6 Elves Trained",
enabled: elvesMilestone.earned
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.times(paper.books.oilBook.amount.value, 0.1).add(1),
description: "Burning the Midnight Oil",
enabled: () => Decimal.gt(paper.books.oilBook.amount.value, 0)
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "10 Elves Trained",
enabled: elvesMilestone2.earned
}))
]);
const metalCooldown = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "6 Elves Trained",
enabled: elvesMilestone.earned
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.times(paper.books.metalBook.amount.value, 0.1).add(1),
description: "Physical Metallurgy",
enabled: () => Decimal.gt(paper.books.metalBook.amount.value, 0)
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "10 Elves Trained",
enabled: elvesMilestone2.earned
}))
]);
const [generalTab, generalTabCollapsed] = createCollapsibleModifierSections(() => [ const [generalTab, generalTabCollapsed] = createCollapsibleModifierSections(() => [
{ {
@ -395,6 +465,34 @@ const layer = createLayer(id, function (this: BaseLayer) {
base: 10, base: 10,
unit: "/s", unit: "/s",
visible: elves.clothElf.bought visible: elves.clothElf.bought
},
{
title: "Peppermint Auto-Buy Frequency",
modifier: miningDrillCooldown,
base: 10,
unit: "/s",
visible: management.elfTraining.expandersElfTraining.milestones[3].earned
},
{
title: "Frosty Auto-Buy Frequency",
modifier: heavyDrillCooldown,
base: 10,
unit: "/s",
visible: management.elfTraining.fertilizerElfTraining.milestones[4].earned.value
},
{
title: "Cocoa Auto-Buy Frequency",
modifier: oilCooldown,
base: 10,
unit: "/s",
visible: management.elfTraining.heatedCutterElfTraining.milestones[4].earned.value
},
{
title: "Twinkle Auto-Buy Frequency",
modifier: metalCooldown,
base: 10,
unit: "/s",
visible: management.elfTraining.expandersElfTraining.milestones[4].earned
} }
]); ]);
const showModifiersModal = ref(false); const showModifiersModal = ref(false);
@ -428,7 +526,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
customCost?: (amount: DecimalSource) => DecimalSource; customCost?: (amount: DecimalSource) => DecimalSource;
hasToggle?: boolean; hasToggle?: boolean;
toggleDesc?: string; toggleDesc?: string;
onAutoPurchase?: VoidFunction; onAutoPurchase?: (buyable: GenericBuyable & { resource: Resource }) => void;
onPurchase?: VoidFunction; // Will get overriden by the custom onpurchase, but that's fine onPurchase?: VoidFunction; // Will get overriden by the custom onpurchase, but that's fine
canBuy?: Computable<boolean>; canBuy?: Computable<boolean>;
buyMax?: Computable<boolean>; buyMax?: Computable<boolean>;
@ -461,7 +559,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
) { ) {
buyable.amount.value = Decimal.add(buyable.amount.value, 1); buyable.amount.value = Decimal.add(buyable.amount.value, 1);
buyProgress.value = Decimal.sub(buyProgress.value, cooldown); buyProgress.value = Decimal.sub(buyProgress.value, cooldown);
options.onAutoPurchase?.(); options.onAutoPurchase?.(buyable);
} else { } else {
buyProgress.value = cooldown; buyProgress.value = cooldown;
break; break;
@ -532,21 +630,24 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: description:
"Holly will automatically purchase cutters you can afford, without actually spending any logs.", "Holly will automatically purchase cutters you can afford, without actually spending any logs.",
buyable: trees.row1Buyables[0], buyable: trees.row1Buyables[0],
cooldownModifier: cutterCooldown cooldownModifier: cutterCooldown,
buyMax: () => management.elfTraining.cutterElfTraining.milestones[1].earned.value
}); });
const plantersElf = createElf({ const plantersElf = createElf({
name: "Ivy", name: "Ivy",
description: description:
"Ivy will automatically purchase planters you can afford, without actually spending any logs.", "Ivy will automatically purchase planters you can afford, without actually spending any logs.",
buyable: trees.row1Buyables[1], buyable: trees.row1Buyables[1],
cooldownModifier: planterCooldown cooldownModifier: planterCooldown,
buyMax: () => management.elfTraining.planterElfTraining.milestones[1].earned.value
}); });
const expandersElf = createElf({ const expandersElf = createElf({
name: "Hope", name: "Hope",
description: description:
"Hope will automatically purchase forest expanders you can afford, without actually spending any logs.", "Hope will automatically purchase forest expanders you can afford, without actually spending any logs.",
buyable: trees.row1Buyables[2], buyable: trees.row1Buyables[2],
cooldownModifier: expanderCooldown cooldownModifier: expanderCooldown,
buyMax: () => management.elfTraining.expandersElfTraining.milestones[1].earned.value
}); });
const treesElves = [cuttersElf, plantersElf, expandersElf]; const treesElves = [cuttersElf, plantersElf, expandersElf];
const heatedCuttersElf = createElf({ const heatedCuttersElf = createElf({
@ -554,7 +655,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: description:
"Jack will automatically purchase heated cutters you can afford, without actually spending any coal.", "Jack will automatically purchase heated cutters you can afford, without actually spending any coal.",
buyable: coal.heatedCutters, buyable: coal.heatedCutters,
cooldownModifier: heatedCutterCooldown cooldownModifier: heatedCutterCooldown,
buyMax: () => management.elfTraining.heatedCutterElfTraining.milestones[2].earned.value
}); });
const heatedPlantersElf = createElf({ const heatedPlantersElf = createElf({
name: "Mary", name: "Mary",
@ -657,6 +759,77 @@ const layer = createLayer(id, function (this: BaseLayer) {
visibility: () => showIf(plastic.elfUpgrades.clothElf.bought.value) visibility: () => showIf(plastic.elfUpgrades.clothElf.bought.value)
}); });
const plasticElves = [paperElf, boxElf, clothElf]; const plasticElves = [paperElf, boxElf, clothElf];
const miningDrillElf = createElf({
name: "Peppermint",
description:
"Peppermint will automatically purchase all mining drills you can afford, without actually spending any resources.",
buyable: coal.buildDrill,
cooldownModifier: miningDrillCooldown,
visibility: () =>
showIf(management.elfTraining.expandersElfTraining.milestones[3].earned.value),
hasToggle: true,
toggleDesc: "Activate auto-purchased mining drills",
onAutoPurchase() {
if (miningDrillElf.toggle.value) {
coal.activeDrills.value = Decimal.add(coal.activeDrills.value, 1);
}
}
});
const heavyDrillElf = createElf({
name: "Frosty",
description:
"Frosty will automatically purchase all drill types in the oil section, without actually spending any resources.",
buyable: [oil.buildHeavy, oil.buildHeavy2, oil.buildExtractor],
cooldownModifier: heavyDrillCooldown,
visibility: () =>
showIf(management.elfTraining.fertilizerElfTraining.milestones[4].earned.value),
hasToggle: true,
toggleDesc: "Activate auto-purchased oil drills",
onAutoPurchase(buyable) {
if (heavyDrillElf.toggle.value) {
if (buyable === oil.buildHeavy) {
oil.activeHeavy.value = Decimal.add(oil.activeHeavy.value, 1);
} else if (buyable === oil.buildHeavy) {
oil.activeHeavy.value = Decimal.add(oil.activeHeavy.value, 1);
} else if (buyable === oil.buildHeavy) {
oil.activeHeavy.value = Decimal.add(oil.activeHeavy.value, 1);
}
}
}
});
const oilElf = createElf({
name: "Cocoa",
description:
"Cocoa will automatically purchase all oil-using machines you can afford, without actually spending any resources.",
buyable: [oil.buildPump, oil.buildBurner, oil.buildSmelter],
cooldownModifier: oilCooldown,
visibility: () =>
showIf(management.elfTraining.heatedCutterElfTraining.milestones[4].earned.value),
hasToggle: true,
toggleDesc: "Activate auto-purchased oil-using machines",
onAutoPurchase(buyable) {
if (heavyDrillElf.toggle.value) {
if (buyable === oil.buildPump) {
oil.activePump.value = Decimal.add(oil.activePump.value, 1);
} else if (buyable === oil.buildBurner) {
oil.activeBurner.value = Decimal.add(oil.activeBurner.value, 1);
} else if (buyable === oil.buildSmelter) {
oil.activeSmelter.value = Decimal.add(oil.activeSmelter.value, 1);
}
}
}
});
const managementElves = [miningDrillElf, heavyDrillElf, oilElf];
const metalElf = createElf({
name: "Twinkle",
description:
"Twinkle will automatically purchase all metal buyables you can afford, without actually spending any resources.",
buyable: [metal.oreDrill, metal.industrialCrucible, metal.hotterForge],
cooldownModifier: metalCooldown,
visibility: () =>
showIf(management.elfTraining.expandersElfTraining.milestones[4].earned.value)
});
const managementElves2 = [metalElf];
const elves = { const elves = {
cuttersElf, cuttersElf,
plantersElf, plantersElf,
@ -669,7 +842,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
kilnElf, kilnElf,
paperElf, paperElf,
boxElf, boxElf,
clothElf clothElf,
miningDrillElf,
heavyDrillElf,
oilElf,
metalElf
}; };
const totalElves = computed(() => Object.values(elves).filter(elf => elf.bought.value).length); const totalElves = computed(() => Object.values(elves).filter(elf => elf.bought.value).length);
@ -849,7 +1026,14 @@ const layer = createLayer(id, function (this: BaseLayer) {
{render(modifiersModal)} {render(modifiersModal)}
<Spacer /> <Spacer />
<div style="width: 600px"> <div style="width: 600px">
{renderGrid(treesElves, coalElves, fireElves, plasticElves)} {renderGrid(
treesElves,
coalElves,
fireElves,
plasticElves,
managementElves,
managementElves2
)}
</div> </div>
{milestonesDisplay()} {milestonesDisplay()}
</> </>

View file

@ -1,50 +1,41 @@
import Spacer from "components/layout/Spacer.vue"; import Spacer from "components/layout/Spacer.vue";
import Sqrt from "components/math/Sqrt.vue";
import Fraction from "components/math/Fraction.vue"; import Fraction from "components/math/Fraction.vue";
import Sqrt from "components/math/Sqrt.vue";
import Modal from "components/Modal.vue";
import { createCollapsibleMilestones, createCollapsibleModifierSections } from "data/common"; import { createCollapsibleMilestones, createCollapsibleModifierSections } from "data/common";
import { main } from "data/projEntry"; import { main } from "data/projEntry";
import { createBar, GenericBar } from "features/bars/bar"; import { createBar, GenericBar } from "features/bars/bar";
import { createClickable, GenericClickable } from "features/clickables/clickable"; import { createBuyable } from "features/buyable";
import { jsx, JSXFunction, showIf } from "features/feature"; import { createClickable } from "features/clickables/clickable";
import { jsx, showIf } from "features/feature";
import { createMilestone, GenericMilestone } from "features/milestones/milestone"; import { createMilestone, GenericMilestone } from "features/milestones/milestone";
import { createUpgrade } from "features/upgrades/upgrade";
import { globalBus } from "game/events";
import { createLayer } from "game/layers"; import { createLayer } from "game/layers";
import { Persistent, persistent } from "game/persistence"; import {
createAdditiveModifier,
createMultiplicativeModifier,
createSequentialModifier,
Modifier
} from "game/modifiers";
import { persistent } from "game/persistence";
import Decimal, { DecimalSource, format, formatTime, formatWhole } from "util/bignum"; import Decimal, { DecimalSource, format, formatTime, formatWhole } from "util/bignum";
import { Direction } from "util/common"; import { Direction } from "util/common";
import { render, renderCol, renderGrid, renderRow } from "util/vue"; import { render, renderCol, renderGrid } from "util/vue";
import { computed, ComputedRef, ref, Ref } from "vue"; import { computed, ComputedRef, ref, Ref, unref, watchEffect } from "vue";
import { createTabFamily } from "features/tabs/tabFamily";
import { createTab } from "features/tabs/tab";
import elves from "./elves";
import trees from "./trees";
import { globalBus } from "game/events";
import { createMultiplicativeModifier, createSequentialModifier, Modifier } from "game/modifiers";
import Modal from "components/Modal.vue";
import { createBuyable, GenericBuyable } from "features/buyable";
import { createUpgrade } from "features/upgrades/upgrade";
import coal from "./coal";
import paper from "./paper";
import boxes from "./boxes"; import boxes from "./boxes";
import metal from "./metal";
import cloth from "./cloth"; import cloth from "./cloth";
import plastic from "./plastic"; import coal from "./coal";
import dyes from "./dyes"; import dyes from "./dyes";
import elves from "./elves";
import metal from "./metal";
import paper from "./paper";
import plastic from "./plastic";
import trees from "./trees";
const id = "management"; const id = "management";
const day = 12; const day = 12;
const advancedDay = 13;
interface ElfTrainingClickable extends GenericClickable {
name: string,
state: Persistent<boolean>,
displayMilestone: JSXFunction,
level: ComputedRef<number>,
exp: Persistent<DecimalSource>,
milestones: GenericMilestone[],
timeForExp: ComputedRef<DecimalSource>,
amountOfTimesDone: Ref<number>,
elfXPGainComputed: ComputedRef<DecimalSource>,
elfXPGain: Modifier,
}
const layer = createLayer(id, () => { const layer = createLayer(id, () => {
const name = "Management"; const name = "Management";
@ -58,12 +49,24 @@ const layer = createLayer(id, () => {
height: 25, height: 25,
fillStyle: `backgroundColor: ${color}`, fillStyle: `backgroundColor: ${color}`,
progress: () => progress: () =>
main.day.value === day ? totalElfLevels.value / (elves.totalElves.value * 5) : 1, main.day.value === day
? day12Elves.reduce((acc, curr) => acc + Math.min(1, curr.level.value / 3), 0) /
day12Elves.length
: main.day.value === advancedDay && main.days[advancedDay - 1].opened.value
? day13Elves.reduce((acc, curr) => acc + Math.min(1, curr.level.value / 5), 0) /
day13Elves.length
: 1,
display: jsx(() => display: jsx(() =>
main.day.value === day ? ( main.day.value === day ||
(main.day.value === advancedDay && main.days[advancedDay - 1].opened.value) ? (
<> <>
{formatWhole(totalElfLevels.value)}/{formatWhole(elves.totalElves.value * 5)}{" "} {formatWhole(
elf levels Decimal.times(
unref(dayProgress.progress),
main.day.value === advancedDay ? 80 : 36
)
)}
/{main.day.value === advancedDay ? 80 : 36} elf levels
</> </>
) : ( ) : (
"" ""
@ -78,8 +81,10 @@ const layer = createLayer(id, () => {
} }
return elfLevel; return elfLevel;
}); });
const totalElfExp = computed(() =>
Object.values(elfTraining).reduce((acc, curr) => acc.add(curr.exp.value), new Decimal(0))
);
// ------------------------------------------------------------------------------- Upgrades // ------------------------------------------------------------------------------- Upgrades
const teaching = createUpgrade(() => ({ const teaching = createUpgrade(() => ({
@ -105,12 +110,12 @@ const layer = createLayer(id, () => {
})); }));
const globalXPModifier = createSequentialModifier(() => [ const globalXPModifier = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({ createMultiplicativeModifier(() => ({
multiplier: () => classroomEffect.value, multiplier: classroomEffect,
description: "Classroom Effect", description: "Classroom Effect",
enabled: () => classroomUpgrade.bought.value enabled: classroomUpgrade.bought
})) }))
]); ]);
const globalXPModifierComputed = globalXPModifier.apply(1); const globalXPModifierComputed = computed(() => globalXPModifier.apply(1));
// ------------------------------------------------------------------------------- Training core function // ------------------------------------------------------------------------------- Training core function
@ -124,15 +129,33 @@ const layer = createLayer(id, () => {
...modifiers: Modifier[] ...modifiers: Modifier[]
) { ) {
const exp = persistent<DecimalSource>(0); const exp = persistent<DecimalSource>(0);
const expRequiredForNextLevel = computed(() => Decimal.pow(10, level.value).mul(1e4)); let costMulti =
[
"Holly",
"Ivy",
"Hope",
"Jack",
"Mary",
"Noel",
"Joy",
"Faith",
"Snowball",
"Star",
"Bell",
"Gingersnap"
].indexOf(elf.name) + 1;
if (elf.name == "Star" || elf.name == "Bell") {
costMulti /= 3;
}
const costBase = Decimal.mul(4000, costMulti);
const expRequiredForNextLevel = computed(() => Decimal.pow(5, level.value).mul(costBase));
const level = computed(() => const level = computed(() =>
Decimal.min( Decimal.affordGeometricSeries(exp.value, costBase, 5, 0)
Decimal.mul(9, exp.value).div(1e4).add(1).log10().floor(), .min(schools.amount.value)
schools.amount.value .toNumber()
).toNumber()
); );
const expToNextLevel = computed(() => const expToNextLevel = computed(() =>
Decimal.sub(exp.value, Decimal.pow(10, level.value).sub(1).div(9).mul(1e4)) Decimal.sub(exp.value, Decimal.sumGeometricSeries(level.value, costBase, 5, 0))
); );
const bar = createBar(() => ({ const bar = createBar(() => ({
direction: Direction.Right, direction: Direction.Right,
@ -140,17 +163,24 @@ const layer = createLayer(id, () => {
height: 12, height: 12,
style: () => ({ style: () => ({
"margin-top": "8px", "margin-top": "8px",
"box-shadow": focusTargets.value[elf.name] "box-shadow": focusTargets.value[elf.name]
? "0 0 12px " + (currentShown.value == elf.name ? "black" : "white") ? "0 0 12px " + (currentShown.value == elf.name ? "black" : "white")
: "", : ""
}), }),
baseStyle: "margin-top: 0", baseStyle: "margin-top: 0",
fillStyle: "margin-top: 0; transition-duration: 0s", fillStyle: "margin-top: 0; transition-duration: 0s",
borderStyle: () => Decimal.gte(level.value, schools.amount.value) ? "border-color: red" : "", borderStyle: () =>
Decimal.gte(level.value, schools.amount.value) ? "border-color: red" : "",
progress: () => Decimal.div(expToNextLevel.value, expRequiredForNextLevel.value), progress: () => Decimal.div(expToNextLevel.value, expRequiredForNextLevel.value),
display: jsx(() => Decimal.gte(level.value, schools.amount.value) display: jsx(() =>
? <>Limit reached</> Decimal.gte(level.value, schools.amount.value) ? (
: <>{format(expToNextLevel.value)}/{format(expRequiredForNextLevel.value)} XP</>) <>Limit reached</>
) : (
<>
{format(expToNextLevel.value)}/{format(expRequiredForNextLevel.value)} XP
</>
)
)
})); }));
const { collapseMilestones: state, display: displayMilestone } = const { collapseMilestones: state, display: displayMilestone } =
createCollapsibleMilestones(milestones as Record<number, GenericMilestone>); createCollapsibleMilestones(milestones as Record<number, GenericMilestone>);
@ -162,20 +192,23 @@ const layer = createLayer(id, () => {
createMultiplicativeModifier(() => ({ createMultiplicativeModifier(() => ({
multiplier: focusMulti, multiplier: focusMulti,
description: "Focus Multiplier", description: "Focus Multiplier",
enabled: () => focusRolling.value <= 0 && focusTargets.value[elf.name] == true enabled: () =>
Decimal.gt(focusTime.value, 0) && focusTargets.value[elf.name] == true
})), })),
...modifiers ...modifiers
]); ]);
const elfXPGainComputed = computed(() => elfXPGain.apply(0.1)); const elfXPGainComputed = computed(() => elfXPGain.apply(0.1));
const click = createClickable(() => ({ const click = createClickable(() => ({
display: { display: {
title: elf.name, title: jsx(() => (
<>
{elf.name} - LV {formatWhole(level.value)}
</>
)),
description: jsx(() => ( description: jsx(() => (
<> <>
{elf.name} is currently at level {formatWhole(level.value)}, and {elf.name} can buy buyables {formatWhole(elf.computedAutoBuyCooldown.value)}{" "}
achieved a total of {format(exp.value)} XP. times per second, gaining{" "}
They buy buyables {formatWhole(elf.computedAutoBuyCooldown.value)} times per
second, gaining{" "}
{Decimal.gte(level.value, schools.amount.value) {Decimal.gte(level.value, schools.amount.value)
? 0 ? 0
: format( : format(
@ -191,7 +224,7 @@ const layer = createLayer(id, () => {
}, },
style: () => ({ style: () => ({
width: "190px", width: "190px",
background: currentShown.value == elf.name ? "var(--foreground)" : "", background: currentShown.value == elf.name ? "var(--foreground)" : ""
}), }),
onClick() { onClick() {
currentShown.value = elf.name; currentShown.value = elf.name;
@ -219,7 +252,12 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Holly Level 1", requirement: "Holly Level 1",
effectDisplay: jsx(() => <>Multiply log gain by (<Sqrt>Cutter amount</Sqrt>)<sup>3</sup>.</>) effectDisplay: jsx(() => (
<>
Multiply log gain by <sup>9</sup>
<Sqrt>Cutter amount</Sqrt>.
</>
))
}, },
shouldEarn: () => cutterElfTraining.level.value >= 1 shouldEarn: () => cutterElfTraining.level.value >= 1
})), })),
@ -234,7 +272,12 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Holly Level 3", requirement: "Holly Level 3",
effectDisplay: jsx(() => <>Multiply all cloth actions' effectiveness by (<Sqrt>Cutter amount</Sqrt>)<sup>3</sup>.</>) effectDisplay: jsx(() => (
<>
Multiply all cloth actions' effectiveness by log<sub>10</sub>(Cutter
amount).
</>
))
}, },
visibility: () => showIf(cutterElfMilestones[1].earned.value), visibility: () => showIf(cutterElfMilestones[1].earned.value),
shouldEarn: () => cutterElfTraining.level.value >= 3 shouldEarn: () => cutterElfTraining.level.value >= 3
@ -242,7 +285,7 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Holly Level 4", requirement: "Holly Level 4",
effectDisplay: "Multiply cutting speed by 1.1 per day completed" effectDisplay: "Multiply auto cutting amount by 1.1 per day completed"
}, },
visibility: () => showIf(cutterElfMilestones[2].earned.value && main.day.value >= 13), visibility: () => showIf(cutterElfMilestones[2].earned.value && main.day.value >= 13),
shouldEarn: () => cutterElfTraining.level.value >= 4 shouldEarn: () => cutterElfTraining.level.value >= 4
@ -275,7 +318,14 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Ivy Level 3", requirement: "Ivy Level 3",
effectDisplay: jsx(() => <>Planting speed is multiplied by 2<sup>(log<sub>10</sub>(logs)<sup>0.2</sup>)</sup></>) effectDisplay: jsx(() => (
<>
Auto planting speed is multiplied by 2
<sup>
(log<sub>10</sub>(logs)<sup>0.2</sup>)
</sup>
</>
))
}, },
visibility: () => showIf(planterElfMilestones[1].earned.value), visibility: () => showIf(planterElfMilestones[1].earned.value),
shouldEarn: () => planterElfTraining.level.value >= 3 shouldEarn: () => planterElfTraining.level.value >= 3
@ -291,7 +341,8 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Ivy Level 5", requirement: "Ivy Level 5",
effectDisplay: "Boost planting/cutting speed based on which is falling behind" effectDisplay:
"The lesser of auto planting and cutting amounts is increased to match the greater"
}, },
visibility: () => showIf(planterElfMilestones[3].earned.value && main.day.value >= 13), visibility: () => showIf(planterElfMilestones[3].earned.value && main.day.value >= 13),
shouldEarn: () => planterElfTraining.level.value >= 5 shouldEarn: () => planterElfTraining.level.value >= 5
@ -301,7 +352,7 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Hope Level 1", requirement: "Hope Level 1",
effectDisplay: "Planting speed boosts forest size" effectDisplay: "Forest size grows by trees planted per second raised to ^0.99"
}, },
shouldEarn: () => expandersElfTraining.level.value >= 1 shouldEarn: () => expandersElfTraining.level.value >= 1
})), })),
@ -316,7 +367,8 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Hope Level 3", requirement: "Hope Level 3",
effectDisplay: "The workshop can be expanded past 100%, but costs scale faster." effectDisplay:
"The workshop can be expanded past 100%, but costs scale faster. It also buys max now."
}, },
visibility: () => showIf(expanderElfMilestones[1].earned.value), visibility: () => showIf(expanderElfMilestones[1].earned.value),
shouldEarn: () => expandersElfTraining.level.value >= 3 shouldEarn: () => expandersElfTraining.level.value >= 3
@ -342,7 +394,7 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Jack Level 1", requirement: "Jack Level 1",
effectDisplay: "Heated cutters are less expensive." effectDisplay: '"Fahrenheit 451" affects "Heated Cutters" twice.'
}, },
shouldEarn: () => heatedCutterElfTraining.level.value >= 1 shouldEarn: () => heatedCutterElfTraining.level.value >= 1
})), })),
@ -365,7 +417,11 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Jack Level 4", requirement: "Jack Level 4",
effectDisplay: "Oil gain is multiplied based on total elf levels." effectDisplay: jsx(() => (
<>
Oil gain is multiplied by <Sqrt>total elf levels</Sqrt>.
</>
))
}, },
visibility: () => visibility: () =>
showIf(heatedCutterElfMilestones[2].earned.value && main.day.value >= 13), showIf(heatedCutterElfMilestones[2].earned.value && main.day.value >= 13),
@ -374,7 +430,7 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Jack Level 5", requirement: "Jack Level 5",
effectDisplay: "Unlock an elf that autobuys oil buyables." effectDisplay: "Unlock an elf that autobuys oil-using machines."
}, },
visibility: () => visibility: () =>
showIf(heatedCutterElfMilestones[3].earned.value && main.day.value >= 13), showIf(heatedCutterElfMilestones[3].earned.value && main.day.value >= 13),
@ -392,7 +448,7 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Mary Level 2", requirement: "Mary Level 2",
effectDisplay: "Double automatic tree planting speed" effectDisplay: "Metal gain is raised to the 1.1."
}, },
visibility: () => showIf(heatedPlanterElfMilestones[0].earned.value), visibility: () => showIf(heatedPlanterElfMilestones[0].earned.value),
shouldEarn: () => heatedPlanterElfTraining.level.value >= 2 shouldEarn: () => heatedPlanterElfTraining.level.value >= 2
@ -408,7 +464,7 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Mary Level 4", requirement: "Mary Level 4",
effectDisplay: "Metal gain is raised to the 1.1." effectDisplay: "Double automatic tree planting speed"
}, },
visibility: () => visibility: () =>
showIf(heatedPlanterElfMilestones[2].earned.value && main.day.value >= 13), showIf(heatedPlanterElfMilestones[2].earned.value && main.day.value >= 13),
@ -417,7 +473,11 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Mary Level 5", requirement: "Mary Level 5",
effectDisplay: jsx(() => <>Auto smelting speed is multiplied by <Sqrt>total XP/1000</Sqrt>.</>) effectDisplay: jsx(() => (
<>
Auto smelting speed is multiplied by <Sqrt>total XP/1000</Sqrt>.
</>
))
}, },
visibility: () => visibility: () =>
showIf(heatedPlanterElfMilestones[3].earned.value && main.day.value >= 13), showIf(heatedPlanterElfMilestones[3].earned.value && main.day.value >= 13),
@ -428,9 +488,13 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Noel Level 1", requirement: "Noel Level 1",
effectDisplay: jsx(() => <>Log gain is multiplied by <Sqrt>total elf levels</Sqrt>.</>) effectDisplay: jsx(() => (
<>
Log gain is multiplied by <Sqrt>total elf levels</Sqrt>.
</>
))
}, },
shouldEarn: () => heatedPlanterElfTraining.level.value >= 1 shouldEarn: () => fertilizerElfTraining.level.value >= 1
})), })),
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
@ -438,7 +502,7 @@ const layer = createLayer(id, () => {
effectDisplay: `"The Garden Tree's Handbook" affects "Fertilized Soil" twice` effectDisplay: `"The Garden Tree's Handbook" affects "Fertilized Soil" twice`
}, },
visibility: () => showIf(fertilizerElfMilestones[0].earned.value), visibility: () => showIf(fertilizerElfMilestones[0].earned.value),
shouldEarn: () => heatedPlanterElfTraining.level.value >= 2 shouldEarn: () => fertilizerElfTraining.level.value >= 2
})), })),
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
@ -446,16 +510,20 @@ const layer = createLayer(id, () => {
effectDisplay: "Divide the mining drill cost by ln(Total logs + e)" effectDisplay: "Divide the mining drill cost by ln(Total logs + e)"
}, },
visibility: () => showIf(fertilizerElfMilestones[1].earned.value), visibility: () => showIf(fertilizerElfMilestones[1].earned.value),
shouldEarn: () => heatedPlanterElfTraining.level.value >= 3 shouldEarn: () => fertilizerElfTraining.level.value >= 3
})), })),
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Noel Level 4", requirement: "Noel Level 4",
effectDisplay: jsx(() => <>Reduce oil refinery cost by (Plastic amount)<sup>2</sup></>) effectDisplay: jsx(() => (
<>
Reduce oil refinery cost by (Plastic amount)<sup>2</sup>
</>
))
}, },
visibility: () => visibility: () =>
showIf(fertilizerElfMilestones[2].earned.value && main.day.value >= 13), showIf(fertilizerElfMilestones[2].earned.value && main.day.value >= 13),
shouldEarn: () => heatedPlanterElfTraining.level.value >= 4 shouldEarn: () => fertilizerElfTraining.level.value >= 4
})), })),
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
@ -471,7 +539,7 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Joy Level 1", requirement: "Joy Level 1",
effectDisplay: "Multiply small fire efficiency by 5." effectDisplay: "Small Fire synergy counts bonfires at reduced rate."
}, },
shouldEarn: () => smallfireElfTraining.level.value >= 1 shouldEarn: () => smallfireElfTraining.level.value >= 1
})), })),
@ -619,7 +687,11 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Star Level 4", requirement: "Star Level 4",
effectDisplay: jsx(() => <>Multiply XP requirements by 0.95<sup>(total books)</sup></>) effectDisplay: jsx(() => (
<>
Multiply XP requirements by 0.95<sup>(total books)</sup>
</>
))
}, },
visibility: () => showIf(paperElfMilestones[2].earned.value && main.day.value >= 13), visibility: () => showIf(paperElfMilestones[2].earned.value && main.day.value >= 13),
shouldEarn: () => paperElfTraining.level.value >= 4 shouldEarn: () => paperElfTraining.level.value >= 4
@ -637,7 +709,11 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Bell Level 1", requirement: "Bell Level 1",
effectDisplay: jsx(() => <>Every box buyable adds <Sqrt>level</Sqrt> levels to same-row box buyables.</>) effectDisplay: jsx(() => (
<>
Every box buyable adds <Sqrt>level</Sqrt> levels to same-row box buyables.
</>
))
}, },
shouldEarn: () => boxElfTraining.level.value >= 1 shouldEarn: () => boxElfTraining.level.value >= 1
})), })),
@ -685,7 +761,11 @@ const layer = createLayer(id, () => {
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Gingersnap Level 2", requirement: "Gingersnap Level 2",
effectDisplay: jsx(() => <>Multiply all cloth actions' effectiveness by log<sub>10</sub>(dye sum + 10)</>) effectDisplay: jsx(() => (
<>
Multiply all cloth actions' effectiveness by log<sub>10</sub>(dye sum + 10)
</>
))
}, },
visibility: () => showIf(clothElfMilestones[0].earned.value), visibility: () => showIf(clothElfMilestones[0].earned.value),
shouldEarn: () => clothElfTraining.level.value >= 2 shouldEarn: () => clothElfTraining.level.value >= 2
@ -698,26 +778,39 @@ const layer = createLayer(id, () => {
visibility: () => showIf(clothElfMilestones[1].earned.value), visibility: () => showIf(clothElfMilestones[1].earned.value),
shouldEarn: () => clothElfTraining.level.value >= 3, shouldEarn: () => clothElfTraining.level.value >= 3,
onComplete() { onComplete() {
(["red", "yellow", "blue", "orange", "green", "purple"] as const).forEach(dyeColor => { (["red", "yellow", "blue", "orange", "green", "purple"] as const).forEach(
dyes.dyes[dyeColor].amount.value = 0; dyeColor => {
dyes.dyes[dyeColor].buyable.amount.value = 0; dyes.dyes[dyeColor].amount.value = 0;
}); dyes.dyes[dyeColor].buyable.amount.value = 0;
}
);
} }
})), })),
createMilestone(() => ({ createMilestone(() => ({
display: { display: {
requirement: "Gingersnap Level 4", requirement: "Gingersnap Level 4",
effectDisplay: jsx(() => <>Multiply ALL dye gain by{" "} effectDisplay: jsx(() => (
<Fraction><div><Sqrt>classrooms</Sqrt></div><div>2</div></Fraction>+1, <>
but reset all dyes.</>) Multiply ALL dye gain by{" "}
<Fraction>
<div>
<Sqrt>classrooms</Sqrt>
</div>
<div>2</div>
</Fraction>
+1, but reset all dyes.
</>
))
}, },
visibility: () => showIf(clothElfMilestones[2].earned.value && main.day.value >= 13), visibility: () => showIf(clothElfMilestones[2].earned.value && main.day.value >= 13),
shouldEarn: () => clothElfTraining.level.value >= 4, shouldEarn: () => clothElfTraining.level.value >= 4,
onComplete() { onComplete() {
(["red", "yellow", "blue", "orange", "green", "purple"] as const).forEach(dyeColor => { (["red", "yellow", "blue", "orange", "green", "purple"] as const).forEach(
dyes.dyes[dyeColor].amount.value = 0; dyeColor => {
dyes.dyes[dyeColor].buyable.amount.value = 0; dyes.dyes[dyeColor].amount.value = 0;
}); dyes.dyes[dyeColor].buyable.amount.value = 0;
}
);
} }
})), })),
createMilestone(() => ({ createMilestone(() => ({
@ -796,7 +889,35 @@ const layer = createLayer(id, () => {
paperElfTraining, paperElfTraining,
boxElfTraining, boxElfTraining,
clothElfTraining clothElfTraining
} as Record<string, ElfTrainingClickable>; };
const day12Elves = [
cutterElfTraining,
planterElfTraining,
expandersElfTraining,
heatedCutterElfTraining,
heatedPlanterElfTraining,
fertilizerElfTraining,
smallfireElfTraining,
bonfireElfTraining,
kilnElfTraining,
paperElfTraining,
boxElfTraining,
clothElfTraining
];
const day13Elves = [
cutterElfTraining,
planterElfTraining,
expandersElfTraining,
heatedCutterElfTraining,
heatedPlanterElfTraining,
fertilizerElfTraining,
smallfireElfTraining,
bonfireElfTraining,
kilnElfTraining,
paperElfTraining,
boxElfTraining,
clothElfTraining
];
// ------------------------------------------------------------------------------- Update // ------------------------------------------------------------------------------- Update
@ -813,69 +934,115 @@ const layer = createLayer(id, () => {
); );
} }
} }
focusTime.value = Math.max(focusTime.value - diff, 0);
focusCooldown.value = Math.max(focusCooldown.value - diff, 0);
if (focusRolling.value > 0) { if (Decimal.eq(focusTime.value, 0)) {
focusRolling.value += diff; focusTargets.value = {};
focusMulti.value = Decimal.pow(focusMaxMulti.value, 1 - Math.abs(Math.sin((focusRolling.value - 1) * 3))); focusMulti.value = Decimal.pow(
rerollFocusTargets(12, 3); focusMaxMulti.value,
} else { 1 - Math.abs(Math.sin((Date.now() / 1000) * 2))
focusRolling.value = Math.min(focusRolling.value + diff, 0); );
} }
}); });
// ------------------------------------------------------------------------------- Focus // ------------------------------------------------------------------------------- Focus
const focusMulti = persistent<DecimalSource>(1); const focusMulti = persistent<DecimalSource>(1);
const focusTargets = persistent<Record<string, boolean>>({}); const focusTargets = persistent<Record<string, boolean>>({});
const focusRolling = persistent<number>(0); const focusCooldown = persistent<number>(0);
const focusTime = persistent<number>(0);
const focusMaxMultiModifiers = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "Focus Upgrade 1",
enabled: focusUpgrade1.bought
}))
]);
const maximumElvesModifier = createSequentialModifier(() => [
createAdditiveModifier(() => ({
addend: 1,
description: "Focus Upgrade 2",
enabled: focusUpgrade2.bought
}))
]);
const cooldownModifiers = createSequentialModifier(() => [
createAdditiveModifier(() => ({
addend: -5,
description: "Focus Upgrade 3",
enabled: focusUpgrade3.bought
}))
]);
const focusMaxMulti = computed(() => focusMaxMultiModifiers.apply(10));
const maximumElves = computed(() => maximumElvesModifier.apply(3));
const cooldown = computed(() => cooldownModifiers.apply(15));
const focusMaxMulti = computed<DecimalSource>(() => 10);
const focusMeter = createBar(() => ({ const focusMeter = createBar(() => ({
direction: Direction.Right, direction: Direction.Right,
width: 566, width: 566,
height: 25, height: 25,
style: `border-radius: 4px 4px 0 0`, style: `border-radius: 4px 4px 0 0`,
borderStyle: `border-radius: 4px 4px 0 0`, borderStyle: `border-radius: 4px 4px 0 0`,
fillStyle: `background: ${color}; transition: none`, fillStyle: () => ({
progress: () => Decimal.sub(focusMulti.value, 1).div(Decimal.sub(focusMaxMulti.value, 1)).toNumber(), background: focusTime.value > 0 ? color : "#7f7f00",
display: jsx(() => <>{format(focusMulti.value)}x</>) opacity: focusTime.value > 0 ? focusTime.value / 10 : 1,
transition: "none"
}),
progress: () =>
Decimal.sub(focusMulti.value, 1).div(Decimal.sub(focusMaxMulti.value, 1)).toNumber(),
display: jsx(() => (
<>
{format(focusMulti.value)}x
{focusTime.value > 0 ? (
<>
{" "}
to {Object.keys(focusTargets.value).join(", ")} for{" "}
{formatTime(focusTime.value)}
</>
) : (
""
)}
</>
))
})) as GenericBar; })) as GenericBar;
const focusButton = createClickable(() => ({ const focusButton = createClickable(() => ({
display: { display: {
title: "Focus", title: "Focus",
description: jsx(() => ( description: jsx(() => (
<> <>
{focusRolling.value <= 0 Motivate elves to focus, multiplying 3 random elves' XP gain by up to{" "}
? <>Motivate elves to focus, multiplying 3 random elves' XP gain by up to {format(focusMaxMulti.value)}x</> {format(focusMaxMulti.value)}x for 10 seconds, equal to the focus bar's effect.
: "Click to stop the focus bar" {Decimal.gte(focusCooldown.value, 0) ? (
} <>
{focusRolling.value < 0 <br />
? <><br/>Reroll cooldown: {formatTime(-focusRolling.value)}</> Reroll cooldown: {formatTime(focusCooldown.value)}
: "" </>
} ) : (
""
)}
</> </>
)) ))
}, },
style: { style: {
width: "300px" width: "300px"
}, },
canClick: () => focusRolling.value >= 0, canClick: () => Decimal.eq(focusCooldown.value, 0),
onClick() { onClick() {
if (focusRolling.value == 0) { focusCooldown.value = Decimal.fromValue(cooldown.value).toNumber();
focusRolling.value = 1; focusTime.value = 10;
} else if (focusRolling.value > 0) { rerollFocusTargets(12, maximumElves.value);
focusRolling.value = -30;
}
} }
})); }));
function rerollFocusTargets(range: number, count: number) { function rerollFocusTargets(range: number, count: DecimalSource) {
let x = 0; let x = 0;
focusTargets.value = {}; focusTargets.value = {};
count = Math.min(count, range); const newCount = Decimal.min(count, range);
while (x < count) { while (newCount.gt(x)) {
const roll = Object.values(elfTraining)[Math.floor(Math.random() * range)]?.name ?? ""; const roll = Object.values(elfTraining)[Math.floor(Math.random() * range)]?.name ?? "";
if (!focusTargets.value[roll]) { if (!focusTargets.value[roll]) {
focusTargets.value[roll] = true; focusTargets.value[roll] = true;
@ -883,19 +1050,46 @@ const layer = createLayer(id, () => {
} }
} }
} }
const focusUpgrade1 = createUpgrade(() => ({
display: {
title: "Focus Booster",
description: "Multiplies the maximum experience multiplier from focus by 2"
},
resource: trees.logs,
cost: 1e25
}));
const focusUpgrade2 = createUpgrade(() => ({
display: {
title: "Focus Buffer",
description: "Increase elves affected by focus by 1"
},
resource: trees.logs,
cost: 1e30
}));
const focusUpgrade3 = createUpgrade(() => ({
display: {
title: "Focus Upgrader",
description: "Focus can now be rerolled every 10 seconds"
},
resource: trees.logs,
cost: 1e35
}));
const upgrades = [focusUpgrade1, focusUpgrade2, focusUpgrade3];
// ------------------------------------------------------------------------------- Schools // ------------------------------------------------------------------------------- Schools
const schoolCost = computed(() => { const schoolCost = computed(() => {
const schoolFactor = Decimal.pow(10, schools.amount.value); const schoolFactor = Decimal.pow(10, schools.amount.value);
const nerfedSchoolFactor = Decimal.pow(5, schools.amount.value);
const woodFactor = Decimal.pow(2e4, Decimal.pow(schools.amount.value, 0.75));
const coalFactor = Decimal.pow(2000, schools.amount.value);
return { return {
wood: schoolFactor.mul(1e21), wood: woodFactor.mul(1e21),
coal: schoolFactor.mul(1e32), coal: coalFactor.mul(1e32),
paper: schoolFactor.mul(1e19), paper: coalFactor.mul(1e18),
boxes: schoolFactor.mul(1e13), boxes: woodFactor.mul(1e13),
metalIngots: schoolFactor.mul(1e12), metalIngots: nerfedSchoolFactor.mul(1e12),
cloth: schoolFactor.mul(1e4), cloth: schoolFactor.mul(1e4),
plastic: schoolFactor.mul(1e6), plastic: nerfedSchoolFactor.mul(1e6),
dye: Decimal.add(schools.amount.value, 1).mul(10000) dye: Decimal.add(schools.amount.value, 1).mul(10000)
}; };
}); });
@ -906,11 +1100,11 @@ const layer = createLayer(id, () => {
<h3>Build a School</h3> <h3>Build a School</h3>
<div> <div>
You gotta start somewhere, right? Each school increases the maximum level for You gotta start somewhere, right? Each school increases the maximum level for
elves by 1, up to 5. elves by 1, maximum of {main.day.value === 12 ? 3 : 5} schools.
</div> </div>
<div>You have {formatWhole(schools.amount.value)} schools, <div>
which are currently letting elves learn up to level{" "} You have {formatWhole(schools.amount.value)} schools, which are currently
{formatWhole(schools.amount.value)}. letting elves learn up to level {formatWhole(schools.amount.value)}.
</div> </div>
<div> <div>
Costs {format(schoolCost.value.wood)} logs, {format(schoolCost.value.coal)}{" "} Costs {format(schoolCost.value.wood)} logs, {format(schoolCost.value.coal)}{" "}
@ -946,27 +1140,26 @@ const layer = createLayer(id, () => {
plastic.plastic.value = Decimal.sub(plastic.plastic.value, schoolCost.value.plastic); plastic.plastic.value = Decimal.sub(plastic.plastic.value, schoolCost.value.plastic);
this.amount.value = Decimal.add(this.amount.value, 1); this.amount.value = Decimal.add(this.amount.value, 1);
}, },
purchaseLimit: 5, purchaseLimit() {
if (main.days[advancedDay - 1].opened.value) return 5
return 3
},
visibility: computed(() => showIf(teaching.bought.value)), visibility: computed(() => showIf(teaching.bought.value)),
style: "width: 600px" style: "width: 600px"
})); }));
const classroomCost = computed(() => { const classroomCost = computed(() => {
const classroomFactor = Decimal.add(schools.amount.value, 1).pow(1.5); const classroomFactor = Decimal.add(classrooms.amount.value, 1).pow(1.5);
return { return {
wood: classroomFactor.mul(1e21), wood: classroomFactor.mul(1e21),
coal: classroomFactor.mul(1e32), paper: classroomFactor.mul(1e18),
paper: classroomFactor.mul(1e19),
boxes: classroomFactor.mul(1e13), boxes: classroomFactor.mul(1e13),
metalIngots: classroomFactor.mul(1e12), metalIngots: classroomFactor.mul(1e12)
cloth: classroomFactor.mul(1e4),
plastic: classroomFactor.mul(1e6),
dye: classroomFactor.mul(10000)
}; };
}); });
const classroomEffect = computed(() => { const classroomEffect = computed(() => {
return Decimal.add(classrooms.amount.value, 1).sqrt(); return Decimal.add(classrooms.amount.value, 1).pow(0.9);
}); });
const classrooms = createBuyable(() => ({ const classrooms = createBuyable(() => ({
@ -975,44 +1168,32 @@ const layer = createLayer(id, () => {
<h3>Build a Classroom</h3> <h3>Build a Classroom</h3>
<div> <div>
Hopefully it makes the school a bit less boring. Multiplies elves' XP gain by{" "} Hopefully it makes the school a bit less boring. Multiplies elves' XP gain by{" "}
<Sqrt>Classrooms + 1</Sqrt>. (Classrooms + 1)<sup>0.9</sup>.
</div>
<div>You have {formatWhole(schools.amount.value)} classrooms,
which are currently multiplying elves' XP gain by {format(classroomEffect.value)}
</div> </div>
<div> <div>
Costs {format(classroomCost.value.wood)} logs,{" "} You have {formatWhole(classrooms.amount.value)} classrooms, which are currently
{format(classroomCost.value.coal)} coal, {format(classroomCost.value.paper)}{" "} multiplying elves' XP gain by {format(classroomEffect.value)}
paper, {format(classroomCost.value.boxes)} boxes,{" "} </div>
{format(classroomCost.value.metalIngots)} metal ingots,{" "} <div>
{format(classroomCost.value.cloth)} cloth, {format(classroomCost.value.plastic)}{" "} Costs {format(classroomCost.value.wood)} logs,
plastic, and requires {format(classroomCost.value.dye)} of red, yellow, and blue {format(classroomCost.value.paper)} paper, {format(classroomCost.value.boxes)}{" "}
dye boxes, {format(classroomCost.value.metalIngots)} metal ingots
</div> </div>
</> </>
)), )),
canPurchase(): boolean { canPurchase(): boolean {
return ( return (
classroomCost.value.wood.lte(trees.logs.value) && classroomCost.value.wood.lte(trees.logs.value) &&
classroomCost.value.coal.lte(coal.coal.value) &&
classroomCost.value.paper.lte(paper.paper.value) && classroomCost.value.paper.lte(paper.paper.value) &&
classroomCost.value.boxes.lte(boxes.boxes.value) && classroomCost.value.boxes.lte(boxes.boxes.value) &&
classroomCost.value.metalIngots.lte(metal.metal.value) && classroomCost.value.metalIngots.lte(metal.metal.value)
classroomCost.value.cloth.lte(cloth.cloth.value) &&
classroomCost.value.plastic.lte(plastic.plastic.value) &&
classroomCost.value.dye.lte(dyes.dyes.blue.amount.value) &&
classroomCost.value.dye.lte(dyes.dyes.red.amount.value) &&
classroomCost.value.dye.lte(dyes.dyes.yellow.amount.value)
); );
}, },
onPurchase() { onPurchase() {
trees.logs.value = Decimal.sub(trees.logs.value, classroomCost.value.wood); trees.logs.value = Decimal.sub(trees.logs.value, classroomCost.value.wood);
coal.coal.value = Decimal.sub(coal.coal.value, classroomCost.value.coal);
paper.paper.value = Decimal.sub(paper.paper.value, classroomCost.value.paper); paper.paper.value = Decimal.sub(paper.paper.value, classroomCost.value.paper);
boxes.boxes.value = Decimal.sub(boxes.boxes.value, classroomCost.value.boxes); boxes.boxes.value = Decimal.sub(boxes.boxes.value, classroomCost.value.boxes);
metal.metal.value = Decimal.sub(metal.metal.value, classroomCost.value.metalIngots); metal.metal.value = Decimal.sub(metal.metal.value, classroomCost.value.metalIngots);
cloth.cloth.value = Decimal.sub(cloth.cloth.value, classroomCost.value.cloth);
plastic.plastic.value = Decimal.sub(plastic.plastic.value, classroomCost.value.plastic);
this.amount.value = Decimal.add(this.amount.value, 1); this.amount.value = Decimal.add(this.amount.value, 1);
}, },
visibility: computed(() => showIf(classroomUpgrade.bought.value)), visibility: computed(() => showIf(classroomUpgrade.bought.value)),
@ -1022,6 +1203,22 @@ const layer = createLayer(id, () => {
// ------------------------------------------------------------------------------- Modifiers // ------------------------------------------------------------------------------- Modifiers
const [generalTab, generalTabCollapsed] = createCollapsibleModifierSections(() => [ const [generalTab, generalTabCollapsed] = createCollapsibleModifierSections(() => [
{
title: "Elves affected by Focus",
modifier: maximumElvesModifier,
base: 3
},
{
title: "Maximum Focus Effect",
modifier: focusMaxMultiModifiers,
base: 10
},
{
title: "Focus Cooldown",
modifier: cooldownModifiers,
unit: " secs",
base: 15
},
{ {
title: "Global XP Gain", title: "Global XP Gain",
modifier: globalXPModifier, modifier: globalXPModifier,
@ -1112,7 +1309,17 @@ const layer = createLayer(id, () => {
/> />
)); ));
watchEffect(() => {
if (main.day.value === day && day12Elves.every(elf => elf.level.value >= 3)) {
main.completeDay();
} else if (
main.day.value === advancedDay &&
day13Elves.every(elf => elf.level.value >= 5)
) {
main.completeDay();
}
});
// ------------------------------------------------------------------------------- Return // ------------------------------------------------------------------------------- Return
return { return {
@ -1123,6 +1330,7 @@ const layer = createLayer(id, () => {
elfTraining, elfTraining,
totalElfLevels, totalElfLevels,
totalElfExp,
currentShown, currentShown,
generalTabCollapsed, generalTabCollapsed,
@ -1132,12 +1340,19 @@ const layer = createLayer(id, () => {
classroomUpgrade, classroomUpgrade,
focusMultiplier: focusMulti, focusMultiplier: focusMulti,
upgrades,
focusTargets, focusTargets,
focusRolling, focusCooldown,
focusTime,
display: jsx(() => ( display: jsx(() => (
<> <>
{main.day.value === day ? `Get all elves to level 5.` : `${name} Complete!`} - {main.day.value === day
? `Get all elves to level 3.`
: main.day.value === advancedDay && main.days[advancedDay - 1].opened.value
? `Get all elves to level 5.`
: `${name} Complete!`}{" "}
-
<button <button
class="button" class="button"
style="display: inline-block;" style="display: inline-block;"
@ -1147,16 +1362,19 @@ const layer = createLayer(id, () => {
</button> </button>
{render(modifiersModal)} {render(modifiersModal)}
{render(dayProgress)} {render(dayProgress)}
<br/> <br />
{renderCol(schools, classrooms)}{" "} {renderCol(schools, classrooms)}
{renderGrid([teaching, classroomUpgrade])} {renderGrid([teaching, classroomUpgrade])}
{ <Spacer />
Decimal.gt(schools.amount.value, 0) ? <> {Decimal.gt(schools.amount.value, 0) ? (
<br/> <>
<br />
Click on an elf to see their milestones. Click on an elf to see their milestones.
<br/><br/> <br />
<br />
{render(focusButton)} {render(focusButton)}
<br/> {renderGrid(upgrades)}
<br />
{renderGrid( {renderGrid(
[focusMeter], [focusMeter],
treeElfTraining, treeElfTraining,
@ -1166,8 +1384,10 @@ const layer = createLayer(id, () => {
)} )}
<Spacer /> <Spacer />
{currentElfDisplay()} {currentElfDisplay()}
</> : "" </>
} ) : (
""
)}
</> </>
)) ))
}; };

View file

@ -4,7 +4,7 @@ import Toggle from "components/fields/Toggle.vue";
import Modal from "components/Modal.vue"; import Modal from "components/Modal.vue";
import { createCollapsibleModifierSections, setUpDailyProgressTracker } from "data/common"; import { createCollapsibleModifierSections, setUpDailyProgressTracker } from "data/common";
import { jsx, showIf } from "features/feature"; import { jsx, showIf } from "features/feature";
import { createResource, trackBest } from "features/resources/resource"; import { createResource, Resource, trackBest } from "features/resources/resource";
import { BaseLayer, createLayer } from "game/layers"; import { BaseLayer, createLayer } from "game/layers";
import Decimal, { DecimalSource } from "lib/break_eternity"; import Decimal, { DecimalSource } from "lib/break_eternity";
import { render, renderRow } from "util/vue"; import { render, renderRow } from "util/vue";
@ -12,6 +12,7 @@ import { persistent } from "game/persistence";
import { globalBus } from "game/events"; import { globalBus } from "game/events";
import { import {
createAdditiveModifier, createAdditiveModifier,
createExponentialModifier,
createMultiplicativeModifier, createMultiplicativeModifier,
createSequentialModifier createSequentialModifier
} from "game/modifiers"; } from "game/modifiers";
@ -30,6 +31,8 @@ import boxes from "./boxes";
import cloth from "./cloth"; import cloth from "./cloth";
import plastic from "./plastic"; import plastic from "./plastic";
import dyes from "./dyes"; import dyes from "./dyes";
import management from "./management";
import workshop from "./workshop";
const id = "metal"; const id = "metal";
const day = 7; const day = 7;
@ -78,6 +81,17 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: () => Decimal.add(cloth.cloth.value, 1).log10().plus(1), multiplier: () => Decimal.add(cloth.cloth.value, 1).log10().plus(1),
description: "Glistening Paint", description: "Glistening Paint",
enabled: dyes.upgrades.redDyeUpg.bought enabled: dyes.upgrades.redDyeUpg.bought
})),
createMultiplicativeModifier(() => ({
multiplier: () =>
Decimal.div(workshop.foundationProgress.value, 10).floor().div(10).add(1),
description: "400% Foundation Completed",
enabled: workshop.milestones.extraExpansionMilestone2.earned
})),
createExponentialModifier(() => ({
exponent: 1.1,
description: "Mary Level 2",
enabled: management.elfTraining.heatedPlanterElfTraining.milestones[1].earned
})) }))
]); ]);
const computedOrePurity = computed(() => orePurity.apply(0.1)); const computedOrePurity = computed(() => orePurity.apply(0.1));
@ -108,6 +122,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: () => Decimal.add(plastic.activeRefinery.value, 1).sqrt(), multiplier: () => Decimal.add(plastic.activeRefinery.value, 1).sqrt(),
description: "De Louvre", description: "De Louvre",
enabled: dyes.upgrades.redDyeUpg2.bought enabled: dyes.upgrades.redDyeUpg2.bought
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.div(management.totalElfExp.value, 1000).add(1).sqrt(),
description: "Mary Level 5",
enabled: management.elfTraining.heatedPlanterElfTraining.milestones[4].earned
})) }))
]); ]);
const computedAutoSmeltSpeed = computed(() => autoSmeltSpeed.apply(0)); const computedAutoSmeltSpeed = computed(() => autoSmeltSpeed.apply(0));
@ -359,7 +378,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
.gte(10) .gte(10)
), ),
style: { width: "200px" } style: { width: "200px" }
})) as GenericBuyable; })) as GenericBuyable & { resource: Resource };
const industrialCrucible = createBuyable(() => ({ const industrialCrucible = createBuyable(() => ({
resource: noPersist(metal), resource: noPersist(metal),
cost() { cost() {
@ -382,7 +401,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
Decimal.gte(bestOre.value, 50) Decimal.gte(bestOre.value, 50)
), ),
style: { width: "200px" } style: { width: "200px" }
})) as GenericBuyable; })) as GenericBuyable & { resource: Resource };
const autoSmeltEnabled = persistent<boolean>(true); const autoSmeltEnabled = persistent<boolean>(true);
const hotterForge = createBuyable(() => ({ const hotterForge = createBuyable(() => ({
resource: coal.coal, resource: coal.coal,
@ -403,7 +422,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
visibility: () => visibility: () =>
showIf(Decimal.gte(hotterForge.amount.value, 1) || industrialFurnace.bought.value), showIf(Decimal.gte(hotterForge.amount.value, 1) || industrialFurnace.bought.value),
style: { width: "200px" } style: { width: "200px" }
})) as GenericBuyable; })) as GenericBuyable & { resource: Resource };
const hotterForgeEffect = computed(() => Decimal.times(hotterForge.amount.value, 0.25)); const hotterForgeEffect = computed(() => Decimal.times(hotterForge.amount.value, 0.25));
globalBus.on("update", diff => { globalBus.on("update", diff => {
@ -573,6 +592,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
)} )}
{renderRow(oreDrill, industrialCrucible, hotterForge)} {renderRow(oreDrill, industrialCrucible, hotterForge)}
</> </>
)),
minimizedDisplay: jsx(() => (
<div>
{name} - {format(metal.value)} {metal.displayName}
</div>
)) ))
}; };
}); });

View file

@ -35,6 +35,8 @@ import { formatGain } from "util/bignum";
import plastic from "./plastic"; import plastic from "./plastic";
import paper from "./paper"; import paper from "./paper";
import dyes from "./dyes"; import dyes from "./dyes";
import management from "./management";
import workshop from "./workshop";
const id = "oil"; const id = "oil";
const day = 9; const day = 9;
@ -247,8 +249,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
<br /> <br />
Pump that oil from the ground. Pump that oil from the ground.
<br /> <br />
Gain oil based on the number of Heavy buildings active and well Gain oil based on the number of Heavy buildings active and well depth, but coal
depth, but coal usage is multiplied by {row2Upgrades[3].bought.value ? 4 : 5}×. usage is multiplied by {row2Upgrades[3].bought.value ? 4 : 5}×.
<br /> <br />
<br /> <br />
Currently: Currently:
@ -718,6 +720,17 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: () => coalEffectiveness.value, multiplier: () => coalEffectiveness.value,
description: "Effectiveness", description: "Effectiveness",
enabled: () => Decimal.lt(coalEffectiveness.value, 1) enabled: () => Decimal.lt(coalEffectiveness.value, 1)
})),
createMultiplicativeModifier(() => ({
multiplier: () =>
Decimal.div(workshop.foundationProgress.value, 10).floor().div(10).add(1),
description: "600% Foundation Completed",
enabled: workshop.milestones.extraExpansionMilestone3.earned
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.sqrt(management.totalElfLevels.value),
description: "Jack Level 4",
enabled: management.elfTraining.heatedCutterElfTraining.milestones[3].earned
})) }))
]); ]);
const computedOilSpeed = computed(() => oilSpeed.apply(0)); const computedOilSpeed = computed(() => oilSpeed.apply(0));
@ -947,6 +960,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
<MainDisplay <MainDisplay
resource={oil} resource={oil}
color={color} color={color}
resourceStyle={{textShadow: 'grey 0px 0px 10px'}}
sticky={true} sticky={true}
productionDisplay={jsx(() => ( productionDisplay={jsx(() => (
<> <>
@ -1068,7 +1082,12 @@ const layer = createLayer(id, function (this: BaseLayer) {
{Decimal.gte(totalOil.value, 50) ? oilMilestonesDisplay() : ""} {Decimal.gte(totalOil.value, 50) ? oilMilestonesDisplay() : ""}
</> </>
); );
}) }),
minimizedDisplay: jsx(() => (
<div>
{name} - {format(oil.value)} {oil.displayName}
</div>
))
}; };
}); });

View file

@ -28,6 +28,7 @@ import plastic from "./plastic";
import trees from "./trees"; import trees from "./trees";
import dyes from "./dyes"; import dyes from "./dyes";
import management from "./management"; import management from "./management";
import workshop from "./workshop";
const id = "paper"; const id = "paper";
const day = 5; const day = 5;
@ -38,7 +39,12 @@ const layer = createLayer(id, function (this: BaseLayer) {
const paper = createResource<DecimalSource>(0, "paper"); const paper = createResource<DecimalSource>(0, "paper");
const pulp = createResource<DecimalSource>( const pulp = createResource<DecimalSource>(
computed(() => Decimal.min(Decimal.div(trees.logs.value, 1e9), Decimal.div(coal.ash.value, computedAshCost.value))), computed(() =>
Decimal.min(
Decimal.div(trees.logs.value, 1e9),
Decimal.div(coal.ash.value, computedAshCost.value)
)
),
"pulp" "pulp"
); );
@ -49,7 +55,10 @@ const layer = createLayer(id, function (this: BaseLayer) {
roundUpCost: true, roundUpCost: true,
spend(gain, cost) { spend(gain, cost) {
trees.logs.value = Decimal.sub(trees.logs.value, Decimal.times(cost, 1e9)); trees.logs.value = Decimal.sub(trees.logs.value, Decimal.times(cost, 1e9));
coal.ash.value = Decimal.sub(coal.ash.value, Decimal.times(cost, computedAshCost.value)); coal.ash.value = Decimal.sub(
coal.ash.value,
Decimal.times(cost, computedAshCost.value)
);
}, },
gainModifier: paperGain gainModifier: paperGain
})); }));
@ -68,7 +77,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
<span style="font-size: large"> <span style="font-size: large">
Cost: {displayResource(trees.logs, cost)} {pulp.displayName} ( Cost: {displayResource(trees.logs, cost)} {pulp.displayName} (
{formatWhole(Decimal.times(cost, 1e9))} {trees.logs.displayName};{" "} {formatWhole(Decimal.times(cost, 1e9))} {trees.logs.displayName};{" "}
{formatWhole(Decimal.times(cost, computedAshCost.value))} {coal.ash.displayName}) {formatWhole(Decimal.times(cost, computedAshCost.value))}{" "}
{coal.ash.displayName})
</span> </span>
</> </>
); );
@ -187,6 +197,34 @@ const layer = createLayer(id, function (this: BaseLayer) {
buyableName: "Cloth Buyables", buyableName: "Cloth Buyables",
visibility: () => showIf(elves.elves.clothElf.bought.value) visibility: () => showIf(elves.elves.clothElf.bought.value)
}); });
const miningDrillBook = createBook({
name: "Drills and Mills",
elfName: "Peppermint",
buyableName: "Mining Drill",
visibility: () =>
showIf(management.elfTraining.expandersElfTraining.milestones[3].earned.value)
});
const heavyDrillBook = createBook({
name: "Deep in the Earth",
elfName: "Frosty",
buyableName: "Oil Drills",
visibility: () =>
showIf(management.elfTraining.fertilizerElfTraining.milestones[4].earned.value)
});
const oilBook = createBook({
name: "Burning the Midnight Oil",
elfName: "Cocoa",
buyableName: "Oil-Consuming Machines",
visibility: () =>
showIf(management.elfTraining.heatedCutterElfTraining.milestones[4].earned.value)
});
const metalBook = createBook({
name: "Physical Metallurgy",
elfName: "Twinkle",
buyableName: "Metal Buyables",
visibility: () =>
showIf(management.elfTraining.expandersElfTraining.milestones[4].earned.value)
});
const books = { const books = {
cuttersBook, cuttersBook,
plantersBook, plantersBook,
@ -199,9 +237,15 @@ const layer = createLayer(id, function (this: BaseLayer) {
kilnBook, kilnBook,
paperBook, paperBook,
boxBook, boxBook,
clothBook clothBook,
miningDrillBook,
heavyDrillBook,
oilBook,
metalBook
}; };
const sumBooks = computed(() => Object.values(books).reduce((acc, curr) => acc.add(curr.amount.value), new Decimal(0))); const sumBooks = computed(() =>
Object.values(books).reduce((acc, curr) => acc.add(curr.amount.value), new Decimal(0))
);
const clothUpgrade = createUpgrade(() => ({ const clothUpgrade = createUpgrade(() => ({
resource: noPersist(paper), resource: noPersist(paper),
@ -257,11 +301,16 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: dyes.boosts.yellow1, multiplier: dyes.boosts.yellow1,
description: "Yellow Dye Boost 1", description: "Yellow Dye Boost 1",
enabled: () => Decimal.gte(dyes.dyes.yellow.amount.value, 1) enabled: () => Decimal.gte(dyes.dyes.yellow.amount.value, 1)
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "1000% Foundation Completed",
enabled: workshop.milestones.extraExpansionMilestone5.earned
})) }))
]) as WithRequired<Modifier, "description" | "revert">; ]) as WithRequired<Modifier, "description" | "revert">;
const ashCost = createSequentialModifier(() => [ const ashCost = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({ createMultiplicativeModifier(() => ({
multiplier: .1, multiplier: 0.1,
description: "Star Level 2", description: "Star Level 2",
enabled: management.elfTraining.paperElfTraining.milestones[1].earned enabled: management.elfTraining.paperElfTraining.milestones[1].earned
})) }))
@ -340,6 +389,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
<Spacer /> <Spacer />
{renderCol(...Object.values(books))} {renderCol(...Object.values(books))}
</> </>
)),
minimizedDisplay: jsx(() => (
<div>
{name} - {format(paper.value)} {paper.displayName}
</div>
)) ))
}; };
}); });

View file

@ -32,6 +32,8 @@ import boxes from "./boxes";
import metal from "./metal"; import metal from "./metal";
import oil from "./oil"; import oil from "./oil";
import dyes from "./dyes"; import dyes from "./dyes";
import management from "./management";
import workshop from "./workshop";
const id = "plastic"; const id = "plastic";
const day = 10; const day = 10;
@ -66,7 +68,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
resource: metal.metal, resource: metal.metal,
cost() { cost() {
const v = new Decimal(this.amount.value); const v = new Decimal(this.amount.value);
return Decimal.pow(1.2, v).times(1e7); let cost = Decimal.pow(1.2, v).times(1e7);
if (management.elfTraining.fertilizerElfTraining.milestones[3].earned.value) {
cost = Decimal.sub(cost, Decimal.pow(plastic.value, 2)).max(0);
}
return cost;
}, },
display: jsx(() => ( display: jsx(() => (
<> <>
@ -257,6 +263,12 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: dyes.boosts.yellow1, multiplier: dyes.boosts.yellow1,
description: "Yellow Dye Boost 1", description: "Yellow Dye Boost 1",
enabled: () => Decimal.gte(dyes.dyes.yellow.amount.value, 1) enabled: () => Decimal.gte(dyes.dyes.yellow.amount.value, 1)
})),
createMultiplicativeModifier(() => ({
multiplier: () =>
Decimal.div(workshop.foundationProgress.value, 10).floor().div(10).add(1),
description: "800% Foundation Completed",
enabled: workshop.milestones.extraExpansionMilestone4.earned
})) }))
]); ]);
const computedPlasticGain = computed(() => plasticGain.apply(0)); const computedPlasticGain = computed(() => plasticGain.apply(0));
@ -299,11 +311,16 @@ const layer = createLayer(id, function (this: BaseLayer) {
<> <>
{render(trackerDisplay)} {render(trackerDisplay)}
<Spacer /> <Spacer />
<MainDisplay resource={plastic} color={color} style="margin-bottom: 0" effectDisplay={ <MainDisplay
resource={plastic}
color={color}
style="margin-bottom: 0"
effectDisplay={
Decimal.gt(computedPlasticGain.value, 0) Decimal.gt(computedPlasticGain.value, 0)
? `+${format(computedPlasticGain.value)}/s` ? `+${format(computedPlasticGain.value)}/s`
: undefined : undefined
} /> }
/>
<Spacer /> <Spacer />
<Column> <Column>
{render(buildRefinery)} {render(buildRefinery)}
@ -319,6 +336,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
{renderCol(clothTools, clothElf, clothGains)} {renderCol(clothTools, clothElf, clothGains)}
</Row> </Row>
</> </>
)),
minimizedDisplay: jsx(() => (
<div>
{name} - {format(plastic.value)} {plastic.displayName}
</div>
)) ))
}; };
}); });

View file

@ -27,7 +27,7 @@ import { noPersist, persistent } from "game/persistence";
import Decimal, { DecimalSource, format, formatGain, formatLimit, formatWhole } from "util/bignum"; import Decimal, { DecimalSource, format, formatGain, formatLimit, formatWhole } from "util/bignum";
import { Direction, WithRequired } from "util/common"; import { Direction, WithRequired } from "util/common";
import { render, renderGrid, renderRow } from "util/vue"; import { render, renderGrid, renderRow } from "util/vue";
import { computed, ref } from "vue"; import { computed, ref, watch } from "vue";
import boxes from "./boxes"; import boxes from "./boxes";
import cloth from "./cloth"; import cloth from "./cloth";
import coal from "./coal"; import coal from "./coal";
@ -83,6 +83,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
addend: dyes.boosts.blue1, addend: dyes.boosts.blue1,
description: "Blue Dye Boost 1", description: "Blue Dye Boost 1",
enabled: () => Decimal.gte(dyes.dyes.blue.amount.value, 1) enabled: () => Decimal.gte(dyes.dyes.blue.amount.value, 1)
})),
createAdditiveModifier(() => ({
addend: () => Decimal.pow(computedManualCuttingAmount.value, 0.99),
description: "Hope Level 1",
enabled: management.elfTraining.expandersElfTraining.milestones[0].earned
})) }))
]) as WithRequired<Modifier, "description" | "revert">; ]) as WithRequired<Modifier, "description" | "revert">;
const trees = createResource( const trees = createResource(
@ -201,6 +206,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
if (Decimal.gte(v, 50)) v = Decimal.pow(v, 2).div(50); if (Decimal.gte(v, 50)) v = Decimal.pow(v, 2).div(50);
if (Decimal.gte(v, 200)) v = Decimal.pow(v, 2).div(200); if (Decimal.gte(v, 200)) v = Decimal.pow(v, 2).div(200);
if (Decimal.gte(v, 2e6)) v = Decimal.pow(v, 2).div(2e6); if (Decimal.gte(v, 2e6)) v = Decimal.pow(v, 2).div(2e6);
if (Decimal.gte(v, 2e30)) v = Decimal.pow(v,10000).div(Decimal.pow(2e30,9999));
v = Decimal.pow(0.95, paper.books.cuttersBook.amount.value).times(v); v = Decimal.pow(0.95, paper.books.cuttersBook.amount.value).times(v);
return Decimal.times(100, v).add(200); return Decimal.times(100, v).add(200);
}, },
@ -217,8 +223,13 @@ const layer = createLayer(id, function (this: BaseLayer) {
if (Decimal.gte(v, 50)) v = Decimal.pow(v, 2).div(50); if (Decimal.gte(v, 50)) v = Decimal.pow(v, 2).div(50);
if (Decimal.gte(v, 200)) v = Decimal.pow(v, 2).div(200); if (Decimal.gte(v, 200)) v = Decimal.pow(v, 2).div(200);
if (Decimal.gte(v, 2e6)) v = Decimal.pow(v, 2).div(2e6); if (Decimal.gte(v, 2e6)) v = Decimal.pow(v, 2).div(2e6);
if (Decimal.gte(v, 2e30)) v = Decimal.pow(v,10000).div(Decimal.pow(2e30,9999));
v = Decimal.pow(0.95, paper.books.plantersBook.amount.value).times(v); v = Decimal.pow(0.95, paper.books.plantersBook.amount.value).times(v);
return Decimal.times(100, v).add(200); let cost = Decimal.times(100, v).add(200);
if (management.elfTraining.planterElfTraining.milestones[3].earned.value) {
cost = Decimal.div(cost, 10);
}
return cost;
}, },
display: { display: {
title: "Generic Planters", title: "Generic Planters",
@ -232,6 +243,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
let v = this.amount.value; let v = this.amount.value;
if (Decimal.gte(v, 100)) v = Decimal.pow(v, 2).div(100); if (Decimal.gte(v, 100)) v = Decimal.pow(v, 2).div(100);
if (Decimal.gte(v, 1e5)) v = Decimal.pow(v, 2).div(1e5); if (Decimal.gte(v, 1e5)) v = Decimal.pow(v, 2).div(1e5);
if (Decimal.gte(v, 1e15)) v = Decimal.pow(v, 10).div(1e135);
v = Decimal.pow(0.95, paper.books.expandersBook.amount.value).times(v); v = Decimal.pow(0.95, paper.books.expandersBook.amount.value).times(v);
return Decimal.pow(Decimal.add(v, 1), 1.5).times(500); return Decimal.pow(Decimal.add(v, 1), 1.5).times(500);
}, },
@ -282,7 +294,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
enabled: researchUpgrade2.bought enabled: researchUpgrade2.bought
})), })),
createAdditiveModifier(() => ({ createAdditiveModifier(() => ({
addend: () => Decimal.div(workshop.foundationProgress.value, 5).floor(), addend: () =>
Decimal.div(workshop.foundationProgress.value, 5).floor(),
description: "10% Foundation Completed", description: "10% Foundation Completed",
enabled: workshop.milestones.autoCutMilestone1.earned enabled: workshop.milestones.autoCutMilestone1.earned
})), })),
@ -305,9 +318,28 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: 4, multiplier: 4,
description: "Lumberjack Jeans", description: "Lumberjack Jeans",
enabled: cloth.treesUpgrades.treesUpgrade2.bought enabled: cloth.treesUpgrades.treesUpgrade2.bought
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.pow(1.1, main.day.value),
description: "Holly Level 4",
enabled: management.elfTraining.cutterElfTraining.milestones[3].earned
})),
createAdditiveModifier(() => ({
addend: () =>
Decimal.sub(lastAutoCuttingAmount.value, lastAutoPlantedAmount.value).max(0),
description: "Ivy Level 5",
enabled: management.elfTraining.planterElfTraining.milestones[4].earned
})) }))
]) as WithRequired<Modifier, "description" | "revert">; ]) as WithRequired<Modifier, "description" | "revert">;
const computedAutoCuttingAmount = computed(() => autoCuttingAmount.apply(0)); const computedAutoCuttingAmount = computed(() => autoCuttingAmount.apply(0));
const lastAutoCuttingAmount = ref<DecimalSource>(0);
setInterval(
() =>
watch(computedAutoCuttingAmount, cut => {
lastAutoCuttingAmount.value = cut;
}),
0
);
const manualPlantingAmount = createSequentialModifier(() => [ const manualPlantingAmount = createSequentialModifier(() => [
createAdditiveModifier(() => ({ createAdditiveModifier(() => ({
@ -377,13 +409,32 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: "Ivy Level 1", description: "Ivy Level 1",
enabled: management.elfTraining.planterElfTraining.milestones[0].earned enabled: management.elfTraining.planterElfTraining.milestones[0].earned
})), })),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.pow(trees.value, 0.2).log10().pow_base(2),
description: "Ivy Level 3",
enabled: management.elfTraining.planterElfTraining.milestones[2].earned
})),
createMultiplicativeModifier(() => ({ createMultiplicativeModifier(() => ({
multiplier: 2, multiplier: 2,
description: "Mary Level 2", description: "Mary Level 4",
enabled: management.elfTraining.planterElfTraining.milestones[1].earned enabled: management.elfTraining.heatedPlanterElfTraining.milestones[3].earned
})),
createAdditiveModifier(() => ({
addend: () =>
Decimal.sub(lastAutoPlantedAmount.value, lastAutoCuttingAmount.value).max(0),
description: "Ivy Level 5",
enabled: management.elfTraining.planterElfTraining.milestones[4].earned
})) }))
]) as WithRequired<Modifier, "description" | "revert">; ]) as WithRequired<Modifier, "description" | "revert">;
const computedAutoPlantingAmount = computed(() => autoPlantingAmount.apply(0)); const computedAutoPlantingAmount = computed(() => autoPlantingAmount.apply(0));
const lastAutoPlantedAmount = ref<DecimalSource>(0);
setInterval(
() =>
watch(computedAutoPlantingAmount, planted => {
lastAutoPlantedAmount.value = planted;
}),
0
);
const logGain = createSequentialModifier(() => [ const logGain = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({ createMultiplicativeModifier(() => ({
@ -397,7 +448,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
enabled: researchUpgrade2.bought enabled: researchUpgrade2.bought
})), })),
createMultiplicativeModifier(() => ({ createMultiplicativeModifier(() => ({
multiplier: () => Decimal.div(workshop.foundationProgress.value, 20).add(1), multiplier: () => workshop.milestones.extraExpansionMilestone1.earned.value
? Decimal.pow(1.02, workshop.foundationProgress.value) : Decimal.div(workshop.foundationProgress.value, 20).add(1),
description: "1% Foundation Completed", description: "1% Foundation Completed",
enabled: workshop.milestones.logGainMilestone1.earned enabled: workshop.milestones.logGainMilestone1.earned
})), })),
@ -444,9 +496,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
enabled: dyes.upgrades.blueDyeUpg.bought enabled: dyes.upgrades.blueDyeUpg.bought
})), })),
createMultiplicativeModifier(() => ({ createMultiplicativeModifier(() => ({
multiplier: computed(() => multiplier: computed(() => Decimal.add(computedAutoCuttingAmount.value, 1).root(9)),
Decimal.add(computedAutoCuttingAmount.value, 1).log10().plus(1)
),
description: "Holly Level 1", description: "Holly Level 1",
enabled: management.elfTraining.cutterElfTraining.milestones[0].earned enabled: management.elfTraining.cutterElfTraining.milestones[0].earned
})), })),
@ -770,6 +820,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
<Spacer /> <Spacer />
{renderRow(...row1Buyables)} {renderRow(...row1Buyables)}
</> </>
)),
minimizedDisplay: jsx(() => (
<div>
{name} - {format(logs.value)} {logs.displayName}
</div>
)) ))
}; };
}); });

View file

@ -8,33 +8,24 @@ import { main } from "data/projEntry";
import { createBar } from "features/bars/bar"; import { createBar } from "features/bars/bar";
import { createClickable } from "features/clickables/clickable"; import { createClickable } from "features/clickables/clickable";
import { import {
Conversion, addSoftcap,
createIndependentConversion, createIndependentConversion,
createPolynomialScaling, createPolynomialScaling
ScalingFunction
} from "features/conversion"; } from "features/conversion";
import { jsx, showIf } from "features/feature"; import { jsx, showIf } from "features/feature";
import { createHotkey } from "features/hotkey"; import { createHotkey } from "features/hotkey";
import { createMilestone } from "features/milestones/milestone"; import { createMilestone } from "features/milestones/milestone";
import { createResource, displayResource, Resource } from "features/resources/resource"; import { createResource, displayResource } from "features/resources/resource";
import { BaseLayer, createLayer } from "game/layers"; import { BaseLayer, createLayer } from "game/layers";
import { createExponentialModifier, createSequentialModifier } from "game/modifiers";
import { noPersist } from "game/persistence"; import { noPersist } from "game/persistence";
import Decimal, { DecimalSource, formatWhole } from "util/bignum"; import Decimal, { DecimalSource, format, formatWhole } from "util/bignum";
import { Direction } from "util/common"; import { Direction } from "util/common";
import { render } from "util/vue"; import { render } from "util/vue";
import { computed, unref, watchEffect } from "vue"; import { computed, unref, watchEffect } from "vue";
import elves from "./elves"; import elves from "./elves";
import trees from "./trees";
import management from "./management"; import management from "./management";
import trees from "./trees";
interface FoundationConversionOptions {
scaling: ScalingFunction;
baseResource: Resource;
gainResource: Resource;
roundUpCost: boolean;
buyMax: boolean;
spend: (gain: DecimalSource, spent: DecimalSource) => void;
}
const id = "workshop"; const id = "workshop";
const day = 2; const day = 2;
@ -45,22 +36,34 @@ const layer = createLayer(id, function (this: BaseLayer) {
const foundationProgress = createResource<DecimalSource>(0, "foundation progress"); const foundationProgress = createResource<DecimalSource>(0, "foundation progress");
const foundationConversion: Conversion<FoundationConversionOptions> = const foundationConversion = createIndependentConversion(() => ({
createIndependentConversion(() => ({ scaling: addSoftcap(
scaling: createPolynomialScaling(250, 1.5), addSoftcap(createPolynomialScaling(250, 1.5), 5387, 1 / 1e10),
baseResource: trees.logs, 1e20,
gainResource: noPersist(foundationProgress), 3e8
roundUpCost: true, ),
buyMax: false, baseResource: trees.logs,
spend(gain, spent) { gainResource: noPersist(foundationProgress),
trees.logs.value = Decimal.sub(trees.logs.value, spent); roundUpCost: true,
} // buyMax: management.elfTraining.expandersElfTraining.milestones[2].earned,
})); spend(gain, spent) {
trees.logs.value = Decimal.sub(trees.logs.value, spent);
},
costModifier: createSequentialModifier(() => [
createExponentialModifier(() => ({
exponent: 0.95,
description: "Holly Level 5",
enabled: management.elfTraining.cutterElfTraining.milestones[4].earned
}))
])
}));
const buildFoundation = createClickable(() => ({ const buildFoundation = createClickable(() => ({
display: jsx(() => ( display: jsx(() => (
<> <>
<b style="font-size: x-large">Build part of the foundation</b> <b style="font-size: x-large">
Build {formatWhole(foundationConversion.actualGain.value)}% of the foundation
</b>
<br /> <br />
<br /> <br />
<span style="font-size: large"> <span style="font-size: large">
@ -75,10 +78,15 @@ const layer = createLayer(id, function (this: BaseLayer) {
</span> </span>
</> </>
)), )),
visibility: () => showIf(Decimal.lt(foundationProgress.value, 100)), visibility: () =>
showIf(
Decimal.lt(foundationProgress.value, 100) ||
management.elfTraining.expandersElfTraining.milestones[2].earned.value
),
canClick: () => canClick: () =>
Decimal.gte(foundationConversion.actualGain.value, 1) && Decimal.gte(trees.logs.value, foundationConversion.currentAt.value) &&
Decimal.lt(foundationProgress.value, 100), (Decimal.lt(foundationProgress.value, 100) ||
management.elfTraining.expandersElfTraining.milestones[2].earned.value),
onClick() { onClick() {
if (!unref(this.canClick)) { if (!unref(this.canClick)) {
return; return;
@ -171,52 +179,67 @@ const layer = createLayer(id, function (this: BaseLayer) {
})); }));
const extraExpansionMilestone1 = createMilestone(() => ({ const extraExpansionMilestone1 = createMilestone(() => ({
display: { display: {
requirement: "120% Foundation Completed", requirement: "200% Foundation Completed",
effectDisplay: "The 1% milestone is now +2% and multiplicative" effectDisplay: "The 1% milestone is now +2% and multiplicative"
}, },
shouldEarn: () => Decimal.gte(foundationProgress.value, 120), shouldEarn: () => Decimal.gte(foundationProgress.value, 200),
visibility: () => visibility: () =>
showIf(management.elfTraining.expandersElfTraining.milestones[2].earned.value), showIf(
logGainMilestone3.earned.value &&
management.elfTraining.expandersElfTraining.milestones[2].earned.value
),
showPopups: shouldShowPopups showPopups: shouldShowPopups
})); }));
const extraExpansionMilestone2 = createMilestone(() => ({ const extraExpansionMilestone2 = createMilestone(() => ({
display: { display: {
requirement: "140% Foundation Completed", requirement: "400% Foundation Completed",
effectDisplay: "Gain +10% metal for every 10% foundation completed" effectDisplay: "Gain +10% metal for every 10% foundation completed"
}, },
shouldEarn: () => Decimal.gte(foundationProgress.value, 140), shouldEarn: () => Decimal.gte(foundationProgress.value, 400),
visibility: () => visibility: () =>
showIf(management.elfTraining.expandersElfTraining.milestones[2].earned.value), showIf(
extraExpansionMilestone1.earned.value &&
management.elfTraining.expandersElfTraining.milestones[2].earned.value
),
showPopups: shouldShowPopups showPopups: shouldShowPopups
})); }));
const extraExpansionMilestone3 = createMilestone(() => ({ const extraExpansionMilestone3 = createMilestone(() => ({
display: { display: {
requirement: "160% Foundation Completed", requirement: "600% Foundation Completed",
effectDisplay: "Gain +10% oil for every 10% foundation completed" effectDisplay: "Gain +10% oil for every 10% foundation completed"
}, },
shouldEarn: () => Decimal.gte(foundationProgress.value, 160), shouldEarn: () => Decimal.gte(foundationProgress.value, 600),
visibility: () => visibility: () =>
showIf(management.elfTraining.expandersElfTraining.milestones[2].earned.value), showIf(
extraExpansionMilestone2.earned.value &&
management.elfTraining.expandersElfTraining.milestones[2].earned.value
),
showPopups: shouldShowPopups showPopups: shouldShowPopups
})); }));
const extraExpansionMilestone4 = createMilestone(() => ({ const extraExpansionMilestone4 = createMilestone(() => ({
display: { display: {
requirement: "180% Foundation Completed", requirement: "800% Foundation Completed",
effectDisplay: "Gain +10% plastic for every 10% foundation completed" effectDisplay: "Gain +10% plastic for every 10% foundation completed"
}, },
shouldEarn: () => Decimal.gte(foundationProgress.value, 180), shouldEarn: () => Decimal.gte(foundationProgress.value, 800),
visibility: () => visibility: () =>
showIf(management.elfTraining.expandersElfTraining.milestones[2].earned.value), showIf(
extraExpansionMilestone3.earned.value &&
management.elfTraining.expandersElfTraining.milestones[2].earned.value
),
showPopups: shouldShowPopups showPopups: shouldShowPopups
})); }));
const extraExpansionMilestone5 = createMilestone(() => ({ const extraExpansionMilestone5 = createMilestone(() => ({
display: { display: {
requirement: "200% Foundation Completed", requirement: "1000% Foundation Completed",
effectDisplay: "Double paper, boxes, and all cloth actions" effectDisplay: "Double paper, boxes, and all cloth actions"
}, },
shouldEarn: () => Decimal.gte(foundationProgress.value, 200), shouldEarn: () => Decimal.gte(foundationProgress.value, 1000),
visibility: () => visibility: () =>
showIf(management.elfTraining.expandersElfTraining.milestones[2].earned.value), showIf(
extraExpansionMilestone4.earned.value &&
management.elfTraining.expandersElfTraining.milestones[2].earned.value
),
showPopups: shouldShowPopups showPopups: shouldShowPopups
})); }));
const milestones = { const milestones = {
@ -280,11 +303,19 @@ const layer = createLayer(id, function (this: BaseLayer) {
</h2> </h2>
% completed % completed
</div> </div>
{Decimal.lt(foundationProgress.value, 100) ? <Spacer /> : null} {Decimal.lt(foundationProgress.value, 100) ||
management.elfTraining.expandersElfTraining.milestones[2].earned.value ? (
<Spacer />
) : null}
{render(buildFoundation)} {render(buildFoundation)}
<Spacer /> <Spacer />
{milestonesDisplay()} {milestonesDisplay()}
</> </>
)),
minimizedDisplay: jsx(() => (
<div>
{name} - {format(foundationProgress.value)} {foundationProgress.displayName}
</div>
)) ))
}; };
}); });

View file

@ -148,7 +148,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
loreScene.value = -1; loreScene.value = -1;
loreTitle.value = unref(layers[layer ?? "trees"]?.name ?? ""); loreTitle.value = unref(layers[layer ?? "trees"]?.name ?? "");
loreBody.value = story; loreBody.value = story;
player.devSpeed = null; if (player.autoPause) player.devSpeed = null;
showLoreModal.value = true; showLoreModal.value = true;
}, 1000); }, 1000);
} }
@ -262,23 +262,25 @@ export const main = createLayer("main", function (this: BaseLayer) {
createDay(() => ({ createDay(() => ({
day: 12, day: 12,
shouldNotify: false, shouldNotify: false,
layer: null, layer: "management",
symbol: managementSymbol, symbol: managementSymbol,
story: "You watch as the elves work, and you realize that they could probably be trained to help out better. Just then, Santa comes over to check on your progress. You reply that you're doing fine, except that the elves may need a bit of behavior management. Santa offers to help, saying that he doesn't want to leave you to do everything. Unfortunately for you, the behavior problems won't fix themselves, so let's get to work!", story: "You watch as the elves work, and you realize that they could probably be trained to help out better. Just then, Santa comes over to check on your progress. You reply that you're doing fine, except that the elves may need a bit of behavior management. Santa offers to help, saying that he doesn't want to leave you to do everything. Unfortunately for you, the behavior problems won't fix themselves, so let's get to work!",
completedStory: "" completedStory:
"Woo! You are exhausted - this layer felt really long to you. It's great seeing the elves so productive, although you worry a bit about your own job security now! Good Job!"
})), })),
createDay(() => ({ createDay(() => ({
day: 13, day: 13,
shouldNotify: false, shouldNotify: false,
layer: null, // "" layer: null, // "management" (advanced)
symbol: "", symbol: "",
story: "", story: "So after a good night's rest you decide that maybe making these elves able to do all the work for you isn't something to be scared of, but rather encouraged. Let's spend another day continuing to train them up and really get this place spinning. They are Santa's elves after all, they're supposed to be able to run everything without you!",
completedStory: "" completedStory:
"The elves are doing an incredible job, and Santa does not seem keen on firing you - Score! Now you can get to work on guiding this properly trained highly functional group of hard workers to make Christmas as great as possible. Good Job!"
})), })),
createDay(() => ({ createDay(() => ({
day: 14, day: 14,
shouldNotify: false, shouldNotify: false,
layer: null, // "" layer: null, // "letters to santa"
symbol: "", symbol: "",
story: "", story: "",
completedStory: "" completedStory: ""
@ -372,7 +374,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
showLoreModal.value = true; showLoreModal.value = true;
day.value++; day.value++;
main.minimized.value = false; main.minimized.value = false;
player.devSpeed = 0; if (player.autoPause) player.devSpeed = 0;
} }
return { return {
@ -436,6 +438,7 @@ export const getInitialLayers = (
plastic, plastic,
dyes, dyes,
wrappingPaper, wrappingPaper,
management
]; ];
/** /**
@ -459,7 +462,7 @@ export function fixOldSave(
if (!["0.0", "0.1", "0.2", "0.3", "0.4"].includes(oldVersion ?? "")) { if (!["0.0", "0.1", "0.2", "0.3", "0.4"].includes(oldVersion ?? "")) {
return; return;
} }
player.offlineProd = false; /*player.offlineProd = false;
delete player.layers?.management; delete player.layers?.management;
if ((player.layers?.main as LayerData<typeof main> | undefined)?.days?.[11]) { if ((player.layers?.main as LayerData<typeof main> | undefined)?.days?.[11]) {
(player.layers!.main as LayerData<typeof main>).days![11].opened = false; (player.layers!.main as LayerData<typeof main>).days![11].opened = false;
@ -470,6 +473,6 @@ export function fixOldSave(
} }
if (player.tabs) { if (player.tabs) {
player.tabs = player.tabs.filter(l => l !== "management"); player.tabs = player.tabs.filter(l => l !== "management");
} }*/
} }
/* eslint-enable @typescript-eslint/no-unused-vars */ /* eslint-enable @typescript-eslint/no-unused-vars */

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -299,7 +299,12 @@ globalBus.on("loadSettings", settings => {
registerSettingField( registerSettingField(
jsx(() => ( jsx(() => (
<Toggle <Toggle
title="Hide Maxed Challenges" title={jsx(() => (
<span class="option-title">
Hide maxed challenges
<desc>Hide challenges that have been fully completed.</desc>
</span>
))}
onUpdate:modelValue={value => (settings.hideChallenges = value)} onUpdate:modelValue={value => (settings.hideChallenges = value)}
modelValue={settings.hideChallenges} modelValue={settings.hideChallenges}
/> />

View file

@ -511,6 +511,8 @@ export function addSoftcap(
): ScalingFunction { ): ScalingFunction {
return { return {
...scaling, ...scaling,
currentAt: conversion => softcap(scaling.currentAt(conversion), unref(cap), Decimal.recip(unref(power))),
nextAt: conversion => softcap(scaling.nextAt(conversion), unref(cap), Decimal.recip(unref(power))),
currentGain: conversion => currentGain: conversion =>
softcap(scaling.currentGain(conversion), unref(cap), unref(power)) softcap(scaling.currentGain(conversion), unref(cap), unref(power))
}; };

View file

@ -204,7 +204,12 @@ const msDisplayOptions = Object.values(MilestoneDisplay).map(option => ({
registerSettingField( registerSettingField(
jsx(() => ( jsx(() => (
<Select <Select
title="Show Milestones" title={jsx(() => (
<span class="option-title">
Show milestones
<desc>Select which milestones to display based on criterias.</desc>
</span>
))}
options={msDisplayOptions} options={msDisplayOptions}
onUpdate:modelValue={value => (settings.msDisplay = value as MilestoneDisplay)} onUpdate:modelValue={value => (settings.msDisplay = value as MilestoneDisplay)}
modelValue={settings.msDisplay} modelValue={settings.msDisplay}

View file

@ -7,7 +7,7 @@
> >
<div class="main-display"> <div class="main-display">
<span v-if="showPrefix">You have </span> <span v-if="showPrefix">You have </span>
<ResourceVue :resource="resource" :color="color || 'white'" /> <ResourceVue :resource="resource" :color="color || 'white'" :style="resourceStyle" />
{{ resource.displayName {{ resource.displayName
}}<!-- remove whitespace --> }}<!-- remove whitespace -->
<span v-if="effectComponent" <span v-if="effectComponent"
@ -27,7 +27,7 @@
> >
<div class="main-display"> <div class="main-display">
<span v-if="showPrefix">You have </span> <span v-if="showPrefix">You have </span>
<ResourceVue :resource="resource" :color="color || 'white'" /> <ResourceVue :resource="resource" :color="color || 'white'" :style="resourceStyle" />
{{ resource.displayName {{ resource.displayName
}}<!-- remove whitespace --> }}<!-- remove whitespace -->
<span v-if="effectComponent" <span v-if="effectComponent"
@ -56,6 +56,7 @@ const _props = withDefaults(defineProps<{
color?: string; color?: string;
classes?: Record<string, boolean>; classes?: Record<string, boolean>;
style?: StyleValue; style?: StyleValue;
resourceStyle?: StyleValue;
effectDisplay?: CoercableComponent; effectDisplay?: CoercableComponent;
productionDisplay?: CoercableComponent; productionDisplay?: CoercableComponent;
sticky?: boolean sticky?: boolean

View file

@ -1,5 +1,5 @@
<template> <template>
<h2 :style="{ color, 'text-shadow': '0px 0px 10px ' + color }"> <h2 :style="[{ color, 'text-shadow': '0px 0px 10px ' + color }, style ?? {}]">
{{ amount }} {{ amount }}
</h2> </h2>
</template> </template>
@ -7,11 +7,12 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Resource } from "features/resources/resource"; import type { Resource } from "features/resources/resource";
import { displayResource } from "features/resources/resource"; import { displayResource } from "features/resources/resource";
import { computed } from "vue"; import { computed, StyleValue } from "vue";
const props = defineProps<{ const props = defineProps<{
resource: Resource; resource: Resource;
color: string; color: string;
style?: StyleValue;
}>(); }>();
const amount = computed(() => displayResource(props.resource)); const amount = computed(() => displayResource(props.resource));

View file

@ -109,7 +109,7 @@ export interface LayerOptions {
color?: Computable<string>; color?: Computable<string>;
/** /**
* The layout of this layer's features. * The layout of this layer's features.
* When the layer is open in {@link game/player.PlayerData.tabs}, this is the content that is display. * When the layer is open in {@link game/player.PlayerData.tabs}, this is the content that is displayed.
*/ */
display: Computable<CoercableComponent>; display: Computable<CoercableComponent>;
/** An object of classes that should be applied to the display. */ /** An object of classes that should be applied to the display. */
@ -126,6 +126,11 @@ export interface LayerOptions {
* Defaults to true. * Defaults to true.
*/ */
minimizable?: Computable<boolean>; minimizable?: Computable<boolean>;
/**
* The layout of this layer's features.
* When the layer is open in {@link game/player.PlayerData.tabs}, but the tab is {@link Layer.minimized} this is the content that is displayed.
*/
minimizedDisplay?: Computable<CoercableComponent>;
/** /**
* Whether or not to force the go back button to be hidden. * Whether or not to force the go back button to be hidden.
* If true, go back will be hidden regardless of {@link data/projInfo.allowGoBack}. * If true, go back will be hidden regardless of {@link data/projInfo.allowGoBack}.
@ -170,6 +175,7 @@ export type Layer<T extends LayerOptions> = Replace<
name: GetComputableTypeWithDefault<T["name"], string>; name: GetComputableTypeWithDefault<T["name"], string>;
minWidth: GetComputableTypeWithDefault<T["minWidth"], 600>; minWidth: GetComputableTypeWithDefault<T["minWidth"], 600>;
minimizable: GetComputableTypeWithDefault<T["minimizable"], true>; minimizable: GetComputableTypeWithDefault<T["minimizable"], true>;
minimizedDisplay: GetComputableType<T["minimizedDisplay"]>;
forceHideGoBack: GetComputableType<T["forceHideGoBack"]>; forceHideGoBack: GetComputableType<T["forceHideGoBack"]>;
} }
>; >;
@ -231,6 +237,7 @@ export function createLayer<T extends LayerOptions>(
setDefault(layer, "minWidth", 600); setDefault(layer, "minWidth", 600);
processComputable(layer as T, "minimizable"); processComputable(layer as T, "minimizable");
setDefault(layer, "minimizable", true); setDefault(layer, "minimizable", true);
processComputable(layer as T, "minimizedDisplay");
return layer as unknown as Layer<T>; return layer as unknown as Layer<T>;
}); });

View file

@ -1,6 +1,7 @@
import "components/common/modifiers.css"; import "components/common/modifiers.css";
import type { CoercableComponent } from "features/feature"; import type { CoercableComponent } from "features/feature";
import { jsx } from "features/feature"; import { jsx } from "features/feature";
import settings from "game/settings";
import type { DecimalSource } from "util/bignum"; import type { DecimalSource } from "util/bignum";
import Decimal, { format } from "util/bignum"; import Decimal, { format } from "util/bignum";
import type { WithRequired } from "util/common"; import type { WithRequired } from "util/common";
@ -9,6 +10,7 @@ import { convertComputable } from "util/computed";
import { createLazyProxy } from "util/proxies"; import { createLazyProxy } from "util/proxies";
import { renderJSX } from "util/vue"; import { renderJSX } from "util/vue";
import { computed, unref } from "vue"; import { computed, unref } from "vue";
import player from "./player";
/** /**
* An object that can be used to apply or unapply some modification to a number. * An object that can be used to apply or unapply some modification to a number.
@ -272,7 +274,7 @@ export function createModifierSection(
baseText: CoercableComponent = "Base" baseText: CoercableComponent = "Base"
) { ) {
return ( return (
<div> <div style={{"--unit": settings.alignUnits ? "'" + unit + "'" : ""}}>
<h3> <h3>
{title} {title}
{subtitle ? <span class="subtitle"> ({subtitle})</span> : null} {subtitle ? <span class="subtitle"> ({subtitle})</span> : null}

View file

@ -34,8 +34,9 @@ export interface PlayerData {
modVersion: string; modVersion: string;
/** A dictionary of layer save data. */ /** A dictionary of layer save data. */
layers: Record<string, LayerData<unknown>>; layers: Record<string, LayerData<unknown>>;
/** Whether to use log for progress toward finishing the day, or use linear. */
usingLog: boolean; /** Should the game be paused when the player complete a day? */
autoPause: boolean;
} }
/** The proxied player that is used to track NaN values. */ /** The proxied player that is used to track NaN values. */
@ -68,7 +69,8 @@ const state = reactive<PlayerData>({
modID: "", modID: "",
modVersion: "", modVersion: "",
layers: {}, layers: {},
usingLog: false
autoPause: true,
}); });
/** Convert a player save data object into a JSON string. Unwraps refs. */ /** Convert a player save data object into a JSON string. Unwraps refs. */

View file

@ -18,6 +18,13 @@ export interface Settings {
theme: Themes; theme: Themes;
/** Whether or not to cap the project at 20 ticks per second. */ /** Whether or not to cap the project at 20 ticks per second. */
unthrottled: boolean; unthrottled: boolean;
/** Game-specific settings */
/** Whether to use log for progress toward finishing the day, or use linear. */
usingLog: boolean;
/** Whether to align modifiers to the unit. */
alignUnits: boolean;
} }
const state = reactive<Partial<Settings>>({ const state = reactive<Partial<Settings>>({
@ -25,7 +32,10 @@ const state = reactive<Partial<Settings>>({
saves: [], saves: [],
showTPS: true, showTPS: true,
theme: Themes.Nordic, theme: Themes.Nordic,
unthrottled: false unthrottled: false,
usingLog: false,
alignUnits: false,
}); });
watch( watch(
@ -57,7 +67,10 @@ export const hardResetSettings = (window.hardResetSettings = () => {
active: "", active: "",
saves: [], saves: [],
showTPS: true, showTPS: true,
theme: Themes.Nordic theme: Themes.Nordic,
usingLog: false,
alignUnits: false,
}; };
globalBus.emit("loadSettings", settings); globalBus.emit("loadSettings", settings);
Object.assign(state, settings); Object.assign(state, settings);

View file

@ -66,3 +66,74 @@ ul {
.Vue-Toastification__toast { .Vue-Toastification__toast {
margin: unset; margin: unset;
} }
/* Scrollbar stuff */
* {
scrollbar-color: #ffffff0f var(--accent1);
}
::-webkit-scrollbar {
appearance: none;
width: 16px;
height: 16px;
background-color: #ffffff0f;
}
::-webkit-scrollbar-thumb {
--back-color: var(--accent1);
background: linear-gradient(90deg, var(--back-color), var(--back-color)) no-repeat content-box;
border: 2px solid transparent;
}
::-webkit-scrollbar-thumb:hover {
--back-color: var(--foreground);
}
::-webkit-scrollbar-button:single-button {
--back-color: transparent;
--arrow-color: var(--accent1);
width: 16px;
height: 16px;
}
::-webkit-scrollbar-button:single-button:hover {
--back-color: #ffffff0f;
--arrow-color: var(--foreground);
}
::-webkit-scrollbar-button:single-button:active {
--back-color: var(--foreground);
--arrow-color: var(--background);
}
::-webkit-scrollbar-button:single-button:disabled {
--arrow-color: var(--foreground);
}
::-webkit-scrollbar-button:single-button:vertical:decrement {
background:
conic-gradient(#0000 37.5%, var(--arrow-color) 37.5% 62.5%, #0000 62.5%) no-repeat content-box,
linear-gradient(90deg, var(--back-color), var(--back-color)) no-repeat content-box;
background-size: 60% 50%, 100% 100%;
background-position: 50% 20%, 0% 0%;
}
::-webkit-scrollbar-button:single-button:vertical:increment {
background:
conic-gradient(var(--arrow-color) 12.5%, #0000 12.5% 87.5%, var(--arrow-color) 87.5%) no-repeat content-box,
linear-gradient(90deg, var(--back-color), var(--back-color)) no-repeat content-box;
background-size: 60% 50%, 100% 100%;
background-position: 50% 80%, 0% 0%;
}
::-webkit-scrollbar-button:single-button:horizontal:decrement {
background:
conic-gradient(#0000 12.5%, var(--arrow-color) 12.5% 37.5%, #0000 37.5%) no-repeat content-box,
linear-gradient(90deg, var(--back-color), var(--back-color)) no-repeat content-box;
background-size: 50% 60%, 100% 100%;
background-position: 20% 50%, 0% 0%;
}
::-webkit-scrollbar-button:single-button:horizontal:increment {
background:
conic-gradient(#0000 62.5%, var(--arrow-color) 62.5% 87.5%, #0000 87.5%) no-repeat content-box,
linear-gradient(90deg, var(--back-color), var(--back-color)) no-repeat content-box;
background-size: 50% 60%, 100% 100%;
background-position: 80% 50%, 0% 0%;
}
::-webkit-scrollbar-corner {
background: #070710;
}

View file

@ -25,6 +25,11 @@ export default defineConfig({
vue: "vue/dist/vue.esm-bundler.js" vue: "vue/dist/vue.esm-bundler.js"
} }
}, },
server: {
hmr: {
clientPort: process.env.CODESPACES ? 443 : undefined
}
},
plugins: [ plugins: [
vue(), vue(),
vueJsx({ vueJsx({