This commit is contained in:
Seth Posner 2022-12-05 10:27:42 -08:00
commit 65622c84c7
13 changed files with 132 additions and 7428 deletions

7406
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -32,7 +32,7 @@
<Scene :day="main.loreScene.value" /> <Scene :day="main.loreScene.value" />
<br /> <br />
You can help continue the <i>advent</i>ure at: You can help continue the <i>advent</i>ure at:
<a href="https://discord.gg/WzejVAx" class="info-modal-discord-link"> <a href="https://discord.gg/WzejVAx" class="info-modal-discord-link" target="_blank">
<span class="material-icons info-modal-discord">discord</span> <span class="material-icons info-modal-discord">discord</span>
The Paper Pilot Community The Paper Pilot Community
</a> </a>

View file

@ -21,19 +21,32 @@
<div class="link" @click="openChangelog">Changelog</div> <div class="link" @click="openChangelog">Changelog</div>
<br /> <br />
<div> <div>
<a :href="discordLink" v-if="discordLink" class="info-modal-discord-link"> <a
:href="discordLink"
v-if="discordLink"
class="info-modal-discord-link"
target="_blank"
>
<span class="material-icons info-modal-discord">discord</span> <span class="material-icons info-modal-discord">discord</span>
{{ discordName }} {{ discordName }}
</a> </a>
</div> </div>
<div> <div>
<a href="https://discord.gg/WzejVAx" class="info-modal-discord-link"> <a
href="https://discord.gg/WzejVAx"
class="info-modal-discord-link"
target="_blank"
>
<span class="material-icons info-modal-discord">discord</span> <span class="material-icons info-modal-discord">discord</span>
The Paper Pilot Community The Paper Pilot Community
</a> </a>
</div> </div>
<div> <div>
<a href="https://discord.gg/F3xveHV" class="info-modal-discord-link"> <a
href="https://discord.gg/F3xveHV"
class="info-modal-discord-link"
target="_blank"
>
<span class="material-icons info-modal-discord">discord</span> <span class="material-icons info-modal-discord">discord</span>
The Modding Tree The Modding Tree
</a> </a>

View file

@ -35,6 +35,7 @@ const props = defineProps<{
day: number; day: number;
symbol: string; symbol: string;
opened: Ref<boolean>; opened: Ref<boolean>;
recentlyUpdated: Ref<boolean>;
shouldNotify: ProcessedComputable<boolean>; shouldNotify: ProcessedComputable<boolean>;
}>(); }>();

View file

@ -74,6 +74,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Carry logs in boxes", title: "Carry logs in boxes",
description: "Double log gain and unlock a new elf for training" description: "Double log gain and unlock a new elf for training"
}, },
onPurchase () {
main.days[3].recentlyUpdated.value = true;
},
resource: boxes, resource: boxes,
cost: 100 cost: 100
})); }));
@ -82,6 +85,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Carry ash in boxes", title: "Carry ash in boxes",
description: "Double ash gain and unlock a new elf for training" description: "Double ash gain and unlock a new elf for training"
}, },
onPurchase () {
main.days[3].recentlyUpdated.value = true;
},
resource: boxes, resource: boxes,
cost: 1000 cost: 1000
})); }));
@ -90,6 +96,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
title: "Carry coal in boxes", title: "Carry coal in boxes",
description: "Double coal gain and unlock a new elf for training" description: "Double coal gain and unlock a new elf for training"
}, },
onPurchase () {
main.days[3].recentlyUpdated.value = true;
},
resource: boxes, resource: boxes,
cost: 4000 cost: 4000
})); }));

View file

@ -92,7 +92,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
const buildFire = createBuyable(() => ({ const buildFire = createBuyable(() => ({
resource: trees.logs, resource: trees.logs,
cost() { cost() {
let v = Decimal.times(buildBonfire.amount.value, unref(buildBonfire.cost!)).plus(this.amount.value); let v = Decimal.times(buildBonfire.amount.value, unref(buildBonfire.cost!)).plus(
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, 10000)) v = Decimal.pow(v, 2).div(10000); if (Decimal.gte(v, 10000)) v = Decimal.pow(v, 2).div(10000);
v = Decimal.pow(0.95, paper.books.smallFireBook.amount.value).times(v); v = Decimal.pow(0.95, paper.books.smallFireBook.amount.value).times(v);
@ -586,7 +588,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
createExponentialModifier(() => ({ createExponentialModifier(() => ({
exponent: 1.25, exponent: 1.25,
description: "3 Elves Trained", description: "3 Elves Trained",
enabled: elves.milestones[2].earned enabled: elves.milestones[2].earned,
supportLowNumbers: true
})) }))
]); ]);
const computedCoalGain = computed(() => coalGain.apply(0)); const computedCoalGain = computed(() => coalGain.apply(0));

View file

@ -286,6 +286,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
hasToggle?: boolean; hasToggle?: boolean;
toggleDesc?: string; toggleDesc?: string;
onAutoPurchase?: VoidFunction; onAutoPurchase?: VoidFunction;
onPurchase?: VoidFunction; // Will get overriden by the custom onpurchase, but that's fine
} & Partial<ClickableOptions> } & Partial<ClickableOptions>
) { ) {
const trainingCost = computed(() => Decimal.pow(4, totalElves.value).times(1e6)); const trainingCost = computed(() => Decimal.pow(4, totalElves.value).times(1e6));
@ -353,7 +354,10 @@ const layer = createLayer(id, function (this: BaseLayer) {
showCost: !upgrade.bought.value showCost: !upgrade.bought.value
}), }),
style: "width: 190px", style: "width: 190px",
onPurchase: elfReset.reset onPurchase () {
options.onPurchase?.();
elfReset.reset();
}
}; };
}) as GenericUpgrade & { }) as GenericUpgrade & {
buyProgress: Ref<number>; buyProgress: Ref<number>;
@ -420,6 +424,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
if (smallFireElf.toggle.value) { if (smallFireElf.toggle.value) {
coal.activeFires.value = Decimal.add(coal.activeFires.value, 1); coal.activeFires.value = Decimal.add(coal.activeFires.value, 1);
} }
},
onPurchase () {
main.days[4].recentlyUpdated.value = true;
} }
}); });
const bonfireElf = createElf({ const bonfireElf = createElf({
@ -437,6 +444,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
coal.buildFire.amount.value = Decimal.sub(coal.buildFire.amount.value, unref(this.buyable.cost!)); coal.buildFire.amount.value = Decimal.sub(coal.buildFire.amount.value, unref(this.buyable.cost!));
coal.activeFires.value = Decimal.sub(coal.activeFires.value, unref(this.buyable.cost!)); coal.activeFires.value = Decimal.sub(coal.activeFires.value, unref(this.buyable.cost!));
} }
},
onPurchase () {
main.days[4].recentlyUpdated.value = true;
} }
}); });
const kilnElf = createElf({ const kilnElf = createElf({
@ -452,6 +462,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
if (kilnElf.toggle.value) { if (kilnElf.toggle.value) {
coal.activeKilns.value = Decimal.add(coal.activeKilns.value, 1); coal.activeKilns.value = Decimal.add(coal.activeKilns.value, 1);
} }
},
onPurchase () {
main.days[4].recentlyUpdated.value = true;
} }
}); });
const fireElves = [smallFireElf, bonfireElf, kilnElf]; const fireElves = [smallFireElf, bonfireElf, kilnElf];

View file

@ -24,7 +24,7 @@ import {
Modifier Modifier
} from "game/modifiers"; } from "game/modifiers";
import { persistent } from "game/persistence"; import { persistent } from "game/persistence";
import Decimal, { DecimalSource, format, formatWhole } from "util/bignum"; import Decimal, { DecimalSource, format, formatWhole, formatLimit } from "util/bignum";
import { Direction, WithRequired } from "util/common"; import { Direction, WithRequired } from "util/common";
import { render, renderRow } from "util/vue"; import { render, renderRow } from "util/vue";
import { computed, ref, watchEffect } from "vue"; import { computed, ref, watchEffect } from "vue";
@ -39,7 +39,7 @@ const day = 1;
// how much to prioritize this' income // how much to prioritize this' income
// vs the previous ones // vs the previous ones
const SMOOTHING_FACTOR = 0.5; const SMOOTHING_FACTOR = 0.1;
const layer = createLayer(id, function (this: BaseLayer) { const layer = createLayer(id, function (this: BaseLayer) {
const name = "Trees"; const name = "Trees";
const colorBright = "#4BDC13"; const colorBright = "#4BDC13";
@ -79,6 +79,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
computed(() => Decimal.sub(totalTrees.apply(10), saplings.value)), computed(() => Decimal.sub(totalTrees.apply(10), saplings.value)),
"trees" "trees"
); );
const computedTotalTrees = computed(() => totalTrees.apply(10));
const manualCutUpgrade1 = createUpgrade(() => ({ const manualCutUpgrade1 = createUpgrade(() => ({
resource: logs, resource: logs,
@ -421,7 +422,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
enabled: boxes.upgrades.logsUpgrade.bought enabled: boxes.upgrades.logsUpgrade.bought
})), })),
createExponentialModifier(() => ({ createExponentialModifier(() => ({
exponent: 1.1, exponent: 1.2,
description: "100% Foundation Completed", description: "100% Foundation Completed",
enabled: workshop.milestones.logGainMilestone3.earned enabled: workshop.milestones.logGainMilestone3.earned
})) }))
@ -623,7 +624,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
trees.value, trees.value,
Decimal.times(computedAutoCuttingAmount.value, diff) Decimal.times(computedAutoCuttingAmount.value, diff)
); );
const logsGained = logGain.apply(amountCut); const logsGained = Decimal.mul(logGain.apply(1), amountCut);
const effectiveLogsGained = Decimal.div(logsGained, diff); const effectiveLogsGained = Decimal.div(logsGained, diff);
ema.value = Decimal.mul(effectiveLogsGained, SMOOTHING_FACTOR).add( ema.value = Decimal.mul(effectiveLogsGained, SMOOTHING_FACTOR).add(
@ -708,16 +709,13 @@ const layer = createLayer(id, function (this: BaseLayer) {
resource={logs} resource={logs}
color={colorBright} color={colorBright}
style="margin-bottom: 0" style="margin-bottom: 0"
effectDisplay={ productionDisplay={
Decimal.gt(computedAutoCuttingAmount.value, 0) Decimal.gt(computedAutoCuttingAmount.value, 0)
? `expected: +${format( ? `+${format(ema.value)}/s average<br/>equilibrium: +${formatLimit([
logGain.apply(computedAutoCuttingAmount.value) [Decimal.mul(logGain.apply(1), computedAutoCuttingAmount.value), "cutting speed"],
)}/s, average: +${format(ema.value)}/s (${format( [Decimal.mul(logGain.apply(1), computedAutoPlantingAmount.value), "planting speed"],
Decimal.div( [Decimal.mul(logGain.apply(1), Decimal.mul(computedTotalTrees.value, 20)), "forest cap"]
ema.value, ], "/s")}`
logGain.apply(computedAutoCuttingAmount.value)
).mul(100)
)}% efficent)`
: undefined : undefined
} }
/> />
@ -725,7 +723,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
resource={saplings} resource={saplings}
color={colorDark} color={colorDark}
style="margin-bottom: 0" style="margin-bottom: 0"
effectDisplay={ productionDisplay={
{ {
[-1]: `${formatWhole(netSaplingGain.value)}/s`, [-1]: `${formatWhole(netSaplingGain.value)}/s`,
0: undefined, 0: undefined,
@ -737,7 +735,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
resource={trees} resource={trees}
color={colorDark} color={colorDark}
style="margin-bottom: 0" style="margin-bottom: 0"
effectDisplay={ productionDisplay={
{ {
[-1]: `${formatWhole(netTreeGain.value)}/s`, [-1]: `${formatWhole(netTreeGain.value)}/s`,
0: undefined, 0: undefined,
@ -748,10 +746,6 @@ const layer = createLayer(id, function (this: BaseLayer) {
<Spacer /> <Spacer />
{renderRow(cutTree, plantTree)} {renderRow(cutTree, plantTree)}
<div>Tip: You can hold down on actions to perform them automatically</div> <div>Tip: You can hold down on actions to perform them automatically</div>
<div>
Note: your average log gain will be equal to your expected log gain if you have
enough trees to support your chopping
</div>
<Spacer /> <Spacer />
{renderRow(...row1Upgrades)} {renderRow(...row1Upgrades)}
{renderRow(...row2Upgrades)} {renderRow(...row2Upgrades)}

View file

@ -18,7 +18,7 @@ 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, Resource } from "features/resources/resource";
import { BaseLayer, createLayer } from "game/layers"; import { BaseLayer, createLayer } from "game/layers";
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";
@ -161,7 +161,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
const logGainMilestone3 = createMilestone(() => ({ const logGainMilestone3 = createMilestone(() => ({
display: { display: {
requirement: "100% Foundation Completed", requirement: "100% Foundation Completed",
effectDisplay: "Trees' log gain is now raised to the 1.1th power" effectDisplay: "Log per tree is raised to the 1.2th power"
}, },
shouldEarn: () => Decimal.gte(foundationProgress.value, 100), shouldEarn: () => Decimal.gte(foundationProgress.value, 100),
visibility: () => showIf(morePlantsMilestone1.earned.value), visibility: () => showIf(morePlantsMilestone1.earned.value),
@ -216,10 +216,17 @@ const layer = createLayer(id, function (this: BaseLayer) {
</div> </div>
{render(dayProgress)} {render(dayProgress)}
<Spacer /> <Spacer />
{render(buildFoundation)} <div>
<span>The foundation is </span>
<h2 style={`color: ${color}; text-shadow: 0 0 10px ${color}`}>
{ formatWhole( foundationProgress.value ) }
</h2>
% completed
</div>
{Decimal.lt(foundationProgress.value, 100) ? ( {Decimal.lt(foundationProgress.value, 100) ? (
<div>You have {formatWhole(foundationProgress.value)}% completed</div> <Spacer />
) : null} ) : null}
{render(buildFoundation)}
<Spacer /> <Spacer />
{milestonesDisplay()} {milestonesDisplay()}
</> </>

View file

@ -11,7 +11,12 @@ import { persistent } from "game/persistence";
import type { PlayerData } from "game/player"; import type { PlayerData } from "game/player";
import player from "game/player"; import player from "game/player";
import { format, formatTime } from "util/bignum"; import { format, formatTime } from "util/bignum";
import { Computable, convertComputable, ProcessedComputable } from "util/computed"; import {
Computable,
convertComputable,
processComputable,
ProcessedComputable
} from "util/computed";
import { createLazyProxy } from "util/proxies"; import { createLazyProxy } from "util/proxies";
import { renderRow, VueFeature } from "util/vue"; import { renderRow, VueFeature } from "util/vue";
import type { Ref } from "vue"; import type { Ref } from "vue";
@ -38,6 +43,7 @@ export interface Day extends VueFeature {
story: string; story: string;
completedStory: string; completedStory: string;
opened: Ref<boolean>; opened: Ref<boolean>;
recentlyUpdated: Ref<boolean>; // Has the tab recieved an update since the player last opened it?
shouldNotify: ProcessedComputable<boolean>; shouldNotify: ProcessedComputable<boolean>;
} }
@ -60,24 +66,39 @@ export const main = createLayer("main", function (this: BaseLayer) {
} }
): Day { ): Day {
const opened = persistent<boolean>(false); const opened = persistent<boolean>(false);
const recentlyUpdated = persistent<boolean>(false);
return createLazyProxy(() => { return createLazyProxy(() => {
const day = optionsFunc(); const day = optionsFunc();
const shouldNotify = convertComputable(day.shouldNotify); const optionsShouldNotify = convertComputable(day.shouldNotify);
const shouldNotify = convertComputable(
() => unref(optionsShouldNotify) || unref(recentlyUpdated)
);
return { return {
...day, ...day,
opened, opened,
shouldNotify, shouldNotify,
recentlyUpdated,
[Component]: Day as GenericComponent, [Component]: Day as GenericComponent,
[GatherProps]: function (this: Day) { [GatherProps]: function (this: Day) {
const { day, layer, symbol, opened, shouldNotify, story, completedStory } = const {
this; day,
layer,
symbol,
opened,
shouldNotify,
story,
completedStory,
recentlyUpdated
} = this;
return { return {
day, day,
symbol, symbol,
opened, opened,
recentlyUpdated,
shouldNotify, shouldNotify,
onOpenLore() { onOpenLore() {
const completed = main.day.value > day; const completed = main.day.value > day;
@ -91,6 +112,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
showLoreModal.value = true; showLoreModal.value = true;
}, },
onOpenLayer() { onOpenLayer() {
recentlyUpdated.value = false;
// 1468 is because two tabs with minWidth of 700px plus the minimized calendar of 60px plus 2 dividers of 4px each // 1468 is because two tabs with minWidth of 700px plus the minimized calendar of 60px plus 2 dividers of 4px each
if (window.matchMedia("(min-width: 1468px)").matches) { if (window.matchMedia("(min-width: 1468px)").matches) {
// Desktop, allow multiple tabs to be open // Desktop, allow multiple tabs to be open

View file

@ -13,6 +13,10 @@
<span v-if="effectComponent" <span v-if="effectComponent"
>, <component :is="effectComponent" ref="effectRef" >, <component :is="effectComponent" ref="effectRef"
/></span> /></span>
<span v-if="productionComponent">
<br/>
<component :is="productionComponent" ref="effectRef"
/></span>
</div> </div>
</div> </div>
</Sticky> </Sticky>
@ -34,6 +38,7 @@ const _props = defineProps<{
classes?: Record<string, boolean>; classes?: Record<string, boolean>;
style?: StyleValue; style?: StyleValue;
effectDisplay?: CoercableComponent; effectDisplay?: CoercableComponent;
productionDisplay?: CoercableComponent;
}>(); }>();
const props = toRefs(_props); const props = toRefs(_props);
@ -43,6 +48,10 @@ const effectComponent = computeOptionalComponent(
props.effectDisplay as Ref<CoercableComponent | undefined> props.effectDisplay as Ref<CoercableComponent | undefined>
); );
const productionComponent = computeOptionalComponent(
props.productionDisplay as Ref<CoercableComponent | undefined>
);
const showPrefix = computed(() => { const showPrefix = computed(() => {
return Decimal.lt(props.resource.value, "1e1000"); return Decimal.lt(props.resource.value, "1e1000");
}); });

View file

@ -12,6 +12,7 @@ export const {
formatTime, formatTime,
toPlaces, toPlaces,
formatSmall, formatSmall,
formatLimit,
invertOOM invertOOM
} = numberUtils; } = numberUtils;
@ -29,6 +30,7 @@ declare global {
formatTime: (s: number) => string; formatTime: (s: number) => string;
toPlaces: (x: DecimalSource, precision: number, maxAccepted: DecimalSource) => string; toPlaces: (x: DecimalSource, precision: number, maxAccepted: DecimalSource) => string;
formatSmall: (x: DecimalSource, precision?: number) => string; formatSmall: (x: DecimalSource, precision?: number) => string;
formatLimit: (list: [DecimalSource, string][], unit: string) => string ;
invertOOM: (x: DecimalSource) => Decimal; invertOOM: (x: DecimalSource) => Decimal;
} }
} }
@ -41,6 +43,7 @@ window.formatWhole = formatWhole;
window.formatTime = formatTime; window.formatTime = formatTime;
window.toPlaces = toPlaces; window.toPlaces = toPlaces;
window.formatSmall = formatSmall; window.formatSmall = formatSmall;
window.formatLimit = formatLimit;
window.invertOOM = invertOOM; window.invertOOM = invertOOM;
export default Decimal; export default Decimal;

View file

@ -194,3 +194,15 @@ export function invertOOM(x: DecimalSource): Decimal {
return x; return x;
} }
export function formatLimit(list: [DecimalSource, string][], unit: string): string {
let num = list[0][0];
let str = list[0][1];
for (let i = 1; i < list.length; i++) {
if (Decimal.lt(list[i][0], num)) {
num = list[i][0];
str = list[i][1];
}
}
return format(num) + unit + ", limited by " + str;
}