Some refactoring of resources
This commit is contained in:
parent
e90aac51f2
commit
e642b0e420
2 changed files with 174 additions and 128 deletions
|
@ -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
|
||||||
|
|
2
src/typings/features/board.d.ts
vendored
2
src/typings/features/board.d.ts
vendored
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue