Some refactoring of resources

This commit is contained in:
thepaperpilot 2021-08-25 00:04:40 -05:00
parent e90aac51f2
commit e642b0e420
2 changed files with 174 additions and 128 deletions

View file

@ -2,20 +2,20 @@ import { ProgressDisplay, Shape } from "@/game/enums";
import { layers } from "@/game/layers"; import { layers } from "@/game/layers";
import player from "@/game/player"; import player from "@/game/player";
import Decimal, { DecimalSource } from "@/lib/break_eternity"; import Decimal, { DecimalSource } from "@/lib/break_eternity";
import { BoardNodeAction } from "@/typings/features/board"; import { BoardNode, BoardNodeAction } from "@/typings/features/board";
import { RawLayer } from "@/typings/layer"; import { RawLayer } from "@/typings/layer";
import { formatTime } from "@/util/bignum"; import { formatTime } from "@/util/bignum";
import { format, formatWhole } 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 { computed, watch } from "vue";
import themes from "../themes"; import themes from "../themes";
import Main from "./Main.vue"; import Main from "./Main.vue";
export type ResourceNodeData = { export type ResourceNodeData = {
resourceType: string; resourceType: string;
amount: DecimalSource; amount: DecimalSource;
maxAmount: DecimalSource; [key: string]: any;
}; };
export type ItemNodeData = { export type ItemNodeData = {
@ -92,8 +92,8 @@ enum LinkType {
// Links cause gain/loss of one resource to also affect other resources // Links cause gain/loss of one resource to also affect other resources
const links = { const links = {
time: [ time: [
{ resource: "social", amount: 1 / 60, linkType: LinkType.LossOnly }, { resource: "social", amount: 1 / (60 * 60), linkType: LinkType.LossOnly },
{ resource: "mental", amount: 1 / 120, linkType: LinkType.LossOnly } { resource: "mental", amount: 1 / (120 * 60), linkType: LinkType.LossOnly }
] ]
} as Record< } as Record<
string, string,
@ -107,41 +107,25 @@ const links = {
for (const resource in links) { for (const resource in links) {
const resourceLinks = links[resource]; const resourceLinks = links[resource];
watch( watch(
() => () => resources[resource].amount,
(player.layers.main?.boards.main.nodes.find(
node =>
node.type === "resource" &&
(node.data as ResourceNodeData).resourceType === resource
)?.data as ResourceNodeData | null)?.amount,
(amount, oldAmount) => { (amount, oldAmount) => {
if (amount == null || oldAmount == null) { if (amount == null || oldAmount == null) {
return; return;
} }
const resourceGain = Decimal.sub(amount, oldAmount); const resourceGain = Decimal.sub(amount, oldAmount);
resourceLinks.forEach(link => { resourceLinks.forEach(link => {
switch (link.linkType) { if (link.linkType === LinkType.LossOnly && Decimal.gt(amount, oldAmount)) {
case LinkType.LossOnly:
if (Decimal.gt(amount, oldAmount)) {
return; return;
} }
break; if (link.linkType === LinkType.GainOnly && Decimal.lt(amount, oldAmount)) {
case LinkType.GainOnly:
if (Decimal.lt(amount, oldAmount)) {
return; return;
} }
break; const resource = resources[link.resource];
} if (resource.amount != null) {
const node = player.layers.main.boards.main.nodes.find( resource.amount = Decimal.add(
node => resource.amount,
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) Decimal.times(link.amount, resourceGain)
).clamp(0, data.maxAmount); );
} }
}); });
} }
@ -164,6 +148,53 @@ const pinAction = {
} }
} as BoardNodeAction; } as BoardNodeAction;
type Resource = {
readonly name: string;
readonly color: string;
readonly node: BoardNode | undefined;
amount: DecimalSource | undefined;
readonly maxAmount: DecimalSource;
};
const resources = {
time: createResource("time", "#3EB48933", 24 * 60 * 60),
energy: createResource("energy", "#FFA50033", 100),
social: createResource("social", "#80008033", 100),
mental: createResource("mental", "#32CD3233", 100),
focus: createResource("focus", "#0000FF33", 100)
} as Record<string, Resource>;
function createResource(name: string, color: string, maxAmount: DecimalSource): Resource {
const node = computed(() =>
player.layers.main?.boards.main.nodes.find(
node =>
node.type === "resource" && (node.data as ResourceNodeData).resourceType === name
)
);
const data = computed(() => node.value?.data as ResourceNodeData);
return {
name,
color,
get node() {
return node.value;
},
get amount() {
return data.value?.amount;
},
set amount(amount: DecimalSource) {
data.value.amount = Decimal.clamp(amount, 0, maxAmount);
},
maxAmount
};
}
function getResource(node: BoardNode): Resource | undefined {
return Object.values(resources).find(resource => resource.node === node);
}
const selectedNode = computed(() => layers.main?.boards?.data.main.selectedNode);
const selectedAction = computed(() => layers.main?.boards?.data.main.selectedAction);
export default { export default {
id: "main", id: "main",
display: Main, display: Main,
@ -196,43 +227,40 @@ export default {
type: "resource", type: "resource",
data: { data: {
resourceType: "time", resourceType: "time",
amount: new Decimal(24 * 60 * 60), amount: new Decimal(24 * 60 * 60)
maxAmount: new Decimal(24 * 60 * 60)
} }
}, },
{ {
position: { x: 0, y: 0 }, position: { x: 300, y: 0 },
type: "resource", type: "resource",
data: { data: {
resourceType: "mental", resourceType: "mental",
amount: new Decimal(100), amount: new Decimal(100)
maxAmount: new Decimal(100)
} }
}, },
{ {
position: { x: 0, y: 0 }, position: { x: 150, y: 0 },
type: "resource", type: "resource",
data: { data: {
resourceType: "social", resourceType: "social",
amount: new Decimal(100), amount: new Decimal(100)
maxAmount: new Decimal(100)
} }
}, },
{ {
position: { x: 0, y: 0 }, position: { x: -150, y: 0 },
type: "resource", type: "resource",
data: { data: {
resourceType: "focus", resourceType: "focus",
amount: new Decimal(100), amount: new Decimal(0),
maxAmount: new Decimal(100) currentFocus: ""
} }
}, },
{ {
position: { x: 0, y: 150 }, position: { x: -300, y: 0 },
type: "item", type: "resource",
data: { data: {
itemType: "time", resourceType: "energy",
amount: new Decimal(5 * 60 * 60) amount: new Decimal(100)
} }
}, },
{ {
@ -251,48 +279,52 @@ export default {
return (node.data as ResourceNodeData).resourceType; return (node.data as ResourceNodeData).resourceType;
}, },
label(node) { label(node) {
const selectedNode = layers[this.layer].boards!.data[this.id] const resource = getResource(node)!;
.selectedNode; if (selectedNode.value != node && selectedAction.value != null) {
if ( if (resource && resource.name === "focus") {
selectedNode != node && const currentFocus =
player.layers[this.layer].boards[this.id].selectedAction != null (resource.node?.data as ResourceNodeData | undefined)
) { ?.currentFocus === selectedAction.value?.id;
const action = return {
player.layers[this.layer].boards[this.id].selectedAction; text: currentFocus ? "10%" : "X",
switch (action) { color: currentFocus ? "green" : "black",
pulsing: true
};
}
switch (selectedAction.value.id) {
case "reddit": case "reddit":
if ( switch (resource.name) {
(node.data as ResourceNodeData).resourceType === "time" case "time":
) { return {
return { text: "30m", color: "red", pulsing: true }; text: "30m",
color: "red",
pulsing: true
};
case "energy":
return {
text: "5%",
color: "green",
pulsing: true
};
} }
break; break;
} }
} }
if ( if (
selectedNode != node && selectedNode.value != node &&
selectedNode != null && selectedNode.value != null &&
selectedNode.type === "resource" selectedNode.value.type === "resource"
) { ) {
const data = selectedNode.data as ResourceNodeData; const selectedResource = getResource(selectedNode.value);
if (data.resourceType in links) { if (selectedResource && selectedResource.name in links) {
const link = links[data.resourceType].find( const link = links[selectedResource.name].find(
link => link => link.resource === resource.name
link.resource ===
(node.data as ResourceNodeData).resourceType
); );
if (link) { if (link) {
let text; let text;
if ( if (resource.name === "time") {
(node.data as ResourceNodeData).resourceType === "time"
) {
text = formatTime(link.amount); text = formatTime(link.amount);
} else if ( } else if (Decimal.eq(resource.maxAmount, 100)) {
Decimal.eq(
(node.data as ResourceNodeData).maxAmount,
100
)
) {
text = formatWhole(link.amount) + "%"; text = formatWhole(link.amount) + "%";
} else { } else {
text = format(link.amount); text = format(link.amount);
@ -305,12 +337,12 @@ export default {
} }
} }
} }
if (selectedNode == node || node.pinned) { if (selectedNode.value == node || node.pinned) {
const data = node.data as ResourceNodeData; const data = node.data as ResourceNodeData;
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)) { if (Decimal.eq(resource.maxAmount, 100)) {
return { text: formatWhole(data.amount) + "%", color: "#0FF3" }; return { text: formatWhole(data.amount) + "%", color: "#0FF3" };
} }
return { text: format(data.amount), color: "#0FF3" }; return { text: format(data.amount), color: "#0FF3" };
@ -318,27 +350,28 @@ export default {
}, },
draggable: true, draggable: true,
progress(node) { progress(node) {
const data = node.data as ResourceNodeData; const resource = getResource(node)!;
return Decimal.div(data.amount, data.maxAmount).toNumber(); return Decimal.div(resource.amount || 0, resource.maxAmount).toNumber();
}, },
fillColor() { fillColor() {
return themes[player.theme].variables["--background"]; return themes[player.theme].variables["--background"];
}, },
progressColor(node) { progressColor(node) {
return "#0FF3"; return getResource(node)!.color;
}, },
canAccept(node, otherNode) { canAccept(node, otherNode) {
return otherNode.type === "item"; return otherNode.type === "item";
}, },
onDrop(node, otherNode) { onDrop(node, otherNode) {
const resource = getResource(node)!;
const index = player.layers[this.layer].boards[this.id].nodes.indexOf( const index = player.layers[this.layer].boards[this.id].nodes.indexOf(
otherNode otherNode
); );
player.layers[this.layer].boards[this.id].nodes.splice(index, 1); player.layers[this.layer].boards[this.id].nodes.splice(index, 1);
(node.data as ResourceNodeData).amount = Decimal.add( resource.amount = Decimal.add(
(node.data as ResourceNodeData).amount, resource.amount || 0,
(otherNode.data as ItemNodeData).amount (otherNode.data as ItemNodeData).amount
).min((node.data as ResourceNodeData).maxAmount); );
}, },
actions: [pinAction] actions: [pinAction]
}, },
@ -352,10 +385,7 @@ export default {
} }
}, },
label(node) { label(node) {
if ( if (selectedNode.value == node || node.pinned) {
player.layers[this.layer].boards[this.id].selectedNode == node.id ||
node.pinned
) {
const data = node.data as ItemNodeData; const data = node.data as ItemNodeData;
if (data.itemType === "time") { if (data.itemType === "time") {
return { text: formatTime(data.amount), color: "#0FF3" }; return { text: formatTime(data.amount), color: "#0FF3" };
@ -393,23 +423,34 @@ export default {
icon: "reddit", icon: "reddit",
tooltip: "Browse Reddit", tooltip: "Browse Reddit",
onClick(node) { onClick(node) {
if (player.layers.main.boards.main.selectedAction === this.id) { if (selectedAction.value?.id === this.id) {
const timeNode = player.layers.main.boards.main.nodes.find( const focusData = resources.focus.node
node => ?.data as ResourceNodeData;
node.type === "resource" && if (focusData.currentFocus === "reddit") {
(node.data as ResourceNodeData).resourceType === resources.focus.amount = Decimal.add(
"time" resources.focus.amount || 0,
10
); );
if (timeNode) { } else {
(timeNode.data as ResourceNodeData).amount = Decimal.sub( focusData.currentFocus = "reddit";
(timeNode.data as ResourceNodeData).amount, resources.focus.amount = 10;
30 * 60 }
const focusMult = Decimal.div(
resources.focus.amount,
100
).add(1);
resources.time.amount = Decimal.sub(
resources.time.amount || 0,
Decimal.times(30 * 60, focusMult)
);
resources.energy.amount = Decimal.sub(
resources.energy.amount || 0,
Decimal.times(5, focusMult)
); );
player.layers.main.boards.main.selectedAction = null; player.layers.main.boards.main.selectedAction = null;
(node.data as ActionNodeData).log.push( (node.data as ActionNodeData).log.push(
getRandomEvent(redditEvents)! getRandomEvent(redditEvents)!
); );
}
} else { } else {
player.layers.main.boards.main.selectedAction = this.id; player.layers.main.boards.main.selectedAction = this.id;
} }
@ -417,18 +458,29 @@ export default {
links(node) { links(node) {
return [ return [
{ {
// TODO this is ridiculous and needs some utility from: resources.time.node,
// function to shrink it down
from: player.layers.main.boards.main.nodes.find(
node =>
node.type === "resource" &&
(node.data as ResourceNodeData).resourceType ===
"time"
),
to: node, to: node,
stroke: "red", stroke: "red",
"stroke-width": 4, "stroke-width": 4,
pulsing: true pulsing: true
},
{
from: resources.energy.node,
to: node,
stroke: "green",
"stroke-width": 4,
pulsing: true
},
{
from: resources.focus.node,
to: node,
stroke:
(resources.focus.node?.data as ResourceNodeData)
.currentFocus === selectedAction.value?.id
? "green"
: "black",
"stroke-width": 4,
pulsing: true
} }
]; ];
} }
@ -443,27 +495,21 @@ export default {
} }
return this.selectedAction!.links; return this.selectedAction!.links;
} }
if (player.layers[this.layer].boards[this.id].selectedNode == null) { if (selectedNode.value == null) {
return null; return null;
} }
const selectedNode = layers[this.layer].boards!.data[this.id].selectedNode; if (selectedNode.value.type === "resource") {
if (selectedNode.type === "resource") { const resource = getResource(selectedNode.value)!;
const data = selectedNode.data as ResourceNodeData; if (resource.name in links) {
if (data.resourceType in links) { return links[resource.name].map(link => {
return links[data.resourceType].map(link => { const linkResource = resources[link.resource];
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); let negativeLink = Decimal.lt(link.amount, 0);
if (link.linkType === LinkType.LossOnly) { if (link.linkType === LinkType.LossOnly) {
negativeLink = !negativeLink; negativeLink = !negativeLink;
} }
return { return {
from: selectedNode, from: selectedNode.value,
to: node, to: linkResource.node,
stroke: negativeLink ? "red" : "green", stroke: negativeLink ? "red" : "green",
"stroke-width": 4, "stroke-width": 4,
pulsing: true pulsing: true

View file

@ -65,13 +65,13 @@ export interface BoardNodeAction {
tooltip: string | ((node: BoardNode) => string); tooltip: string | ((node: BoardNode) => string);
onClick: (node: BoardNode) => boolean | undefined; onClick: (node: BoardNode) => boolean | undefined;
links?: BoardNodeLink[] | ((node: BoardNode) => BoardNodeLink[]); links?: BoardNodeLink[] | ((node: BoardNode) => BoardNodeLink[]);
[key: string]: any;
} }
export interface BoardNodeLink { export interface BoardNodeLink {
from: BoardNode; from: BoardNode;
to: BoardNode; to: BoardNode;
stroke: string; stroke: string;
strokeWidth: number | string;
pulsing?: boolean; pulsing?: boolean;
[key: string]: any; [key: string]: any;
} }