Implemented force sleep and rest actions

This commit is contained in:
thepaperpilot 2021-08-26 22:01:56 -05:00
parent 116e6a47ec
commit f516a3a092
2 changed files with 207 additions and 68 deletions

View file

@ -1,6 +1,7 @@
<template> <template>
<g <g
class="boardnode" class="boardnode"
:class="node.type"
:style="{ opacity: dragging?.id === node.id && hasDragged ? 0.5 : 1 }" :style="{ opacity: dragging?.id === node.id && hasDragged ? 0.5 : 1 }"
:transform="`translate(${position.x},${position.y})`" :transform="`translate(${position.x},${position.y})`"
> >
@ -56,15 +57,23 @@
<g v-if="shape === Shape.Circle"> <g v-if="shape === Shape.Circle">
<circle <circle
v-if="canAccept" v-if="canAccept"
class="receiver"
:r="size + 8" :r="size + 8"
:fill="backgroundColor" :fill="backgroundColor"
:stroke="receivingNode ? '#0F0' : '#0F03'" :stroke="receivingNode ? '#0F0' : '#0F03'"
:stroke-width="2" :stroke-width="2"
/> />
<circle :r="size" :fill="fillColor" :stroke="outlineColor" :stroke-width="4" /> <circle
class="body"
:r="size"
:fill="fillColor"
:stroke="outlineColor"
:stroke-width="4"
/>
<circle <circle
class="progressFill"
v-if="progressDisplay === ProgressDisplay.Fill" v-if="progressDisplay === ProgressDisplay.Fill"
:r="Math.max(size * progress - 2, 0)" :r="Math.max(size * progress - 2, 0)"
:fill="progressColor" :fill="progressColor"
@ -85,6 +94,7 @@
<g v-else-if="shape === Shape.Diamond" transform="rotate(45, 0, 0)"> <g v-else-if="shape === Shape.Diamond" transform="rotate(45, 0, 0)">
<rect <rect
v-if="canAccept" v-if="canAccept"
class="receiver"
:width="size * sqrtTwo + 16" :width="size * sqrtTwo + 16"
:height="size * sqrtTwo + 16" :height="size * sqrtTwo + 16"
:transform=" :transform="
@ -96,6 +106,7 @@
/> />
<rect <rect
class="body"
:width="size * sqrtTwo" :width="size * sqrtTwo"
:height="size * sqrtTwo" :height="size * sqrtTwo"
:transform="`translate(${(-size * sqrtTwo) / 2}, ${(-size * sqrtTwo) / 2})`" :transform="`translate(${(-size * sqrtTwo) / 2}, ${(-size * sqrtTwo) / 2})`"
@ -106,6 +117,7 @@
<rect <rect
v-if="progressDisplay === ProgressDisplay.Fill" v-if="progressDisplay === ProgressDisplay.Fill"
class="progressFill"
:width="Math.max(size * sqrtTwo * progress - 2, 0)" :width="Math.max(size * sqrtTwo * progress - 2, 0)"
:height="Math.max(size * sqrtTwo * progress - 2, 0)" :height="Math.max(size * sqrtTwo * progress - 2, 0)"
:transform=" :transform="
@ -118,6 +130,7 @@
/> />
<rect <rect
v-else v-else
class="progressDiamond"
:width="size * sqrtTwo + 9" :width="size * sqrtTwo + 9"
:height="size * sqrtTwo + 9" :height="size * sqrtTwo + 9"
:transform=" :transform="

View file

@ -31,7 +31,7 @@ type ItemNodeData = {
display: string; display: string;
}; };
type ActionNodeData = { export type ActionNodeData = {
actionType: string; actionType: string;
log: LogEntry[]; log: LogEntry[];
}; };
@ -147,14 +147,14 @@ function createItem(resource: string, amount: DecimalSource, display?: string) {
} }
type Action = { type Action = {
icon: string; icon?: string;
fillColor?: string; fillColor?: string;
tooltip?: string; tooltip?: string;
events: Array<{ events?: Array<{
event: () => LogEntry; event: () => LogEntry;
weight: number; weight: number;
}>; }>;
baseChanges: Array<{ baseChanges?: Array<{
resource: string; resource: string;
amount: DecimalSource; amount: DecimalSource;
assign?: boolean; assign?: boolean;
@ -194,11 +194,15 @@ const actions = {
tooltip: "Sleep", tooltip: "Sleep",
events: [ events: [
{ {
event: () => ({ description: "You have a normal evening of undisturbed sleep" }), event: () => {
player.day = (player.day as Decimal).add(1);
return { description: "You have a normal evening of undisturbed sleep" };
},
weight: 90 weight: 90
}, },
{ {
event: () => { event: () => {
player.day = (player.day as Decimal).add(1);
resources.energy.amount = 50; resources.energy.amount = 50;
return { return {
description: "You had a very restless sleep filled with nightmares :(", description: "You had a very restless sleep filled with nightmares :(",
@ -211,6 +215,7 @@ const actions = {
}, },
{ {
event: () => { event: () => {
player.day = (player.day as Decimal).add(1);
createItem("energy", 25, "Refreshed"); createItem("energy", 25, "Refreshed");
return { return {
description: description:
@ -224,10 +229,28 @@ const actions = {
} }
], ],
baseChanges: [ baseChanges: [
{ resource: "time", amount: -8 * 30 * 60 }, { resource: "time", amount: 16 * 60 * 60, assign: true },
{ resource: "energy", amount: 100, assign: true } { resource: "energy", amount: 100, assign: true }
] ]
}, },
forcedSleep: {
events: [
{
event: () => {
const amount = resources.time.amount;
resources.time.amount = 16 * 60 * 60;
resources.energy.amount = Decimal.sub(100, Decimal.div(amount, 6 * 60));
resources.mental.amount = Decimal.sub(resources.mental.amount, 10);
player.day = (player.day as Decimal).add(1);
return {
description: `You passed out! That was <span style="font-style: italicize">not</span> a good night's sleep`
};
},
weight: 1
}
],
baseChanges: [{ resource: "mental", amount: -10 }]
},
rest: { rest: {
icon: "chair", icon: "chair",
tooltip: "Rest", tooltip: "Rest",
@ -259,18 +282,33 @@ const actions = {
return { return {
description: description:
"You take an incredible power nap and wake up significantly more refreshed", "You take an incredible power nap and wake up significantly more refreshed",
effectDescription: `+50% effectvie <span style="color: ${resources.energy.color};">Energy</span> restoration` effectDescription: `+50% effective <span style="color: ${resources.energy.color};">Energy</span> restoration`
}; };
}, },
weight: 5 weight: 5
} }
], ],
baseChanges: [ baseChanges: [
{ resource: "time", amount: -4 * 30 * 60 }, { resource: "time", amount: -4 * 60 * 60 },
// 30 is the lowest it can be from any event // 30 is the lowest it can be from any event
// typically you'll get 40 though // typically you'll get 40 though
{ resource: "energy", amount: 30 } { resource: "energy", amount: 30 }
] ]
},
forcedRest: {
events: [
{
event: () => ({
description: `You drag yourself to the couch before collapsing. You wake back up but still feel oddly drained`
}),
weight: 1
}
],
baseChanges: [
{ resource: "time", amount: -6 * 60 * 60 },
{ resource: "energy", amount: 30 },
{ resource: "mental", amount: -5 }
]
} }
} as Record<string, Action>; } as Record<string, Action>;
@ -378,21 +416,21 @@ const resourceNodeType = {
(resource.node.data as ResourceNodeData).currentFocus === (resource.node.data as ResourceNodeData).currentFocus ===
selectedAction.value?.id; selectedAction.value?.id;
return { return {
text: currentFocus ? "10%" : "X", text: "10%",
color: currentFocus ? "green" : "white", color: currentFocus ? "green" : "white",
pulsing: true pulsing: true
}; };
} }
const action = actions[selectedAction.value.id]; const action = actions[selectedAction.value.id];
const change = action.baseChanges.find(change => change.resource === resource.name); const change = action.baseChanges?.find(change => change.resource === resource.name);
if (change != null) { if (change != null) {
let text; let text = Decimal.gt(change.amount, 0) ? "+" : "";
if (resource.name === "time") { if (resource.name === "time") {
text = formatTime(change.amount); text += formatTime(change.amount);
} else if (Decimal.eq(resource.maxAmount, 100)) { } else if (Decimal.eq(resource.maxAmount, 100)) {
text = formatWhole(change.amount) + "%"; text += formatWhole(change.amount) + "%";
} else { } else {
text = format(change.amount); text += format(change.amount);
} }
let color; let color;
if (change.assign) { if (change.assign) {
@ -470,6 +508,44 @@ const resourceNodeType = {
actions: [pinAction] actions: [pinAction]
} as RawFeature<NodeType>; } as RawFeature<NodeType>;
function performAction(id: string, action: Action, node: BoardNode) {
if (
player.layers.main.forcedAction &&
(player.layers.main.forcedAction as { action: string }).action !== id
) {
return;
}
const focusData = resources.focus.node.data as ResourceNodeData;
if (focusData.currentFocus === id) {
resources.focus.amount = Decimal.add(resources.focus.amount, 10);
} else {
focusData.currentFocus = id;
resources.focus.amount = 10;
}
if (action.baseChanges) {
for (const change of action.baseChanges) {
if (change.assign) {
resources[change.resource].amount = change.amount;
} else if (change.resource === "time") {
// Time isn't affected by focus multiplier
resources.time.amount = Decimal.add(resources.time.amount, change.amount);
} else {
resources[change.resource].amount = Decimal.add(
resources[change.resource].amount,
Decimal.times(change.amount, focusMult.value)
);
}
}
}
player.layers.main.boards.main.selectedAction = null;
if (action.events) {
const logEntry = getRandomEvent(action.events);
if (logEntry) {
(node.data as ActionNodeData).log.push(logEntry);
}
}
}
const actionNodeType = { const actionNodeType = {
title(node) { title(node) {
return actionNodes[(node.data as ActionNodeData).actionType].display; return actionNodes[(node.data as ActionNodeData).actionType].display;
@ -484,6 +560,17 @@ const actionNodeType = {
shape: Shape.Diamond, shape: Shape.Diamond,
progressColor: "#000", progressColor: "#000",
progressDisplay: ProgressDisplay.Outline, progressDisplay: ProgressDisplay.Outline,
progress(node) {
const forcedAction = player.layers.main.forcedAction as {
resource: string;
node: number;
action: string;
progress: number;
} | null;
if (forcedAction && node.id === forcedAction.node) {
return forcedAction.progress;
}
},
actions(node) { actions(node) {
const actionNode = actionNodes[(node.data as ActionNodeData).actionType]; const actionNode = actionNodes[(node.data as ActionNodeData).actionType];
return [ return [
@ -495,38 +582,11 @@ const actionNodeType = {
icon: action.icon, icon: action.icon,
tooltip: action.tooltip, tooltip: action.tooltip,
fillColor: action.fillColor, fillColor: action.fillColor,
onClick(node) { onClick: node => {
if (selectedAction.value?.id === this.id) { if (selectedAction.value?.id === id) {
const focusData = resources.focus.node.data as ResourceNodeData; performAction(id, action, node);
if (focusData.currentFocus === id) {
resources.focus.amount = Decimal.add(resources.focus.amount, 10);
} else {
focusData.currentFocus = id;
resources.focus.amount = 10;
}
for (const change of action.baseChanges) {
if (change.assign) {
resources[change.resource].amount = change.amount;
} else if (change.resource === "time") {
// Time isn't affected by focus multiplier
resources.time.amount = Decimal.add(
resources.time.amount,
change.amount
);
} else {
resources.time.amount = Decimal.add(
resources.time.amount,
Decimal.times(change.amount, focusMult.value)
);
}
}
player.layers.main.boards.main.selectedAction = null;
const logEntry = getRandomEvent(action.events);
if (logEntry) {
(node.data as ActionNodeData).log.push(logEntry);
}
} else { } else {
player.layers.main.boards.main.selectedAction = this.id; player.layers.main.boards.main.selectedAction = id;
} }
}, },
links(node) { links(node) {
@ -542,7 +602,7 @@ const actionNodeType = {
"stroke-width": 4, "stroke-width": 4,
pulsing: true pulsing: true
}, },
...action.baseChanges.map(change => { ...(action.baseChanges || []).map(change => {
let color; let color;
if (change.assign) { if (change.assign) {
color = "white"; color = "white";
@ -565,6 +625,32 @@ const actionNodeType = {
} }
} as RawFeature<NodeType>; } as RawFeature<NodeType>;
function registerResourceDepletedAction(resource: string, nodeID: string, action: string) {
watch(
() => ({
amount: resources[resource].amount,
forcedAction: player.layers.main?.forcedAction
}),
({ amount, forcedAction }) => {
if (Decimal.eq(amount, 0) && forcedAction == null) {
player.layers.main.forcedAction = {
resource,
node: layers.main.boards!.data.main.nodes.find(
node =>
node.type === "action" &&
(node.data as ActionNodeData).actionType === nodeID
)!.id,
action,
progress: 0
};
}
}
);
}
registerResourceDepletedAction("time", "bed", "forcedSleep");
registerResourceDepletedAction("energy", "bed", "forcedRest");
export default { export default {
id: "main", id: "main",
display: Main, display: Main,
@ -572,10 +658,17 @@ export default {
startData() { startData() {
return { return {
openNode: null, openNode: null,
showModal: false showModal: false,
forcedAction: null
} as { } as {
openNode: string | null; openNode: string | null;
showModal: boolean; showModal: boolean;
forcedAction: {
resource: string;
node: number;
action: string;
progress: number;
} | null;
}; };
}, },
minimizable: false, minimizable: false,
@ -586,6 +679,25 @@ export default {
left: "0" left: "0"
} }
}, },
update(diff) {
const forcedAction = player.layers.main.forcedAction as {
resource: string;
node: number;
action: string;
progress: number;
} | null;
if (forcedAction) {
forcedAction.progress += new Decimal(diff).div(4).toNumber();
if (forcedAction.progress >= 1) {
performAction(
forcedAction.action,
actions[forcedAction.action],
this.boards!.data.main.nodes.find(node => node.id === forcedAction.node)!
);
player.layers.main.forcedAction = null;
}
}
},
boards: { boards: {
data: { data: {
main: { main: {
@ -676,35 +788,49 @@ export default {
} }
}, },
links(this: Board) { links(this: Board) {
const links: BoardNodeLink[] = [];
const forcedAction = player.layers.main.forcedAction as {
resource: string;
node: number;
action: string;
progress: number;
} | null;
if (forcedAction) {
links.push({
from: resources[forcedAction.resource].node,
to: this.nodes.find(node => node.id === forcedAction.node)!,
stroke: "black",
"stroke-width": 4
});
}
if (this.selectedNode && this.selectedAction?.links) { if (this.selectedNode && this.selectedAction?.links) {
if (typeof this.selectedAction.links === "function") { if (typeof this.selectedAction.links === "function") {
return this.selectedAction.links(this.selectedNode); return this.selectedAction.links(this.selectedNode);
} }
return this.selectedAction.links; links.push(...this.selectedAction.links);
} }
if (selectedNode.value == null) { if (selectedNode.value && selectedNode.value.type === "resource") {
return null;
}
if (selectedNode.value.type === "resource") {
const resource = getResource(selectedNode.value); const resource = getResource(selectedNode.value);
if (resource.links) { if (resource.links) {
return resource.links.map(link => { links.push(
const linkResource = resources[link.resource]; ...resource.links.map(link => {
let negativeLink = Decimal.lt(link.amount, 0); const linkResource = resources[link.resource];
if (link.linkType === LinkType.LossOnly) { let negativeLink = Decimal.lt(link.amount, 0);
negativeLink = !negativeLink; if (link.linkType === LinkType.LossOnly) {
} negativeLink = !negativeLink;
return { }
from: selectedNode.value, return {
to: linkResource.node, from: selectedNode.value,
stroke: negativeLink ? "red" : "green", to: linkResource.node,
"stroke-width": 4, stroke: negativeLink ? "red" : "green",
pulsing: true "stroke-width": 4,
}; pulsing: true
}); } as BoardNodeLink;
})
);
} }
} }
return null; return links;
} }
} }
} }