mirror of
https://github.com/thepaperpilot/Planar-Pioneers.git
synced 2025-04-01 13:31:07 +00:00
Making many design changes
This commit is contained in:
parent
2f97dbc58d
commit
286341e054
3 changed files with 181 additions and 75 deletions
|
@ -1,4 +1,15 @@
|
||||||
.tooltip-inline-container,
|
.nav-container {
|
||||||
.tooltip-inline-container > .tooltip-container {
|
margin-top: -50px;
|
||||||
display: inline;
|
text-align: left;
|
||||||
|
border-bottom: solid 1px var(--outline);
|
||||||
|
margin-left: -10px;
|
||||||
|
margin-right: -10px;
|
||||||
|
padding: 10px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-segment {
|
||||||
|
border-right: solid 1px var(--outline);
|
||||||
|
padding-right: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import Modal from "components/Modal.vue";
|
||||||
import StickyVue from "components/layout/Sticky.vue";
|
import StickyVue from "components/layout/Sticky.vue";
|
||||||
import {
|
import {
|
||||||
BoardNode,
|
BoardNode,
|
||||||
|
@ -7,26 +8,26 @@ import {
|
||||||
getUniqueNodeID
|
getUniqueNodeID
|
||||||
} from "features/boards/board";
|
} from "features/boards/board";
|
||||||
import { jsx } from "features/feature";
|
import { jsx } from "features/feature";
|
||||||
import MainDisplay from "features/resources/MainDisplay.vue";
|
|
||||||
import { createResource, displayResource } from "features/resources/resource";
|
import { createResource, displayResource } from "features/resources/resource";
|
||||||
import TooltipVue from "features/tooltips/Tooltip.vue";
|
import { createTabFamily } from "features/tabs/tabFamily";
|
||||||
import Formula, { calculateCost } from "game/formulas/formulas";
|
import Formula, { calculateCost } from "game/formulas/formulas";
|
||||||
import type { BaseLayer, GenericLayer } from "game/layers";
|
import type { BaseLayer, GenericLayer } from "game/layers";
|
||||||
import { createLayer } from "game/layers";
|
import { createLayer } from "game/layers";
|
||||||
import {
|
import { createMultiplicativeModifier, createSequentialModifier } from "game/modifiers";
|
||||||
createModifierSection,
|
|
||||||
createMultiplicativeModifier,
|
|
||||||
createSequentialModifier
|
|
||||||
} from "game/modifiers";
|
|
||||||
import { State } from "game/persistence";
|
import { State } from "game/persistence";
|
||||||
import type { Player } from "game/player";
|
import type { Player } from "game/player";
|
||||||
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 { format, formatTime, formatWhole } from "util/bignum";
|
import { format, formatWhole } from "util/bignum";
|
||||||
import { Direction } from "util/common";
|
import { camelToTitle } from "util/common";
|
||||||
import { render } from "util/vue";
|
import { render } from "util/vue";
|
||||||
import { ComputedRef, computed, reactive } from "vue";
|
import { ComputedRef, computed, nextTick, reactive, ref, watch } from "vue";
|
||||||
|
import { useToast } from "vue-toastification";
|
||||||
|
import { createCollapsibleModifierSections } from "./common";
|
||||||
import "./main.css";
|
import "./main.css";
|
||||||
|
import settings from "game/settings";
|
||||||
|
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
export interface ResourceState {
|
export interface ResourceState {
|
||||||
type: Resources;
|
type: Resources;
|
||||||
|
@ -61,21 +62,44 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
const energy = createResource<DecimalSource>(0, "energy");
|
const energy = createResource<DecimalSource>(0, "energy");
|
||||||
|
|
||||||
const resourceLevelFormula = Formula.variable(0).add(1);
|
const resourceLevelFormula = Formula.variable(0).add(1);
|
||||||
function getResourceLevelProgress(amount: DecimalSource) {
|
|
||||||
// Sub 10 and then manually sum until we go over amount
|
const resourceNodes: ComputedRef<Record<Resources, BoardNode>> = computed(() =>
|
||||||
let currentLevel = Decimal.floor(resourceLevelFormula.invertIntegral(amount))
|
board.nodes.value.reduce((acc, curr) => {
|
||||||
.sub(10)
|
if (curr.type === "resource") {
|
||||||
.clampMin(0);
|
acc[(curr.state as unknown as ResourceState).type] = curr;
|
||||||
let summedCost = calculateCost(resourceLevelFormula, currentLevel, true, 0);
|
|
||||||
while (true) {
|
|
||||||
const nextCost = resourceLevelFormula.evaluate(currentLevel);
|
|
||||||
if (Decimal.add(summedCost, nextCost).lte(amount)) {
|
|
||||||
currentLevel = currentLevel.add(1);
|
|
||||||
summedCost = Decimal.add(summedCost, nextCost);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
return acc;
|
||||||
|
}, {} as Record<Resources, BoardNode>)
|
||||||
|
);
|
||||||
|
|
||||||
|
const resourceLevels = computed(() =>
|
||||||
|
resourceNames.reduce((acc, curr) => {
|
||||||
|
const amount =
|
||||||
|
(resourceNodes.value[curr]?.state as unknown as ResourceState | undefined)
|
||||||
|
?.amount ?? 0;
|
||||||
|
// Sub 10 and then manually sum until we go over amount
|
||||||
|
let currentLevel = Decimal.floor(resourceLevelFormula.invertIntegral(amount))
|
||||||
|
.sub(10)
|
||||||
|
.clampMin(0);
|
||||||
|
let summedCost = calculateCost(resourceLevelFormula, currentLevel, true, 0);
|
||||||
|
while (true) {
|
||||||
|
const nextCost = resourceLevelFormula.evaluate(currentLevel);
|
||||||
|
if (Decimal.add(summedCost, nextCost).lte(amount)) {
|
||||||
|
currentLevel = currentLevel.add(1);
|
||||||
|
summedCost = Decimal.add(summedCost, nextCost);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc[curr] = currentLevel;
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<Resources, DecimalSource>)
|
||||||
|
);
|
||||||
|
function getResourceLevelProgress(resource: Resources) {
|
||||||
|
const amount =
|
||||||
|
(resourceNodes.value[resource]?.state as unknown as ResourceState | undefined)
|
||||||
|
?.amount ?? 0;
|
||||||
|
const currentLevel = resourceLevels.value[resource];
|
||||||
const requiredForCurrentLevel = calculateCost(resourceLevelFormula, currentLevel, true);
|
const requiredForCurrentLevel = calculateCost(resourceLevelFormula, currentLevel, true);
|
||||||
const requiredForNextLevel = calculateCost(
|
const requiredForNextLevel = calculateCost(
|
||||||
resourceLevelFormula,
|
resourceLevelFormula,
|
||||||
|
@ -90,20 +114,71 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
|
|
||||||
const resourceMinedCooldown: Partial<Record<Resources, number>> = reactive({});
|
const resourceMinedCooldown: Partial<Record<Resources, number>> = reactive({});
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
resourceNames.forEach(resource => {
|
||||||
|
watch(
|
||||||
|
() => resourceLevels.value[resource],
|
||||||
|
(level, prevLevel) => {
|
||||||
|
if (Decimal.gt(level, prevLevel) && settings.active === player.id) {
|
||||||
|
toast.info(
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
{Decimal.eq(level, 1)
|
||||||
|
? `${camelToTitle(resource)} discovered`
|
||||||
|
: `${camelToTitle(resource)} is now Level ${formatWhole(
|
||||||
|
level
|
||||||
|
)}`}
|
||||||
|
!
|
||||||
|
</h3>
|
||||||
|
<div>Energy gain is now 1.01x higher.</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const board = createBoard(board => ({
|
const board = createBoard(board => ({
|
||||||
startNodes: () => [{ position: { x: 0, y: 0 }, type: "mine", state: 0 }],
|
startNodes: () => [
|
||||||
|
{ position: { x: 0, y: 0 }, type: "mine", state: 0 },
|
||||||
|
{ position: { x: 400, y: -400 }, type: "brokenFactory" }
|
||||||
|
],
|
||||||
types: {
|
types: {
|
||||||
mine: {
|
mine: {
|
||||||
shape: Shape.Diamond,
|
shape: Shape.Diamond,
|
||||||
size: 50,
|
size: 50,
|
||||||
title: "Mine",
|
title: "🪨",
|
||||||
label: node => (node === board.selectedNode.value ? null : { text: "Click me!" }),
|
label: node =>
|
||||||
|
node === board.selectedNode.value
|
||||||
|
? { text: "Mining..." }
|
||||||
|
: Object.keys(resourceNodes.value).length === 0
|
||||||
|
? { text: "Click me!" }
|
||||||
|
: null,
|
||||||
progress: node =>
|
progress: node =>
|
||||||
node == board.selectedNode.value
|
node == board.selectedNode.value
|
||||||
? new Decimal(node.state as DecimalSource).toNumber()
|
? new Decimal(node.state as DecimalSource).toNumber()
|
||||||
: 0,
|
: 0,
|
||||||
progressDisplay: ProgressDisplay.Outline,
|
progressDisplay: ProgressDisplay.Outline,
|
||||||
progressColor: "var(--accent2)"
|
progressColor: "var(--accent2)",
|
||||||
|
draggable: true
|
||||||
|
},
|
||||||
|
brokenFactory: {
|
||||||
|
shape: Shape.Diamond,
|
||||||
|
size: 50,
|
||||||
|
title: "🛠️",
|
||||||
|
label: node => (node === board.selectedNode.value ? { text: "Repair me!" } : null),
|
||||||
|
actionDistance: 80,
|
||||||
|
actions: [
|
||||||
|
{ id: "repair", icon: "build", tooltip: "Costs 1000 energy", onClick() {} }
|
||||||
|
],
|
||||||
|
draggable: true
|
||||||
|
},
|
||||||
|
factory: {
|
||||||
|
shape: Shape.Diamond,
|
||||||
|
size: 50,
|
||||||
|
title: "🛠️",
|
||||||
|
draggable: true
|
||||||
},
|
},
|
||||||
resource: {
|
resource: {
|
||||||
shape: Shape.Circle,
|
shape: Shape.Circle,
|
||||||
|
@ -111,7 +186,10 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
title: node => (node.state as unknown as ResourceState).type,
|
title: node => (node.state as unknown as ResourceState).type,
|
||||||
subtitle: node => formatWhole((node.state as unknown as ResourceState).amount),
|
subtitle: node => formatWhole((node.state as unknown as ResourceState).amount),
|
||||||
progress: node =>
|
progress: node =>
|
||||||
getResourceLevelProgress((node.state as unknown as ResourceState).amount),
|
getResourceLevelProgress((node.state as unknown as ResourceState).type),
|
||||||
|
// Make clicking resources a no-op so they can't be selected
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
onClick() {},
|
||||||
progressDisplay: ProgressDisplay.Outline,
|
progressDisplay: ProgressDisplay.Outline,
|
||||||
progressColor: "var(--accent3)",
|
progressColor: "var(--accent3)",
|
||||||
draggable: true
|
draggable: true
|
||||||
|
@ -136,15 +214,6 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const resourceNodes: ComputedRef<Record<Resources, BoardNode>> = computed(() =>
|
|
||||||
board.nodes.value.reduce((acc, curr) => {
|
|
||||||
if (curr.type === "resource") {
|
|
||||||
acc[(curr.state as unknown as ResourceState).type] = curr;
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, {} as Record<Resources, BoardNode>)
|
|
||||||
);
|
|
||||||
|
|
||||||
function grantResource(type: Resources, amount: DecimalSource) {
|
function grantResource(type: Resources, amount: DecimalSource) {
|
||||||
let node = resourceNodes.value[type];
|
let node = resourceNodes.value[type];
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
|
@ -175,15 +244,11 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
const energyModifier = createSequentialModifier(() =>
|
const energyModifier = createSequentialModifier(() =>
|
||||||
resourceNames.map(resource =>
|
resourceNames.map(resource =>
|
||||||
createMultiplicativeModifier(() => ({
|
createMultiplicativeModifier(() => ({
|
||||||
description: resource,
|
description: () =>
|
||||||
multiplier: () =>
|
`${camelToTitle(resource)} (Lv. ${formatWhole(
|
||||||
Decimal.pow(
|
resourceLevels.value[resource]
|
||||||
1.01,
|
)})`,
|
||||||
resourceLevelFormula.invertIntegral(
|
multiplier: () => Decimal.pow(1.01, resourceLevels.value[resource]),
|
||||||
(resourceNodes.value[resource]?.state as ResourceState | undefined)
|
|
||||||
?.amount ?? 0
|
|
||||||
)
|
|
||||||
),
|
|
||||||
enabled: () =>
|
enabled: () =>
|
||||||
resource in resourceNodes.value &&
|
resource in resourceNodes.value &&
|
||||||
Decimal.gt(
|
Decimal.gt(
|
||||||
|
@ -195,14 +260,36 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const computedEnergyModifier = computed(() => energyModifier.apply(1));
|
const computedEnergyModifier = computed(() => energyModifier.apply(1));
|
||||||
const energyGainTooltip = jsx(() =>
|
|
||||||
createModifierSection({
|
const [energyTab, energyTabCollapsed] = createCollapsibleModifierSections(() => [
|
||||||
|
{
|
||||||
title: "Energy Gain",
|
title: "Energy Gain",
|
||||||
modifier: energyModifier,
|
modifier: energyModifier,
|
||||||
base: 1,
|
base: 1,
|
||||||
unit: "/s"
|
unit: "/s"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
const modifierTabs = createTabFamily({
|
||||||
|
general: () => ({
|
||||||
|
display: "Energy",
|
||||||
|
glowColor(): string {
|
||||||
|
return modifierTabs.activeTab.value === this.tab ? "white" : "";
|
||||||
|
},
|
||||||
|
tab: energyTab,
|
||||||
|
energyTabCollapsed
|
||||||
})
|
})
|
||||||
);
|
});
|
||||||
|
const showModifiersModal = ref(false);
|
||||||
|
const modifiersModal = jsx(() => (
|
||||||
|
<Modal
|
||||||
|
modelValue={showModifiersModal.value}
|
||||||
|
onUpdate:modelValue={(value: boolean) => (showModifiersModal.value = value)}
|
||||||
|
v-slots={{
|
||||||
|
header: () => <h2>Modifiers</h2>,
|
||||||
|
body: () => render(modifierTabs)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
this.on("preUpdate", diff => {
|
this.on("preUpdate", diff => {
|
||||||
Object.keys(resourceMinedCooldown).forEach(resource => {
|
Object.keys(resourceMinedCooldown).forEach(resource => {
|
||||||
|
@ -255,32 +342,40 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
name: "World",
|
name: "World",
|
||||||
board,
|
board,
|
||||||
energy,
|
energy,
|
||||||
|
modifierTabs,
|
||||||
display: jsx(() => (
|
display: jsx(() => (
|
||||||
<>
|
<>
|
||||||
{player.devSpeed === 0 ? <div>Game Paused</div> : null}
|
<StickyVue class="nav-container">
|
||||||
{player.devSpeed != null && player.devSpeed !== 0 && player.devSpeed !== 1 ? (
|
<span class="nav-segment">
|
||||||
<div>Dev Speed: {format(player.devSpeed)}x</div>
|
<h2 style="color: white; text-shadow: 0px 0px 10px white;">
|
||||||
) : null}
|
{displayResource(energy)}
|
||||||
{player.offlineTime != null && player.offlineTime !== 0 ? (
|
</h2>{" "}
|
||||||
<div>Offline Time: {formatTime(player.offlineTime)}</div>
|
energy
|
||||||
) : null}
|
</span>
|
||||||
<MainDisplay resource={energy} />
|
<span class="nav-segment">
|
||||||
<StickyVue style="margin-top: -20px">
|
(
|
||||||
You are gaining{" "}
|
<h3 style="color: white; text-shadow: 0px 0px 10px white;">
|
||||||
<span class="tooltip-inline-container">
|
+{format(computedEnergyModifier.value)}
|
||||||
<TooltipVue
|
</h3>
|
||||||
display={energyGainTooltip}
|
/s)
|
||||||
direction={Direction.Down}
|
</span>
|
||||||
style="width: 200px; text-align: left"
|
<span class="nav-segment">
|
||||||
|
<button
|
||||||
|
class="button"
|
||||||
|
style="display: inline"
|
||||||
|
onClick={() => (showModifiersModal.value = true)}
|
||||||
>
|
>
|
||||||
<h3 style="color: white; text-shadow: 0px 0px 10px white;">
|
open modifiers
|
||||||
{displayResource(energy, computedEnergyModifier.value)}
|
</button>
|
||||||
</h3>
|
</span>
|
||||||
</TooltipVue>
|
{player.devSpeed === 0 ? (
|
||||||
</span>{" "}
|
<span class="nav-segment">Game Paused</span>
|
||||||
energy/sec{" "}
|
) : player.devSpeed != null && player.devSpeed !== 1 ? (
|
||||||
|
<span class="nav-segment">Dev Speed: {format(player.devSpeed)}x</span>
|
||||||
|
) : null}
|
||||||
</StickyVue>
|
</StickyVue>
|
||||||
{render(board)}
|
{render(board)}
|
||||||
|
{render(modifiersModal)}
|
||||||
</>
|
</>
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"initialTabs": [ "main" ],
|
"initialTabs": [ "main" ],
|
||||||
|
|
||||||
"maxTickLength": 3600,
|
"maxTickLength": 3600,
|
||||||
"offlineLimit": 1,
|
"offlineLimit": 0,
|
||||||
"enablePausing": true,
|
"enablePausing": true,
|
||||||
"exportEncoding": "base64"
|
"exportEncoding": "base64"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue