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 { VueFeature, render, renderRow, trackHover } from "util/vue";
import { ComputedRef, Ref, computed, ref } from "vue"; import { ComputedRef, Ref, computed, ref } from "vue";
import { createCollapsibleModifierSections, createFormulaPreview, estimateTime } from "./common"; 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 { getColor, getName, sfc32 } from "./utils";
import ModalVue from "components/Modal.vue"; import ModalVue from "components/Modal.vue";
import { addTooltip } from "features/tooltips/tooltip"; import { addTooltip } from "features/tooltips/tooltip";
@ -185,7 +185,10 @@ export function createPlane(id: string, tier: Resources, seed: number) {
break; break;
} }
const treasureWeights = { const treasureWeights = {
dirtGeneration: 16 cache: 100,
generation: 10,
resourceMulti: 5,
energyMulti: 5
}; };
const sumTreasureWeights = Object.values(treasureWeights).reduce((a, b) => a + b); const sumTreasureWeights = Object.values(treasureWeights).reduce((a, b) => a + b);
const treasureWeightsKeys = Object.keys( const treasureWeightsKeys = Object.keys(
@ -209,11 +212,43 @@ export function createPlane(id: string, tier: Resources, seed: number) {
let update: (diff: number) => void; let update: (diff: number) => void;
let onComplete: VoidFunction; let onComplete: VoidFunction;
let link: ComputedRef<BoardNode>; let link: ComputedRef<BoardNode>;
let randomResource: Resources;
let effectedResource: Resources | "energy";
let resourceMulti: DecimalSource;
switch (treasureType) { switch (treasureType) {
case "dirtGeneration": case "cache":
description = `Gain ${format(difficulty)} dirt/s while plane is active`; randomResource = getRandomResource(random);
update = diff => main.grantResource("dirt", Decimal.times(diff, difficulty)); description = `Gain ${format(difficulty)}x your current ${randomResource}.`;
link = computed(() => main.resourceNodes.value["dirt"]); 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; break;
} }
const cost = Decimal.times(difficulty, random() + 0.5) const cost = Decimal.times(difficulty, random() + 0.5)
@ -237,7 +272,9 @@ export function createPlane(id: string, tier: Resources, seed: number) {
}, },
update, update,
onComplete, onComplete,
link link,
effectedResource,
resourceMulti
})) as GenericAchievement; })) as GenericAchievement;
features.push([milestone]); features.push([milestone]);
visibility = milestone.earned; visibility = milestone.earned;
@ -317,6 +354,32 @@ export function createPlane(id: string, tier: Resources, seed: number) {
return links; 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 { return {
tier: persistent(tier), tier: persistent(tier),
seed: persistent(seed), seed: persistent(seed),
@ -331,6 +394,7 @@ export function createPlane(id: string, tier: Resources, seed: number) {
features, features,
resourceTabCollapsed, resourceTabCollapsed,
links, links,
resourceMultis,
display: jsx(() => ( display: jsx(() => (
<> <>
<StickyVue class="nav-container"> <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>; export type GenericPlane = ReturnType<typeof createPlane>;

View file

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