forked from profectus/Profectus
Implemented most of the basic features for new Board component
This commit is contained in:
parent
c8651adb6b
commit
d47ce3525d
13 changed files with 490 additions and 10 deletions
83
package-lock.json
generated
83
package-lock.json
generated
|
@ -13,6 +13,7 @@
|
|||
"vue": "^3.2.2",
|
||||
"vue-class-component": "^8.0.0-rc.1",
|
||||
"vue-next-select": "^2.9.0",
|
||||
"vue-panzoom": "^1.1.6",
|
||||
"vue-sortable": "github:Netbel/vue-sortable#master-fix",
|
||||
"vue-textarea-autosize": "^1.1.1",
|
||||
"vue-transition-expand": "^0.1.0"
|
||||
|
@ -14925,6 +14926,14 @@
|
|||
"integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/amator": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/amator/-/amator-1.1.0.tgz",
|
||||
"integrity": "sha1-CMa2C8k67Cthu/wMTWd9MDI8wPE=",
|
||||
"dependencies": {
|
||||
"bezier-easing": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-colors": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
|
||||
|
@ -15495,6 +15504,11 @@
|
|||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
},
|
||||
"node_modules/bezier-easing": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz",
|
||||
"integrity": "sha1-wE3+i5JtbsrKGBPWn/F5t8ICXYY="
|
||||
},
|
||||
"node_modules/bfj": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz",
|
||||
|
@ -22071,6 +22085,11 @@
|
|||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ngraph.events": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ngraph.events/-/ngraph.events-1.2.1.tgz",
|
||||
"integrity": "sha512-D4C+nXH/RFxioGXQdHu8ELDtC6EaCiNsZtih0IvyGN81OZSUby4jXoJ5+RNWasfsd0FnKxxpAROyUMzw64QNsw=="
|
||||
},
|
||||
"node_modules/nice-try": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
|
@ -22736,6 +22755,16 @@
|
|||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/panzoom": {
|
||||
"version": "9.4.2",
|
||||
"resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.2.tgz",
|
||||
"integrity": "sha512-sQLr0t6EmNFXpZHag0HQVtOKqF9xjF7iZdgWg3Ss1o7uh2QZLvcrz7S0Cl8M0d2TkPZ69JfPJdknXN3I0e/2aQ==",
|
||||
"dependencies": {
|
||||
"amator": "^1.1.0",
|
||||
"ngraph.events": "^1.2.1",
|
||||
"wheel": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/parallel-transform": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
|
||||
|
@ -27245,6 +27274,14 @@
|
|||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-panzoom": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/vue-panzoom/-/vue-panzoom-1.1.6.tgz",
|
||||
"integrity": "sha512-yEE60C/gnc5NGL6YBD++CErD820va7fkBJE5dCWZZzXX2aMGklj/UKmtqu1u5xDkuOIjnGUr412LNHwOOE711w==",
|
||||
"dependencies": {
|
||||
"panzoom": "^9.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-sortable": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "git+ssh://git@github.com/Netbel/vue-sortable.git#f4d4870ace71ea59bd79252eb2ec1cf6bfb02fe7",
|
||||
|
@ -28083,6 +28120,11 @@
|
|||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wheel": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wheel/-/wheel-1.0.0.tgz",
|
||||
"integrity": "sha512-XiCMHibOiqalCQ+BaNSwRoZ9FDTAvOsXxGHXChBugewDj7HC8VBIER71dEOiRH1fSdLbRCQzngKTSiZ06ZQzeA=="
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||
|
@ -31140,6 +31182,14 @@
|
|||
"integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
|
||||
"dev": true
|
||||
},
|
||||
"amator": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/amator/-/amator-1.1.0.tgz",
|
||||
"integrity": "sha1-CMa2C8k67Cthu/wMTWd9MDI8wPE=",
|
||||
"requires": {
|
||||
"bezier-easing": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"ansi-colors": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
|
||||
|
@ -31576,6 +31626,11 @@
|
|||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
},
|
||||
"bezier-easing": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz",
|
||||
"integrity": "sha1-wE3+i5JtbsrKGBPWn/F5t8ICXYY="
|
||||
},
|
||||
"bfj": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz",
|
||||
|
@ -36803,6 +36858,11 @@
|
|||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
||||
"dev": true
|
||||
},
|
||||
"ngraph.events": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ngraph.events/-/ngraph.events-1.2.1.tgz",
|
||||
"integrity": "sha512-D4C+nXH/RFxioGXQdHu8ELDtC6EaCiNsZtih0IvyGN81OZSUby4jXoJ5+RNWasfsd0FnKxxpAROyUMzw64QNsw=="
|
||||
},
|
||||
"nice-try": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
|
@ -37323,6 +37383,16 @@
|
|||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||
"dev": true
|
||||
},
|
||||
"panzoom": {
|
||||
"version": "9.4.2",
|
||||
"resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.2.tgz",
|
||||
"integrity": "sha512-sQLr0t6EmNFXpZHag0HQVtOKqF9xjF7iZdgWg3Ss1o7uh2QZLvcrz7S0Cl8M0d2TkPZ69JfPJdknXN3I0e/2aQ==",
|
||||
"requires": {
|
||||
"amator": "^1.1.0",
|
||||
"ngraph.events": "^1.2.1",
|
||||
"wheel": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"parallel-transform": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
|
||||
|
@ -41002,6 +41072,14 @@
|
|||
"integrity": "sha512-GjX4pHqZXXitquDeSAtLaf85jXdMUOKyCNzo+EF3xRr4DebGwbST4CtmRvL0TX3EhwLHQjUlAc3JcJX+azpLHg==",
|
||||
"requires": {}
|
||||
},
|
||||
"vue-panzoom": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/vue-panzoom/-/vue-panzoom-1.1.6.tgz",
|
||||
"integrity": "sha512-yEE60C/gnc5NGL6YBD++CErD820va7fkBJE5dCWZZzXX2aMGklj/UKmtqu1u5xDkuOIjnGUr412LNHwOOE711w==",
|
||||
"requires": {
|
||||
"panzoom": "^9.4.1"
|
||||
}
|
||||
},
|
||||
"vue-sortable": {
|
||||
"version": "git+ssh://git@github.com/Netbel/vue-sortable.git#f4d4870ace71ea59bd79252eb2ec1cf6bfb02fe7",
|
||||
"from": "vue-sortable@github:Netbel/vue-sortable#master-fix",
|
||||
|
@ -41687,6 +41765,11 @@
|
|||
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
|
||||
"dev": true
|
||||
},
|
||||
"wheel": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wheel/-/wheel-1.0.0.tgz",
|
||||
"integrity": "sha512-XiCMHibOiqalCQ+BaNSwRoZ9FDTAvOsXxGHXChBugewDj7HC8VBIER71dEOiRH1fSdLbRCQzngKTSiZ06ZQzeA=="
|
||||
},
|
||||
"which": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
"vue": "^3.2.2",
|
||||
"vue-class-component": "^8.0.0-rc.1",
|
||||
"vue-next-select": "^2.9.0",
|
||||
"vue-panzoom": "^1.1.6",
|
||||
"vue-sortable": "github:Netbel/vue-sortable#master-fix",
|
||||
"vue-textarea-autosize": "^1.1.1",
|
||||
"vue-transition-expand": "^0.1.0"
|
||||
|
|
80
src/components/board/Board.vue
Normal file
80
src/components/board/Board.vue
Normal file
|
@ -0,0 +1,80 @@
|
|||
<template>
|
||||
<panZoom
|
||||
:style="style"
|
||||
selector="#g1"
|
||||
@init="onInit"
|
||||
:options="{ initialZoom: 1, minZoom: 0.1, maxZoom: 10 }"
|
||||
ref="stage"
|
||||
>
|
||||
<svg class="stage" width="100%" height="100%">
|
||||
<g id="g1">
|
||||
<BoardNode
|
||||
v-for="(node, nodeIndex) in nodes"
|
||||
:key="nodeIndex"
|
||||
:index="nodeIndex"
|
||||
:node="node"
|
||||
:nodeType="board.types[node.type]"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</panZoom>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { layers } from "@/game/layers";
|
||||
import player from "@/game/player";
|
||||
import { Board } from "@/typings/features/board";
|
||||
import { InjectLayerMixin } from "@/util/vue";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Board",
|
||||
mixins: [InjectLayerMixin],
|
||||
props: {
|
||||
id: {
|
||||
type: [Number, String],
|
||||
required: true
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
getZoomLevel: () => (this.$refs.stage as any).$panZoomInstance.getTransform().scale
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
board(): Board {
|
||||
return layers[this.layer].boards!.data[this.id];
|
||||
},
|
||||
style(): Array<Partial<CSSStyleDeclaration> | undefined> {
|
||||
return [
|
||||
{
|
||||
width: this.board.width,
|
||||
height: this.board.height
|
||||
},
|
||||
layers[this.layer].componentStyles?.board,
|
||||
this.board.style
|
||||
];
|
||||
},
|
||||
nodes() {
|
||||
return player.layers[this.layer].boards[this.id];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onInit: function(panzoomInstance) {
|
||||
panzoomInstance.setTransformOrigin(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.vue-pan-zoom-scene {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
#g1 {
|
||||
transition-duration: 0s;
|
||||
}
|
||||
</style>
|
203
src/components/board/BoardNode.vue
Normal file
203
src/components/board/BoardNode.vue
Normal file
|
@ -0,0 +1,203 @@
|
|||
<template>
|
||||
<g
|
||||
class="boardnode"
|
||||
:style="{ opacity: dragging ? 0.5 : 1 }"
|
||||
:transform="`translate(${position.x},${position.y})`"
|
||||
@mousedown="mouseDown"
|
||||
>
|
||||
<circle :r="size + 8" :fill="backgroundColor" stroke="#0F03" :stroke-width="2" />
|
||||
|
||||
<circle :r="size" :fill="fillColor" :stroke="outlineColor" :stroke-width="4" />
|
||||
|
||||
<circle
|
||||
v-if="progressDisplay === ProgressDisplay.Fill"
|
||||
:r="size * progress"
|
||||
:fill="progressColor"
|
||||
/>
|
||||
<circle
|
||||
v-else
|
||||
:r="size + 4.5"
|
||||
class="progressRing"
|
||||
fill="transparent"
|
||||
:stroke-dasharray="(size + 4.5) * 2 * Math.PI"
|
||||
:stroke-width="5"
|
||||
:stroke-dashoffset="(size + 4.5) * 2 * Math.PI - progress * (size + 4.5) * 2 * Math.PI"
|
||||
:stroke="progressColor"
|
||||
/>
|
||||
|
||||
<text :fill="titleColor" class="node-title">{{ title }}</text>
|
||||
</g>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import themes from "@/data/themes";
|
||||
import { ProgressDisplay } from "@/game/enums";
|
||||
import player from "@/game/player";
|
||||
import { BoardNode, NodeType } from "@/typings/features/board";
|
||||
import { InjectLayerMixin } from "@/util/vue";
|
||||
import { defineComponent, PropType } from "vue";
|
||||
|
||||
// TODO will blindly use any T given (can't restrict it to S[R] because I can't figure out how
|
||||
// to make it support narrowing the return type)
|
||||
function getTypeProperty<T, S extends NodeType, R extends keyof S>(
|
||||
nodeType: S,
|
||||
node: BoardNode,
|
||||
property: R
|
||||
): S[R] extends Pick<
|
||||
S,
|
||||
{
|
||||
[K in keyof S]-?: undefined extends S[K] ? never : K;
|
||||
}[keyof S]
|
||||
>
|
||||
? T
|
||||
: T | undefined {
|
||||
return typeof nodeType[property] === "function"
|
||||
? (nodeType[property] as (node: BoardNode) => T)(node)
|
||||
: (nodeType[property] as T);
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: "BoardNode",
|
||||
mixins: [InjectLayerMixin],
|
||||
inject: ["getZoomLevel"],
|
||||
data() {
|
||||
return {
|
||||
ProgressDisplay,
|
||||
lastMousePosition: { x: 0, y: 0 },
|
||||
dragged: { x: 0, y: 0 },
|
||||
dragging: false
|
||||
};
|
||||
},
|
||||
props: {
|
||||
index: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
node: {
|
||||
type: Object as PropType<BoardNode>,
|
||||
required: true
|
||||
},
|
||||
nodeType: {
|
||||
type: Object as PropType<NodeType>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
draggable(): boolean {
|
||||
return getTypeProperty(this.nodeType, this.node, "draggable");
|
||||
},
|
||||
position(): { x: number; y: number } {
|
||||
return this.draggable && this.dragging
|
||||
? {
|
||||
x: this.node.position.x + Math.round(this.dragged.x / 25) * 25,
|
||||
y: this.node.position.y + Math.round(this.dragged.y / 25) * 25
|
||||
}
|
||||
: this.node.position;
|
||||
},
|
||||
size(): number {
|
||||
return getTypeProperty(this.nodeType, this.node, "size");
|
||||
},
|
||||
title(): string {
|
||||
return getTypeProperty(this.nodeType, this.node, "title");
|
||||
},
|
||||
progress(): number {
|
||||
return getTypeProperty(this.nodeType, this.node, "progress") || 0;
|
||||
},
|
||||
backgroundColor(): string {
|
||||
return themes[player.theme].variables["--background"];
|
||||
},
|
||||
outlineColor(): string {
|
||||
return (
|
||||
getTypeProperty(this.nodeType, this.node, "outlineColor") ||
|
||||
themes[player.theme].variables["--separator"]
|
||||
);
|
||||
},
|
||||
fillColor(): string {
|
||||
return (
|
||||
getTypeProperty(this.nodeType, this.node, "fillColor") ||
|
||||
themes[player.theme].variables["--secondary-background"]
|
||||
);
|
||||
},
|
||||
progressColor(): string {
|
||||
return getTypeProperty(this.nodeType, this.node, "progressColor") || "none";
|
||||
},
|
||||
titleColor(): string {
|
||||
return (
|
||||
getTypeProperty(this.nodeType, this.node, "titleColor") ||
|
||||
themes[player.theme].variables["--color"]
|
||||
);
|
||||
},
|
||||
progressDisplay(): ProgressDisplay {
|
||||
return (
|
||||
getTypeProperty(this.nodeType, this.node, "progressDisplay") ||
|
||||
ProgressDisplay.Outline
|
||||
);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
mouseDown(e: MouseEvent) {
|
||||
if (this.draggable) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
this.lastMousePosition = {
|
||||
x: e.clientX,
|
||||
y: e.clientY
|
||||
};
|
||||
this.dragged = { x: 0, y: 0 };
|
||||
|
||||
this.dragging = true;
|
||||
document.onmouseup = this.mouseUp;
|
||||
document.onmousemove = this.mouseMove;
|
||||
}
|
||||
},
|
||||
mouseMove(e: MouseEvent) {
|
||||
if (this.draggable && this.dragging) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const zoom = (this.getZoomLevel as () => number)();
|
||||
console.log(zoom);
|
||||
this.dragged.x += (e.clientX - this.lastMousePosition.x) / zoom;
|
||||
this.dragged.y += (e.clientY - this.lastMousePosition.y) / zoom;
|
||||
this.lastMousePosition = {
|
||||
x: e.clientX,
|
||||
y: e.clientY
|
||||
};
|
||||
}
|
||||
},
|
||||
mouseUp(e: MouseEvent) {
|
||||
if (this.draggable && this.dragging) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
let node = player.layers[this.nodeType.layer].boards[this.nodeType.id][this.index];
|
||||
node.position.x += Math.round(this.dragged.x / 25) * 25;
|
||||
node.position.y += Math.round(this.dragged.y / 25) * 25;
|
||||
|
||||
this.dragging = false;
|
||||
document.onmouseup = null;
|
||||
document.onmousemove = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.boardnode {
|
||||
cursor: pointer;
|
||||
transition-duration: 0s;
|
||||
}
|
||||
|
||||
.node-title {
|
||||
text-anchor: middle;
|
||||
dominant-baseline: middle;
|
||||
font-family: monospace;
|
||||
font-size: 200%;
|
||||
}
|
||||
|
||||
.progressRing {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
</style>
|
|
@ -6,6 +6,7 @@ import VueTextareaAutosize from "vue-textarea-autosize";
|
|||
import Sortable from "vue-sortable";
|
||||
import VueNextSelect from "vue-next-select";
|
||||
import "vue-next-select/dist/index.css";
|
||||
import panZoom from "vue-panzoom";
|
||||
import { App } from "vue";
|
||||
|
||||
export function registerComponents(vue: App): void {
|
||||
|
@ -23,4 +24,5 @@ export function registerComponents(vue: App): void {
|
|||
vue.use(VueTextareaAutosize);
|
||||
vue.use(Sortable);
|
||||
vue.component("vue-select", VueNextSelect);
|
||||
vue.use(panZoom);
|
||||
}
|
||||
|
|
|
@ -28,3 +28,8 @@ export enum ImportingStatus {
|
|||
WrongID = "WRONG_ID",
|
||||
Force = "FORCE"
|
||||
}
|
||||
|
||||
export enum ProgressDisplay {
|
||||
Outline = "Outline",
|
||||
Fill = "Fill"
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { CacheableFunction } from "@/typings/cacheableFunction";
|
||||
import { Achievement } from "@/typings/features/achievement";
|
||||
import { Board } from "@/typings/features/board";
|
||||
import { Buyable } from "@/typings/features/buyable";
|
||||
import { Challenge } from "@/typings/features/challenge";
|
||||
import { Clickable } from "@/typings/features/clickable";
|
||||
|
@ -23,6 +24,7 @@ import Decimal, { DecimalSource } from "@/util/bignum";
|
|||
import { isFunction } from "@/util/common";
|
||||
import {
|
||||
defaultLayerProperties,
|
||||
getStartingBoards,
|
||||
getStartingBuyables,
|
||||
getStartingChallenges,
|
||||
getStartingClickables,
|
||||
|
@ -32,6 +34,7 @@ import { createGridProxy, createLayerProxy } from "@/util/proxies";
|
|||
import { applyPlayerData } from "@/util/save";
|
||||
import clone from "lodash.clonedeep";
|
||||
import { isRef } from "vue";
|
||||
import { ProgressDisplay } from "./enums";
|
||||
import { default as playerProxy } from "./player";
|
||||
|
||||
export const layers: Record<string, Readonly<Layer>> = {};
|
||||
|
@ -70,6 +73,7 @@ export function addLayer(layer: RawLayer, player?: Partial<PlayerData>): void {
|
|||
buyables: getStartingBuyables(layer.buyables?.data),
|
||||
clickables: getStartingClickables(layer.clickables?.data),
|
||||
challenges: getStartingChallenges(layer.challenges?.data),
|
||||
boards: getStartingBoards(layer.boards?.data),
|
||||
grids: {},
|
||||
confirmRespecBuyables: false,
|
||||
...(layer.startData?.() || {})
|
||||
|
@ -423,6 +427,31 @@ export function addLayer(layer: RawLayer, player?: Partial<PlayerData>): void {
|
|||
layer.grids.data[id] = createGridProxy(layer.grids.data[id]) as Grid;
|
||||
}
|
||||
}
|
||||
if (layer.boards) {
|
||||
setupFeatures<NonNullable<RawLayer["boards"]>, Board>(layer.id, layer.boards);
|
||||
for (const id in layer.boards.data) {
|
||||
setDefault(layer.boards.data[id], "width", "100%");
|
||||
setDefault(layer.boards.data[id], "height", "400px");
|
||||
for (const nodeType in layer.boards.data[id].types) {
|
||||
layer.boards.data[id].types[nodeType].layer = layer.id;
|
||||
layer.boards.data[id].types[nodeType].id = id;
|
||||
layer.boards.data[id].types[nodeType].type = nodeType;
|
||||
setDefault(layer.boards.data[id].types[nodeType], "size", 50);
|
||||
setDefault(layer.boards.data[id].types[nodeType], "draggable", false);
|
||||
setDefault(layer.boards.data[id].types[nodeType], "canAccept", false);
|
||||
setDefault(
|
||||
layer.boards.data[id].types[nodeType],
|
||||
"progressDisplay",
|
||||
ProgressDisplay.Fill
|
||||
);
|
||||
setDefault(layer.boards.data[id].types[nodeType], "nodes", function() {
|
||||
return playerProxy.layers[this.layer].boards[this.id].filter(
|
||||
node => node.type === this.type
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layer.subtabs) {
|
||||
layer.activeSubtab = function() {
|
||||
if (
|
||||
|
|
45
src/typings/features/board.d.ts
vendored
Normal file
45
src/typings/features/board.d.ts
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
import { State } from "../state";
|
||||
import { Feature, RawFeature } from "./feature";
|
||||
|
||||
export interface BoardNode {
|
||||
position: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
type: string;
|
||||
data?: State;
|
||||
}
|
||||
|
||||
export interface CardOption {
|
||||
text: string;
|
||||
selected: (node: BoardNode) => void;
|
||||
}
|
||||
|
||||
export interface Board extends Feature {
|
||||
startNodes: () => BoardNode[];
|
||||
style?: Partial<CSSStyleDeclaration>;
|
||||
height: string;
|
||||
width: string;
|
||||
types: Record<string, NodeType>;
|
||||
}
|
||||
|
||||
export type RawBoard = Omit<RawFeature<Board>, "types"> & {
|
||||
startNodes: () => BoardNode[];
|
||||
types: Record<string, RawFeature<NodeType>>;
|
||||
};
|
||||
|
||||
export interface NodeType extends Feature {
|
||||
tooltip?: string | ((node: BoardNode) => string);
|
||||
title: string | ((node: BoardNode) => string);
|
||||
size: number | ((node: BoardNode) => number);
|
||||
draggable: boolean | ((node: BoardNode) => boolean);
|
||||
canAccept: boolean | ((node: BoardNode, otherNode: BoardNode) => boolean);
|
||||
progress?: number | ((node: BoardNode) => number);
|
||||
progressDisplay: ProgressDisplay | ((node: BoardNode) => ProgressDisplay);
|
||||
progressColor: string | ((node: BoardNode) => string);
|
||||
fillColor?: string | ((node: BoardNode) => string);
|
||||
outlineColor?: string | ((node: BoardNode) => string);
|
||||
titleColor?: string | ((node: BoardNode) => string);
|
||||
onClick: (node: BoardNode) => void;
|
||||
nodes: BoardNode[];
|
||||
}
|
4
src/typings/layer.d.ts
vendored
4
src/typings/layer.d.ts
vendored
|
@ -3,6 +3,7 @@ import Decimal, { DecimalSource } from "@/util/bignum";
|
|||
import { CoercableComponent } from "./component";
|
||||
import { Achievement } from "./features/achievement";
|
||||
import { Bar } from "./features/bar";
|
||||
import { Board, RawBoard } from "./features/board";
|
||||
import { Buyable } from "./features/buyable";
|
||||
import { Challenge } from "./features/challenge";
|
||||
import { Clickable } from "./features/clickable";
|
||||
|
@ -31,6 +32,7 @@ export interface RawLayer extends RawFeature<Layer> {
|
|||
challenges?: RawGridFeatures<NonNullable<Layer["challenges"]>, Challenge>;
|
||||
clickables?: RawGridFeatures<NonNullable<Layer["clickables"]>, Clickable>;
|
||||
grids?: RawFeatures<NonNullable<Layer["grids"]>, Grid>;
|
||||
boards?: RawFeatures<NonNullable<Layer["boards"]>, Board, RawBoard>;
|
||||
hotkeys?: RawFeature<Hotkey>[];
|
||||
infoboxes?: RawFeatures<NonNullable<Layer["infoboxes"]>, Infoboxe>;
|
||||
milestones?: RawFeatures<NonNullable<Layer["milestones"]>, Milestone>;
|
||||
|
@ -108,6 +110,7 @@ export interface Layer extends Feature {
|
|||
showMasterButton?: boolean;
|
||||
};
|
||||
grids?: Features<Grid>;
|
||||
boards?: Features<Board>;
|
||||
hotkeys?: Hotkey[];
|
||||
infoboxes?: Features<Infobox>;
|
||||
milestones?: Features<Milestone>;
|
||||
|
@ -142,5 +145,6 @@ export interface ComponentStyles {
|
|||
"prestige-button"?: Partial<CSSStyleDeclaration>;
|
||||
"respec-button"?: Partial<CSSStyleDeclaration>;
|
||||
upgrade?: Partial<CSSStyleDeclaration>;
|
||||
board?: Partial<CSSStyleDeclaration>;
|
||||
"tab-button"?: Partial<CSSStyleDeclaration>;
|
||||
}
|
||||
|
|
18
src/typings/player.d.ts
vendored
18
src/typings/player.d.ts
vendored
|
@ -1,6 +1,7 @@
|
|||
import { Themes } from "@/data/themes";
|
||||
import { DecimalSource } from "@/lib/break_eternity";
|
||||
import Decimal from "@/util/bignum";
|
||||
import { BoardNode } from "./features/board";
|
||||
import { MilestoneDisplay } from "./features/milestone";
|
||||
import { State } from "./state";
|
||||
|
||||
|
@ -53,14 +54,15 @@ export interface LayerSaveData {
|
|||
unlockOrder?: number;
|
||||
forceTooltip?: boolean;
|
||||
resetTime: Decimal;
|
||||
upgrades: Array<string | number>;
|
||||
achievements: Array<string | number>;
|
||||
milestones: Array<string | number>;
|
||||
infoboxes: Record<string | number, boolean>;
|
||||
buyables: Record<string | number, Decimal>;
|
||||
clickables: Record<string | number, State>;
|
||||
challenges: Record<string | number, Decimal>;
|
||||
grids: Record<string | number, Record<string, number, State>>;
|
||||
upgrades: Array<string>;
|
||||
achievements: Array<string>;
|
||||
milestones: Array<string>;
|
||||
infoboxes: Record<string, boolean>;
|
||||
buyables: Record<string, Decimal>;
|
||||
clickables: Record<string, State>;
|
||||
challenges: Record<string, Decimal>;
|
||||
grids: Record<string, Record<string, State>>;
|
||||
boards: Record<string, Array<BoardNode>>;
|
||||
confirmRespecBuyables: boolean;
|
||||
[index: string]: unknown;
|
||||
}
|
||||
|
|
14
src/typings/theme.d.ts
vendored
14
src/typings/theme.d.ts
vendored
|
@ -1,6 +1,18 @@
|
|||
export interface Theme {
|
||||
variables: {
|
||||
[index: string]: string;
|
||||
"--background": string;
|
||||
"--background-tooltip": string;
|
||||
"--secondary-background": string;
|
||||
"--color": string;
|
||||
"--points": string;
|
||||
"--locked": string;
|
||||
"--bought": string;
|
||||
"--link": string;
|
||||
"--separator": string;
|
||||
"--border-radius": string;
|
||||
"--danger": string;
|
||||
"--modal-border": string;
|
||||
"--feature-margin": string;
|
||||
};
|
||||
stackedInfoboxes: boolean;
|
||||
floatingTabs: boolean;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { hotkeys, layers } from "@/game/layers";
|
||||
import player from "@/game/player";
|
||||
import { CacheableFunction } from "@/typings/cacheableFunction";
|
||||
import { Board, BoardNode, RawBoard } from "@/typings/features/board";
|
||||
import { Buyable } from "@/typings/features/buyable";
|
||||
import { Challenge } from "@/typings/features/challenge";
|
||||
import { Clickable } from "@/typings/features/clickable";
|
||||
|
@ -70,6 +71,20 @@ export function getStartingChallenges(
|
|||
: {};
|
||||
}
|
||||
|
||||
export function getStartingBoards(
|
||||
boards?: Record<string, Board> | Record<string, RawBoard> | undefined
|
||||
): Record<string, Array<BoardNode>> {
|
||||
return boards
|
||||
? Object.keys(boards).reduce((acc: Record<string, Array<BoardNode>>, curr: string): Record<
|
||||
string,
|
||||
Array<BoardNode>
|
||||
> => {
|
||||
acc[curr] = boards[curr].startNodes?.() || [];
|
||||
return acc;
|
||||
}, {})
|
||||
: {};
|
||||
}
|
||||
|
||||
export function resetLayerData(layer: string, keep: Array<string> = []): void {
|
||||
keep.push("unlocked", "forceTooltip", "noRespecConfirm");
|
||||
const keptData = keep.reduce((acc: Record<string, any>, curr: string): Record<string, any> => {
|
||||
|
|
|
@ -13,7 +13,6 @@ export function createLayerProxy(object: Record<string, any>): Record<string, an
|
|||
return objectProxy;
|
||||
}
|
||||
|
||||
// TODO cache grid values? Currently they'll be calculated every render they're visible
|
||||
export function createGridProxy(object: Record<string, any>): Record<string, any> {
|
||||
if (object.isProxy) {
|
||||
console.warn(
|
||||
|
|
Loading…
Reference in a new issue