Implemented links between resource nodes

This commit is contained in:
thepaperpilot 2021-08-24 02:54:42 -05:00
parent 4312b7ac75
commit b41e44e87e
2 changed files with 174 additions and 23 deletions

View file

@ -22,7 +22,7 @@ import { format } from "@/util/break_eternity";
import { camelToTitle } from "@/util/common"; import { camelToTitle } from "@/util/common";
import { coerceComponent } from "@/util/vue"; import { coerceComponent } from "@/util/vue";
import { computed, defineComponent, shallowRef, watchEffect } from "vue"; import { computed, defineComponent, shallowRef, watchEffect } from "vue";
import { ActionNodeData, ResourceNodeData } from "./main"; import { ActionNodeData } from "./main";
export default defineComponent(function Main() { export default defineComponent(function Main() {
const title = shallowRef<CoercableComponent | null>(null); const title = shallowRef<CoercableComponent | null>(null);
@ -41,19 +41,6 @@ export default defineComponent(function Main() {
default: default:
player.layers.main.showModal = false; player.layers.main.showModal = false;
break; break;
case "resource":
switch ((node.data as ResourceNodeData).resourceType) {
default:
player.layers.main.showModal = false;
break;
case "time":
title.value = coerceComponent("<h2>Time</h2>");
body.value = coerceComponent(
"The ultimate resource, that you'll never have enough of."
);
break;
}
break;
case "action": case "action":
title.value = coerceComponent( title.value = coerceComponent(
camelToTitle((node.data as ActionNodeData).actionType) camelToTitle((node.data as ActionNodeData).actionType)

View file

@ -4,9 +4,10 @@ import player from "@/game/player";
import Decimal, { DecimalSource } from "@/lib/break_eternity"; import Decimal, { DecimalSource } from "@/lib/break_eternity";
import { RawLayer } from "@/typings/layer"; import { RawLayer } from "@/typings/layer";
import { formatTime } from "@/util/bignum"; import { formatTime } from "@/util/bignum";
import { format } from "@/util/break_eternity"; import { format, formatWhole } from "@/util/break_eternity";
import { camelToTitle } from "@/util/common"; import { camelToTitle } from "@/util/common";
import { getUniqueNodeID } from "@/util/features"; import { getUniqueNodeID } from "@/util/features";
import { watch } from "vue";
import themes from "../themes"; import themes from "../themes";
import Main from "./Main.vue"; import Main from "./Main.vue";
@ -81,6 +82,71 @@ function getRandomEvent(events: WeightedEvent[]): LogEntry | null {
return null; return null;
} }
enum LinkType {
LossOnly,
GainOnly,
Both
}
// Links cause gain/loss of one resource to also affect other resources
const links = {
time: [
{ resource: "social", amount: 1 / 60, linkType: LinkType.LossOnly },
{ resource: "mental", amount: 1 / 120, linkType: LinkType.LossOnly }
]
} as Record<
string,
{
resource: string;
amount: DecimalSource;
linkType: LinkType;
}[]
>;
for (const resource in links) {
const resourceLinks = links[resource];
watch(
() =>
(player.layers.main?.boards.main.nodes.find(
node =>
node.type === "resource" &&
(node.data as ResourceNodeData).resourceType === resource
)?.data as ResourceNodeData | null)?.amount,
(amount, oldAmount) => {
if (amount == null || oldAmount == null) {
return;
}
const resourceGain = Decimal.sub(amount, oldAmount);
resourceLinks.forEach(link => {
switch (link.linkType) {
case LinkType.LossOnly:
if (Decimal.gt(amount, oldAmount)) {
return;
}
break;
case LinkType.GainOnly:
if (Decimal.lt(amount, oldAmount)) {
return;
}
break;
}
const node = player.layers.main.boards.main.nodes.find(
node =>
node.type === "resource" &&
(node.data as ResourceNodeData).resourceType === link.resource
);
if (node) {
const data = node.data as ResourceNodeData;
data.amount = Decimal.add(
data.amount,
Decimal.times(link.amount, resourceGain)
).clamp(0, data.maxAmount);
}
});
}
);
}
export default { export default {
id: "main", id: "main",
display: Main, display: Main,
@ -116,6 +182,33 @@ export default {
maxAmount: new Decimal(24 * 60 * 60) maxAmount: new Decimal(24 * 60 * 60)
} }
}, },
{
position: { x: 0, y: 0 },
type: "resource",
data: {
resourceType: "mental",
amount: new Decimal(100),
maxAmount: new Decimal(100)
}
},
{
position: { x: 0, y: 0 },
type: "resource",
data: {
resourceType: "social",
amount: new Decimal(100),
maxAmount: new Decimal(100)
}
},
{
position: { x: 0, y: 0 },
type: "resource",
data: {
resourceType: "focus",
amount: new Decimal(100),
maxAmount: new Decimal(100)
}
},
{ {
position: { x: 0, y: 150 }, position: { x: 0, y: 150 },
type: "item", type: "item",
@ -145,8 +238,48 @@ export default {
if (data.resourceType === "time") { if (data.resourceType === "time") {
return { text: formatTime(data.amount), color: "#0FF3" }; return { text: formatTime(data.amount), color: "#0FF3" };
} }
if (Decimal.eq(data.maxAmount, 100)) {
return { text: formatWhole(data.amount) + "%", color: "#0FF3" };
}
return { text: format(data.amount), color: "#0FF3" }; return { text: format(data.amount), color: "#0FF3" };
} }
if (player.layers[this.layer].boards[this.id].selectedNode == null) {
return null;
}
const selectedNode = layers[this.layer].boards!.data[this.id]
.selectedNode;
if (selectedNode.type === "resource") {
const data = selectedNode.data as ResourceNodeData;
if (data.resourceType in links) {
const link = links[data.resourceType].find(
link =>
link.resource ===
(node.data as ResourceNodeData).resourceType
);
if (link) {
let text;
if (
(node.data as ResourceNodeData).resourceType === "time"
) {
text = formatTime(link.amount);
} else if (
Decimal.eq(
(node.data as ResourceNodeData).maxAmount,
100
)
) {
text = formatWhole(link.amount) + "%";
} else {
text = format(link.amount);
}
let negativeLink = Decimal.lt(link.amount, 0);
if (link.linkType === LinkType.LossOnly) {
negativeLink = !negativeLink;
}
return { text, color: negativeLink ? "red" : "green" };
}
}
}
if (player.layers[this.layer].boards[this.id].selectedAction == null) { if (player.layers[this.layer].boards[this.id].selectedAction == null) {
return null; return null;
} }
@ -170,13 +303,7 @@ export default {
return themes[player.theme].variables["--background"]; return themes[player.theme].variables["--background"];
}, },
progressColor(node) { progressColor(node) {
const data = node.data as ResourceNodeData;
switch (data.resourceType) {
case "time":
return "#0FF3"; return "#0FF3";
default:
return "none";
}
}, },
canAccept(node, otherNode) { canAccept(node, otherNode) {
return otherNode.type === "item"; return otherNode.type === "item";
@ -189,7 +316,7 @@ export default {
(node.data as ResourceNodeData).amount = Decimal.add( (node.data as ResourceNodeData).amount = Decimal.add(
(node.data as ResourceNodeData).amount, (node.data as ResourceNodeData).amount,
(otherNode.data as ItemNodeData).amount (otherNode.data as ItemNodeData).amount
); ).min((node.data as ResourceNodeData).maxAmount);
} }
}, },
item: { item: {
@ -281,6 +408,43 @@ export default {
} }
] ]
} }
},
links() {
if (this.selectedAction?.links) {
if (typeof this.selectedAction!.links === "function") {
return this.selectedAction!.links(this.selectedNode);
}
return this.selectedAction!.links;
}
if (player.layers[this.layer].boards[this.id].selectedNode == null) {
return null;
}
const selectedNode = layers[this.layer].boards!.data[this.id].selectedNode;
if (selectedNode.type === "resource") {
const data = selectedNode.data as ResourceNodeData;
if (data.resourceType in links) {
return links[data.resourceType].map(link => {
const node = player.layers.main.boards.main.nodes.find(
node =>
node.type === "resource" &&
(node.data as ResourceNodeData).resourceType ===
link.resource
);
let negativeLink = Decimal.lt(link.amount, 0);
if (link.linkType === LinkType.LossOnly) {
negativeLink = !negativeLink;
}
return {
from: selectedNode,
to: node,
stroke: negativeLink ? "red" : "green",
"stroke-width": 4,
pulsing: true
};
});
}
}
return null;
} }
} }
} }