Implement most treasures

Implemented resource caches, resource generation, resource multis, and energy multis.
Remaining: influences and relics.
This commit is contained in:
thepaperpilot 2023-04-29 13:17:56 -05:00
parent da393b7f5a
commit fd7df64e0e
2 changed files with 183 additions and 26 deletions

View file

@ -20,7 +20,7 @@ import { Direction, WithRequired, camelToTitle } from "util/common";
import { VueFeature, render, renderRow, trackHover } from "util/vue";
import { ComputedRef, Ref, computed, ref } from "vue";
import { createCollapsibleModifierSections, createFormulaPreview, estimateTime } from "./common";
import { main, Resources, resourceNames } from "./projEntry";
import { main, Resources, resourceNames, mineLootTable, ResourceState } from "./projEntry";
import { getColor, getName, sfc32 } from "./utils";
import ModalVue from "components/Modal.vue";
import { addTooltip } from "features/tooltips/tooltip";
@ -185,7 +185,10 @@ export function createPlane(id: string, tier: Resources, seed: number) {
break;
}
const treasureWeights = {
dirtGeneration: 16
cache: 100,
generation: 10,
resourceMulti: 5,
energyMulti: 5
};
const sumTreasureWeights = Object.values(treasureWeights).reduce((a, b) => a + b);
const treasureWeightsKeys = Object.keys(
@ -209,11 +212,43 @@ export function createPlane(id: string, tier: Resources, seed: number) {
let update: (diff: number) => void;
let onComplete: VoidFunction;
let link: ComputedRef<BoardNode>;
let randomResource: Resources;
let effectedResource: Resources | "energy";
let resourceMulti: DecimalSource;
switch (treasureType) {
case "dirtGeneration":
description = `Gain ${format(difficulty)} dirt/s while plane is active`;
update = diff => main.grantResource("dirt", Decimal.times(diff, difficulty));
link = computed(() => main.resourceNodes.value["dirt"]);
case "cache":
randomResource = getRandomResource(random);
description = `Gain ${format(difficulty)}x your current ${randomResource}.`;
onComplete = () =>
main.grantResource(
randomResource,
Decimal.times(
(
main.resourceNodes.value[randomResource]
?.state as unknown as ResourceState | null
)?.amount ?? 0,
difficulty
)
);
break;
case "generation":
randomResource = getRandomResource(random);
const gain = Decimal.div(difficulty, 120).times(mineLootTable[randomResource]);
description = `Gain ${format(gain)} ${randomResource}/s while plane is active.`;
update = diff => main.grantResource(randomResource, Decimal.times(diff, gain));
link = computed(() => main.resourceNodes.value[randomResource]);
break;
case "resourceMulti":
effectedResource = randomResource = getRandomResource(random);
resourceMulti = Decimal.div(difficulty, 17).pow_base(2);
description = `Gain ${format(
resourceMulti
)}x ${randomResource} while plane is active.`;
break;
case "energyMulti":
effectedResource = "energy";
resourceMulti = Decimal.div(difficulty, 17);
description = `Gain ${format(resourceMulti)}x energy while plane is active.`;
break;
}
const cost = Decimal.times(difficulty, random() + 0.5)
@ -237,7 +272,9 @@ export function createPlane(id: string, tier: Resources, seed: number) {
},
update,
onComplete,
link
link,
effectedResource,
resourceMulti
})) as GenericAchievement;
features.push([milestone]);
visibility = milestone.earned;
@ -317,6 +354,32 @@ export function createPlane(id: string, tier: Resources, seed: number) {
return links;
});
const resourceMultis = computed(() => {
const multis: Partial<Record<Resources | "energy", DecimalSource>> = {};
for (let i = 1; i < features.length; i += 2) {
const treasure = features[i][0] as GenericAchievement & {
effectedResource?: Resources | "energy";
resourceMulti: DecimalSource;
};
if (
treasure.earned.value &&
treasure.effectedResource != null &&
treasure.resourceMulti != null
) {
if (multis[treasure.effectedResource] != null) {
multis[treasure.effectedResource] = Decimal.times(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
multis[treasure.effectedResource]!,
treasure.resourceMulti
);
} else {
multis[treasure.effectedResource] = treasure.resourceMulti;
}
}
}
return multis;
});
return {
tier: persistent(tier),
seed: persistent(seed),
@ -331,6 +394,7 @@ export function createPlane(id: string, tier: Resources, seed: number) {
features,
resourceTabCollapsed,
links,
resourceMultis,
display: jsx(() => (
<>
<StickyVue class="nav-container">
@ -375,4 +439,23 @@ export function createPlane(id: string, tier: Resources, seed: number) {
});
}
// Using separate method from what's used in mining, because planes are influenced by influences and not things like dowsing
function getRandomResource(random: () => number) {
const sumResourceWeights = (Object.values(mineLootTable) as number[]).reduce((a, b) => a + b);
const resourceWeightsKeys = Object.keys(mineLootTable) as Resources[];
const r = Math.floor(random() * sumResourceWeights);
let weight = 0;
let resource: Resources;
for (let i = 0; i < resourceWeightsKeys.length; i++) {
const type = resourceWeightsKeys[i];
weight += mineLootTable[type];
if (r < weight) {
resource = type;
break;
}
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return resource!;
}
export type GenericPlane = ReturnType<typeof createPlane>;

View file

@ -74,7 +74,7 @@ export interface PortalState {
powered: boolean;
}
const mineLootTable = {
export const mineLootTable = {
dirt: 120,
sand: 60,
gravel: 40,
@ -202,7 +202,7 @@ const passives = {
},
gravel: {
description: (empowered: boolean) =>
empowered ? "Quadruples material drops" : "Doubles material drops"
empowered ? "Quadruples mine ore drops" : "Doubles mine ore drops"
},
stone: {
description: (empowered: boolean) =>
@ -715,10 +715,14 @@ export const main = createLayer("main", function (this: BaseLayer) {
progressColor: "var(--accent3)",
classes: node => ({
"affected-node":
dowsing.value != null &&
isPowered(dowsing.value) &&
(dowsing.value.state as unknown as DowsingState).resources.includes(
(node.state as unknown as ResourceState).type
(dowsing.value != null &&
isPowered(dowsing.value) &&
(dowsing.value.state as unknown as DowsingState).resources.includes(
(node.state as unknown as ResourceState).type
)) ||
Decimal.neq(
planarMultis.value[(node.state as unknown as ResourceState).type] ?? 1,
1
)
}),
draggable: true
@ -1107,20 +1111,34 @@ export const main = createLayer("main", function (this: BaseLayer) {
});
// TODO link to influences
}
links.push(
...activePortals.value
.map(node =>
(
layers[(node.state as unknown as PortalState).id] as GenericPlane
).links.value.map(n => ({
(board as GenericBoard).types.portal.nodes.value.forEach(node => {
const plane = layers[(node.state as unknown as PortalState).id] as GenericPlane;
plane.links.value.forEach(n => {
if (n.value != null) {
links.push({
startNode: node,
endNode: n.value,
stroke: "var(--accent3)",
stroke: isPowered(node) ? "var(--accent3)" : "var(--foreground)",
strokeWidth: 4
}))
)
.reduce((a, b) => [...a, ...b], [])
);
});
}
});
(Object.keys(plane.resourceMultis.value) as (Resources | "energy")[]).forEach(
type => {
if (type !== "energy" && type in resourceNodes.value) {
links.push({
startNode: node,
endNode: resourceNodes.value[type],
stroke: isPowered(node)
? "var(--accent1)"
: "var(--foreground)",
strokeWidth: 4
});
}
}
);
return links;
});
}
return links;
}
@ -1143,6 +1161,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
function grantResource(type: Resources, amount: DecimalSource) {
let node = resourceNodes.value[type];
amount = Decimal.times(amount, resourceGain[type].computedModifier.value);
if (node == null) {
node = {
id: getUniqueNodeID(board),
@ -1169,6 +1188,26 @@ export const main = createLayer("main", function (this: BaseLayer) {
)
);
const planarMultis = computed(() => {
const multis: Partial<Record<Resources | "energy", DecimalSource>> = {};
board.types.portal.nodes.value.forEach(n => {
if (!isPowered(n)) {
return;
}
const plane = layers[(n.state as unknown as PortalState).id] as GenericPlane;
const planeMultis = plane.resourceMultis.value;
(Object.keys(planeMultis) as (Resources | "energy")[]).forEach(type => {
if (multis[type] != null) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
multis[type] = Decimal.times(multis[type]!, planeMultis[type]!);
} else {
multis[type] = planeMultis[type];
}
});
});
return multis;
});
const energyModifier = createSequentialModifier(() => [
...resourceNames.map(resource =>
createMultiplicativeModifier(() => ({
@ -1205,6 +1244,11 @@ export const main = createLayer("main", function (this: BaseLayer) {
: "") + tools.stone.name,
enabled: () => toolNodes.value["stone"] != null
})),
createMultiplicativeModifier(() => ({
multiplier: () => planarMultis.value.energy ?? 1,
description: "Planar Treasures",
enabled: () => Decimal.neq(planarMultis.value.energy ?? 1, 1)
})),
createAdditiveModifier(() => ({
addend: () => Decimal.pow(100, poweredMachines.value).div(10).neg(),
description: "Powered Machines (100^n/10 energy/s)",
@ -1293,6 +1337,23 @@ export const main = createLayer("main", function (this: BaseLayer) {
return acc;
}, {} as Record<Resources, { modifier: WithRequired<Modifier, "invert" | "description">; computedModifier: ComputedRef<DecimalSource>; section: Section }>);
const resourceGain = (Object.keys(mineLootTable) as Resources[]).reduce((acc, resource) => {
const modifier = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: () => planarMultis.value[resource] ?? 1,
description: "Planar Treasures",
enabled: () => Decimal.neq(planarMultis.value[resource] ?? 1, 1)
}))
]);
const computedModifier = computed(() => modifier.apply(1));
const section = {
title: `${camelToTitle(resource)} Gain`,
modifier
};
acc[resource] = { modifier, computedModifier, section };
return acc;
}, {} as Record<Resources, { modifier: WithRequired<Modifier, "invert" | "description">; computedModifier: ComputedRef<DecimalSource>; section: Section }>);
const [energyTab, energyTabCollapsed] = createCollapsibleModifierSections(() => [
{
title: "Energy Gain",
@ -1325,6 +1386,9 @@ export const main = createLayer("main", function (this: BaseLayer) {
const [resourcesTab, resourcesCollapsed] = createCollapsibleModifierSections(() =>
Object.values(dropRates).map(d => d.section)
);
const [resourceGainTab, resourceGainCollapsed] = createCollapsibleModifierSections(() =>
Object.values(resourceGain).map(d => d.section)
);
const modifierTabs = createTabFamily({
general: () => ({
display: "Energy",
@ -1335,7 +1399,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
energyTabCollapsed
}),
mining: () => ({
display: "Mining",
display: "Mine",
glowColor(): string {
return modifierTabs.activeTab.value === this.tab ? "white" : "";
},
@ -1344,13 +1408,23 @@ export const main = createLayer("main", function (this: BaseLayer) {
miningTabCollapsed
}),
resources: () => ({
display: "Resources",
display: "Mine Rates",
glowColor(): string {
return modifierTabs.activeTab.value === this.tab ? "white" : "";
},
visibility: () => dowsing.value != null,
tab: resourcesTab,
resourcesCollapsed
}),
resourcesGain: () => ({
display: "Resource Gain",
glowColor(): string {
return modifierTabs.activeTab.value === this.tab ? "white" : "";
},
visibility: () =>
Object.values(resourceGain).some(r => Decimal.neq(r.computedModifier.value, 1)),
tab: resourceGainTab,
resourceGainCollapsed
})
});
const showModifiersModal = ref(false);