Implemented force sleep and rest actions
This commit is contained in:
parent
116e6a47ec
commit
f516a3a092
2 changed files with 207 additions and 68 deletions
|
@ -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="
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue