Add automator, some cleanup

This commit is contained in:
thepaperpilot 2023-05-10 09:00:17 -05:00
parent bcaff20313
commit 9dbfdef509
6 changed files with 149 additions and 38 deletions

View file

@ -347,7 +347,7 @@ export function checkConnections<T extends string>(
}; };
const currentConnections = state[connectionsName]; const currentConnections = state[connectionsName];
const maxConnections = state.maxConnections; const maxConnections = state.maxConnections;
if (Decimal.lt(currentConnections.length, Decimal.add(maxConnections, bonusConnections))) { if (Decimal.gt(currentConnections.length, Decimal.add(maxConnections, bonusConnections))) {
node.value.state = { node.value.state = {
...(node.value.state as object), ...(node.value.state as object),
[connectionsName]: currentConnections.slice( [connectionsName]: currentConnections.slice(

View file

@ -56,6 +56,12 @@ export interface UpgraderState {
powered: boolean; powered: boolean;
} }
export interface AutomatorState {
portals: string[];
maxConnections: number;
powered: boolean;
}
export const mineLootTable = { export const mineLootTable = {
dirt: 120, dirt: 120,
sand: 60, sand: 60,
@ -224,8 +230,8 @@ export const passives = {
silver: { silver: {
description: (empowered: boolean) => description: (empowered: boolean) =>
empowered empowered
? "Doubles each plane's resource gain" ? "Quadruples each plane's resource gain"
: "Quadruples each plane's resource gain" : "Doubles each plane's resource gain"
}, },
diamond: { diamond: {
description: (empowered: boolean) => description: (empowered: boolean) =>

View file

@ -29,6 +29,7 @@ import {
togglePoweredAction togglePoweredAction
} from "./boardUtils"; } from "./boardUtils";
import { import {
AutomatorState,
BoosterState, BoosterState,
DowsingState, DowsingState,
EmpowererState, EmpowererState,
@ -239,7 +240,13 @@ export const resource = {
export const passive = { export const passive = {
shape: Shape.Circle, shape: Shape.Circle,
size: 50, size: 50,
title: node => tools[node.state as Resources].name, title: node => {
const passive = node.state as Passives;
if (passive.includes("Relic")) {
return relics[passive.slice(0, -5) as Resources];
}
return tools[passive as Resources].name;
},
label: node => label: node =>
node === main.board.selectedNode.value node === main.board.selectedNode.value
? { ? {
@ -708,7 +715,7 @@ export const upgrader = {
}; };
} }
return labelForAcceptingPortal(node, portal => { return labelForAcceptingPortal(node, portal => {
return `Auto-buy ${(layers[portal] as GenericPlane).name}'s upgrades`; return `Auto-buy ${(layers[portal] as GenericPlane).name}'s upgrades and prestiges`;
}); });
}, },
actionDistance: Math.PI / 4, actionDistance: Math.PI / 4,
@ -737,3 +744,52 @@ export const upgrader = {
}), }),
draggable: true draggable: true
} as NodeTypeOptions; } as NodeTypeOptions;
export const automator = {
shape: Shape.Diamond,
size: 50,
title: "🦾",
label: node => {
if (node === main.board.selectedNode.value) {
return {
text:
(node.state as unknown as AutomatorState).portals.length === 0
? "Automator - Drag a portal to me!"
: `Automatating (${
(node.state as unknown as AutomatorState).portals.length
}/${Decimal.add(
(node.state as unknown as AutomatorState).maxConnections,
main.computedBonusConnectionsModifier.value
)})`
};
}
return labelForAcceptingPortal(node, portal => {
return `Auto-buy ${(layers[portal] as GenericPlane).name}'s repeatables and dimensions`;
});
},
actionDistance: Math.PI / 4,
actions: [
{
id: "deselect",
icon: "close",
tooltip: {
text: "Disconnect portals"
},
onClick(node: BoardNode) {
node.state = { ...(node.state as object), portals: [] };
main.board.selectedAction.value = null;
main.board.selectedNode.value = null;
},
visibility: (node: BoardNode) =>
(node.state as unknown as AutomatorState)?.portals.length ?? 0 > 0
},
getIncreaseConnectionsAction(x => x.add(4).pow_base(1e6)),
togglePoweredAction
],
canAccept: canAcceptPortal,
onDrop: onDropPortal,
classes: node => ({
running: isPowered(node)
}),
draggable: true
} as NodeTypeOptions;

View file

@ -4,7 +4,7 @@ import StickyVue from "components/layout/Sticky.vue";
import { GenericAchievement, createAchievement } from "features/achievements/achievement"; import { GenericAchievement, createAchievement } from "features/achievements/achievement";
import { createBar } from "features/bars/bar"; import { createBar } from "features/bars/bar";
import { BoardNode, getUniqueNodeID } from "features/boards/board"; import { BoardNode, getUniqueNodeID } from "features/boards/board";
import { createClickable } from "features/clickables/clickable"; import { GenericClickable, createClickable, setupAutoClick } from "features/clickables/clickable";
import { createCumulativeConversion } from "features/conversion"; import { createCumulativeConversion } from "features/conversion";
import { CoercableComponent, findFeatures, isVisible, jsx } from "features/feature"; import { CoercableComponent, findFeatures, isVisible, jsx } from "features/feature";
import { GenericRepeatable, RepeatableType, createRepeatable } from "features/repeatable"; import { GenericRepeatable, RepeatableType, createRepeatable } from "features/repeatable";
@ -43,12 +43,14 @@ import { useToast } from "vue-toastification";
import { isPowered } from "./boardUtils"; import { isPowered } from "./boardUtils";
import { createCollapsibleModifierSections, createFormulaPreview, estimateTime } from "./common"; import { createCollapsibleModifierSections, createFormulaPreview, estimateTime } from "./common";
import { import {
AutomatorState,
BoosterState, BoosterState,
InfluenceState, InfluenceState,
Influences, Influences,
PortalState, PortalState,
ResourceState, ResourceState,
Resources, Resources,
UpgraderState,
influences as influenceTypes, influences as influenceTypes,
mineLootTable, mineLootTable,
relics, relics,
@ -130,7 +132,9 @@ export function createPlane(
})), })),
createMultiplicativeModifier(() => ({ createMultiplicativeModifier(() => ({
multiplier: () => multiplier: () =>
Decimal.div(timeActive.value, 6000).times(main.isEmpowered("emerald") ? 2 : 1), Decimal.div(timeActive.value, 6000)
.times(main.isEmpowered("emerald") ? 2 : 1)
.add(1),
description: () => description: () =>
(main.isEmpowered("emerald") ? "Empowered " : "") + tools.emerald.name, (main.isEmpowered("emerald") ? "Empowered " : "") + tools.emerald.name,
enabled: () => main.toolNodes.value.emerald != null enabled: () => main.toolNodes.value.emerald != null
@ -1072,10 +1076,24 @@ export function createPlane(
setupAutoPurchase( setupAutoPurchase(
this as GenericLayer, this as GenericLayer,
() => main.upgrader.value != null && isPowered(main.upgrader.value), () =>
earnedTreasures.value.length < length &&
main.upgrader.value != null &&
isPowered(main.upgrader.value) &&
(main.upgrader.value.state as unknown as UpgraderState).portals.includes(id),
upgrades upgrades
); );
setupAutoClick(
this as GenericLayer,
() =>
earnedTreasures.value.length < length &&
main.automator.value != null &&
isPowered(main.automator.value) &&
(main.automator.value.state as unknown as AutomatorState).portals.includes(id),
repeatables as unknown as GenericClickable[]
);
const resourceChange = computed(() => { const resourceChange = computed(() => {
const preview = previews.find(p => p.shouldShowPreview.value); const preview = previews.find(p => p.shouldShowPreview.value);
if (preview) { if (preview) {
@ -1174,6 +1192,21 @@ export function createPlane(
) )
); );
const renderableFeatures = computed(() => {
const lastIndex = features.findIndex(
(row, i) => i > 0 && i % 2 === 0 && !(features[i - 1][0] as Treasure).earned.value
);
let featuresToRender;
if (lastIndex === -1) {
featuresToRender = features;
} else {
featuresToRender = features.slice(0, lastIndex);
}
return featuresToRender.map((row, i) =>
i in displays ? render(displays[i]) : renderRow(...row)
);
});
return { return {
tier: persistent(tier), tier: persistent(tier),
seed: persistent(seed), seed: persistent(seed),
@ -1254,17 +1287,7 @@ export function createPlane(
) : null} ) : null}
</StickyVue> </StickyVue>
<SpacerVue height="60px" /> <SpacerVue height="60px" />
{features {renderableFeatures.value}
.slice(
0,
features.findIndex(
(row, i) =>
i > 0 &&
i % 2 === 0 &&
!(features[i - 1][0] as Treasure).earned.value
)
)
.map((row, i) => (i in displays ? render(displays[i]) : renderRow(...row)))}
{render(modifiersModal)} {render(modifiersModal)}
</> </>
)), )),

View file

@ -37,6 +37,7 @@ import {
} from "./boardUtils"; } from "./boardUtils";
import { Section, createCollapsibleModifierSections, createFormulaPreview } from "./common"; import { Section, createCollapsibleModifierSections, createFormulaPreview } from "./common";
import { import {
AutomatorState,
BoosterState, BoosterState,
DowsingState, DowsingState,
EmpowererState, EmpowererState,
@ -68,7 +69,8 @@ import {
portalGenerator, portalGenerator,
quarry, quarry,
resource, resource,
upgrader upgrader,
automator
} from "./nodeTypes"; } from "./nodeTypes";
import { GenericPlane, createPlane } from "./planes"; import { GenericPlane, createPlane } from "./planes";
@ -87,7 +89,8 @@ const types = {
portal, portal,
influence, influence,
booster, booster,
upgrader upgrader,
automator
}; };
/** /**
@ -113,7 +116,8 @@ export const main = createLayer("main", function (this: BaseLayer) {
coal: board.types.empowerer.nodes.value[0], coal: board.types.empowerer.nodes.value[0],
iron: board.types.portalGenerator.nodes.value[0], iron: board.types.portalGenerator.nodes.value[0],
gold: board.types.booster.nodes.value[0], gold: board.types.booster.nodes.value[0],
platinum: board.types.upgrader.nodes.value[0] platinum: board.types.upgrader.nodes.value[0],
berylium: board.types.automator.nodes.value[0]
})); }));
const influenceNodes: ComputedRef<Record<Influences, BoardNode>> = computed(() => ({ const influenceNodes: ComputedRef<Record<Influences, BoardNode>> = computed(() => ({
@ -123,6 +127,13 @@ export const main = createLayer("main", function (this: BaseLayer) {
}, {} as Record<Influences, BoardNode>) }, {} as Record<Influences, BoardNode>)
})); }));
const portalNodes: ComputedRef<Record<string, BoardNode>> = computed(() => ({
...board.types.portal.nodes.value.reduce((acc, curr) => {
acc[(curr.state as unknown as PortalState).id] = curr;
return acc;
}, {} as Record<string, BoardNode>)
}));
const resourceLevels = computed(() => const resourceLevels = computed(() =>
resourceNames.reduce((acc, curr) => { resourceNames.reduce((acc, curr) => {
const amount = const amount =
@ -337,10 +348,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
links.push({ links.push({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
startNode: booster.value!, startNode: booster.value!,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion endNode: portalNodes.value[portal],
endNode: (board as GenericBoard).types.portal.nodes.value.find(
node => (node.state as unknown as PortalState).id === portal
)!,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
stroke: isPowered(booster.value!) ? "var(--accent1)" : "var(--foreground)", stroke: isPowered(booster.value!) ? "var(--accent1)" : "var(--foreground)",
strokeWidth: 4 strokeWidth: 4
@ -353,9 +361,19 @@ export const main = createLayer("main", function (this: BaseLayer) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
startNode: upgrader.value!, startNode: upgrader.value!,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
endNode: (board as GenericBoard).types.portal.nodes.value.find( endNode: portalNodes.value[portal],
node => (node.state as unknown as PortalState).id === portal stroke: "var(--foreground)",
)!, strokeWidth: 4
});
});
}
if (automator.value != null) {
(automator.value.state as unknown as AutomatorState).portals.forEach(portal => {
links.push({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
startNode: automator.value!,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
endNode: portalNodes.value[portal],
stroke: "var(--foreground)", stroke: "var(--foreground)",
strokeWidth: 4 strokeWidth: 4
}); });
@ -390,7 +408,8 @@ export const main = createLayer("main", function (this: BaseLayer) {
); );
const booster: ComputedRef<BoardNode | undefined> = computed(() => toolNodes.value.gold); const booster: ComputedRef<BoardNode | undefined> = computed(() => toolNodes.value.gold);
const upgrader: ComputedRef<BoardNode | undefined> = computed(() => toolNodes.value.platinum); const upgrader: ComputedRef<BoardNode | undefined> = computed(() => toolNodes.value.platinum);
const poweredMachines = [mine, dowsing, quarry, empowerer, booster, upgrader]; const automator: ComputedRef<BoardNode | undefined> = computed(() => toolNodes.value.berylium);
const poweredMachines = [mine, dowsing, quarry, empowerer, booster, upgrader, automator];
function grantResource(type: Resources, amount: DecimalSource) { function grantResource(type: Resources, amount: DecimalSource) {
let node = resourceNodes.value[type]; let node = resourceNodes.value[type];
@ -800,6 +819,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
checkConnections(curr, empowerer, "tools"); checkConnections(curr, empowerer, "tools");
checkConnections(curr, booster, "portals"); checkConnections(curr, booster, "portals");
checkConnections(curr, upgrader, "portals"); checkConnections(curr, upgrader, "portals");
checkConnections(curr, automator, "portals");
} }
}); });
@ -822,6 +842,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
empowerer, empowerer,
booster, booster,
upgrader, upgrader,
automator,
resourceLevels, resourceLevels,
planarMultis, planarMultis,
display: jsx(() => ( display: jsx(() => (

View file

@ -1,14 +1,15 @@
import ClickableComponent from "features/clickables/Clickable.vue"; import ClickableComponent from "features/clickables/Clickable.vue";
import { GenericDecorator } from "features/decorators/common"; import { GenericDecorator } from "features/decorators/common";
import type { import {
CoercableComponent, CoercableComponent,
GenericComponent, GenericComponent,
OptionsFunc, OptionsFunc,
Replace, Replace,
StyleValue StyleValue,
findFeatures
} from "features/feature"; } from "features/feature";
import { Component, GatherProps, Visibility, getUniqueID, setDefault } from "features/feature"; import { Component, GatherProps, Visibility, getUniqueID, setDefault } from "features/feature";
import type { BaseLayer } from "game/layers"; import type { BaseLayer, GenericLayer } from "game/layers";
import type { Unsubscribe } from "nanoevents"; import type { Unsubscribe } from "nanoevents";
import type { import type {
Computable, Computable,
@ -190,15 +191,19 @@ export function createClickable<T extends ClickableOptions>(
* @param autoActive Whether or not the clickable should currently be auto-clicking * @param autoActive Whether or not the clickable should currently be auto-clicking
*/ */
export function setupAutoClick( export function setupAutoClick(
layer: BaseLayer, layer: GenericLayer,
clickable: GenericClickable, autoActive: Computable<boolean>,
autoActive: Computable<boolean> = true clickables: GenericClickable[] = []
): Unsubscribe { ): Unsubscribe {
clickables =
clickables.length === 0
? (findFeatures(layer, ClickableType) as GenericClickable[])
: clickables;
const isActive: ProcessedComputable<boolean> = const isActive: ProcessedComputable<boolean> =
typeof autoActive === "function" ? computed(autoActive) : autoActive; typeof autoActive === "function" ? computed(autoActive) : autoActive;
return layer.on("update", () => { return layer.on("update", () => {
if (unref(isActive) && unref(clickable.canClick)) { if (unref(isActive)) {
clickable.onClick?.(); clickables.filter(c => unref(c.canClick)).forEach(c => c.onClick?.());
} }
}); });
} }