forked from profectus/Profectus
Compare commits
36 commits
ducdat0507
...
main
Author | SHA1 | Date | |
---|---|---|---|
1b809a9550 | |||
|
cf6265d8ce | ||
4f807aaf96 | |||
ffc42a5745 | |||
|
8811996f64 | ||
|
7750a3368d | ||
2495dc9783 | |||
e66daad7a2 | |||
8065f8efa4 | |||
e9283b5cca | |||
2c615ea524 | |||
953cd8047e | |||
766c600a70 | |||
c1d0b7eec6 | |||
52b500c9d8 | |||
aabb0a1bba | |||
005bf5da9a | |||
7330a6bda4 | |||
65ff440e25 | |||
acf1d24c15 | |||
d16bb55c3c | |||
312cab1347 | |||
6d148da260 | |||
a5204106aa | |||
0cccf7aecc | |||
d0fffd3b89 | |||
3fe0311331 | |||
eee5ac3e2d | |||
9edda4d957 | |||
6ad08c4052 | |||
e0f1296b35 | |||
c8ba77b89b | |||
63dcad4c12 | |||
d6c9f95851 | |||
210c2290f0 | |||
e896fd84cf |
22 changed files with 195 additions and 50 deletions
31
.forgejo/workflows/deploy.yaml
Normal file
31
.forgejo/workflows/deploy.yaml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
name: Build and Deploy
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
workflow_dispatch:
|
||||||
|
jobs:
|
||||||
|
build-and-deploy:
|
||||||
|
if: github.repository != 'profectus-engine/Profectus' # Don't build placeholder mod on main repo
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
- name: Setup RSync
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y rsync
|
||||||
|
|
||||||
|
- name: Checkout 🛎️
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
|
||||||
|
run: |
|
||||||
|
npm ci
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
- name: Deploy 🚀
|
||||||
|
uses: https://github.com/JamesIves/github-pages-deploy-action@v4.2.5
|
||||||
|
with:
|
||||||
|
branch: pages # The branch the action should deploy to.
|
||||||
|
folder: dist # The folder the action should deploy.
|
21
.forgejo/workflows/test.yaml
Normal file
21
.forgejo/workflows/test.yaml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
name: Run Tests
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: docker
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Use Node.js 16.x
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 16.x
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run build --if-present
|
||||||
|
- run: npm test
|
1
.github/workflows/deploy.yml
vendored
1
.github/workflows/deploy.yml
vendored
|
@ -3,6 +3,7 @@ on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'main'
|
- 'main'
|
||||||
|
workflow_dispatch:
|
||||||
jobs:
|
jobs:
|
||||||
build-and-deploy:
|
build-and-deploy:
|
||||||
if: github.repository != 'profectus-engine/Profectus' # Don't build placeholder mod on main repo
|
if: github.repository != 'profectus-engine/Profectus' # Don't build placeholder mod on main repo
|
||||||
|
|
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
|
@ -1,11 +1,11 @@
|
||||||
name: Build and Deploy
|
name: Run Tests
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<span class="material-icons info-modal-discord">discord</span>
|
<span class="material-icons info-modal-discord">discord</span>
|
||||||
The Paper Pilot Community
|
Profectus & Friends
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
class="nan-modal-discord-link"
|
class="nan-modal-discord-link"
|
||||||
>
|
>
|
||||||
<span class="material-icons nan-modal-discord">discord</span>
|
<span class="material-icons nan-modal-discord">discord</span>
|
||||||
{{ discordName || "The Paper Pilot Community" }}
|
{{ discordName || "Profectus & Friends" }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -15,9 +15,7 @@
|
||||||
<a :href="discordLink" target="_blank">{{ discordName }}</a>
|
<a :href="discordLink" target="_blank">{{ discordName }}</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://discord.gg/yJ4fjnjU54" target="_blank"
|
<a href="https://discord.gg/yJ4fjnjU54" target="_blank">Profectus & Friends</a>
|
||||||
>The Paper Pilot Community</a
|
|
||||||
>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://discord.gg/F3xveHV" target="_blank">The Modding Tree</a>
|
<a href="https://discord.gg/F3xveHV" target="_blank">The Modding Tree</a>
|
||||||
|
@ -82,9 +80,7 @@
|
||||||
<a :href="discordLink" target="_blank">{{ discordName }}</a>
|
<a :href="discordLink" target="_blank">{{ discordName }}</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://discord.gg/yJ4fjnjU54" target="_blank"
|
<a href="https://discord.gg/yJ4fjnjU54" target="_blank">Profectus & Friends</a>
|
||||||
>The Paper Pilot Community</a
|
|
||||||
>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://discord.gg/F3xveHV" target="_blank">The Modding Tree</a>
|
<a href="https://discord.gg/F3xveHV" target="_blank">The Modding Tree</a>
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { Resource, displayResource } from "features/resources/resource";
|
||||||
import type { GenericTree, GenericTreeNode, TreeNode, TreeNodeOptions } from "features/trees/tree";
|
import type { GenericTree, GenericTreeNode, TreeNode, TreeNodeOptions } from "features/trees/tree";
|
||||||
import { createTreeNode } from "features/trees/tree";
|
import { createTreeNode } from "features/trees/tree";
|
||||||
import type { GenericFormula } from "game/formulas/types";
|
import type { GenericFormula } from "game/formulas/types";
|
||||||
|
import { BaseLayer } from "game/layers";
|
||||||
import type { Modifier } from "game/modifiers";
|
import type { Modifier } from "game/modifiers";
|
||||||
import type { Persistent } from "game/persistence";
|
import type { Persistent } from "game/persistence";
|
||||||
import { DefaultValue, persistent } from "game/persistence";
|
import { DefaultValue, persistent } from "game/persistence";
|
||||||
|
@ -133,8 +134,8 @@ export function createResetButton<T extends ClickableOptions & ResetButtonOption
|
||||||
{unref(resetButton.conversion.buyMax) ? "Next:" : "Req:"}{" "}
|
{unref(resetButton.conversion.buyMax) ? "Next:" : "Req:"}{" "}
|
||||||
{displayResource(
|
{displayResource(
|
||||||
resetButton.conversion.baseResource,
|
resetButton.conversion.baseResource,
|
||||||
!unref(resetButton.conversion.buyMax) ||
|
!unref(resetButton.conversion.buyMax) &&
|
||||||
Decimal.lt(unref(resetButton.conversion.actualGain), 1)
|
Decimal.gte(unref(resetButton.conversion.actualGain), 1)
|
||||||
? unref(resetButton.conversion.currentAt)
|
? unref(resetButton.conversion.currentAt)
|
||||||
: unref(resetButton.conversion.nextAt)
|
: unref(resetButton.conversion.nextAt)
|
||||||
)}{" "}
|
)}{" "}
|
||||||
|
@ -485,3 +486,22 @@ export function createFormulaPreview(
|
||||||
return <>{formatSmall(formula.evaluate())}</>;
|
return <>{formatSmall(formula.evaluate())}</>;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function for getting a computed boolean for whether or not a given feature is currently rendered in the DOM.
|
||||||
|
* Note it will have a true value even if the feature is off screen.
|
||||||
|
* @param layer The layer the feature appears within
|
||||||
|
* @param id The ID of the feature
|
||||||
|
*/
|
||||||
|
export function isRendered(layer: BaseLayer, id: string): ComputedRef<boolean>;
|
||||||
|
/**
|
||||||
|
* Utility function for getting a computed boolean for whether or not a given feature is currently rendered in the DOM.
|
||||||
|
* Note it will have a true value even if the feature is off screen.
|
||||||
|
* @param layer The layer the feature appears within
|
||||||
|
* @param feature The feature that may be rendered
|
||||||
|
*/
|
||||||
|
export function isRendered(layer: BaseLayer, feature: { id: string }): ComputedRef<boolean>;
|
||||||
|
export function isRendered(layer: BaseLayer, idOrFeature: string | { id: string }) {
|
||||||
|
const id = typeof idOrFeature === "string" ? idOrFeature : idOrFeature.id;
|
||||||
|
return computed(() => id in layer.nodes.value);
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
|
||||||
color,
|
color,
|
||||||
reset
|
reset
|
||||||
}));
|
}));
|
||||||
addTooltip(treeNode, {
|
const tooltip = addTooltip(treeNode, {
|
||||||
display: createResourceTooltip(points),
|
display: createResourceTooltip(points),
|
||||||
pinnable: true
|
pinnable: true
|
||||||
});
|
});
|
||||||
|
@ -58,6 +58,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
|
||||||
name,
|
name,
|
||||||
color,
|
color,
|
||||||
points,
|
points,
|
||||||
|
tooltip,
|
||||||
display: jsx(() => (
|
display: jsx(() => (
|
||||||
<>
|
<>
|
||||||
<MainDisplay resource={points} color={color} />
|
<MainDisplay resource={points} color={color} />
|
||||||
|
|
|
@ -120,7 +120,7 @@ export default defineComponent({
|
||||||
barStyle.clipPath = `inset(0% ${normalizedProgress.value}% 0% 0%)`;
|
barStyle.clipPath = `inset(0% ${normalizedProgress.value}% 0% 0%)`;
|
||||||
break;
|
break;
|
||||||
case Direction.Left:
|
case Direction.Left:
|
||||||
barStyle.clipPath = `inset(0% 0% 0% ${normalizedProgress.value} + '%)`;
|
barStyle.clipPath = `inset(0% 0% 0% ${normalizedProgress.value}%)`;
|
||||||
break;
|
break;
|
||||||
case Direction.Default:
|
case Direction.Default:
|
||||||
barStyle.clipPath = "inset(0% 50% 0% 0%)";
|
barStyle.clipPath = "inset(0% 50% 0% 0%)";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<line
|
<line
|
||||||
class="link"
|
class="link"
|
||||||
v-bind="link"
|
v-bind="linkProps"
|
||||||
:class="{ pulsing: link.pulsing }"
|
:class="{ pulsing: link.pulsing }"
|
||||||
:x1="startPosition.x"
|
:x1="startPosition.x"
|
||||||
:y1="startPosition.y"
|
:y1="startPosition.y"
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { BoardNode, BoardNodeLink } from "features/boards/board";
|
import type { BoardNode, BoardNodeLink } from "features/boards/board";
|
||||||
|
import { kebabifyObject } from "util/vue";
|
||||||
import { computed, toRefs, unref } from "vue";
|
import { computed, toRefs, unref } from "vue";
|
||||||
|
|
||||||
const _props = defineProps<{
|
const _props = defineProps<{
|
||||||
|
@ -49,11 +50,14 @@ const endPosition = computed(() => {
|
||||||
}
|
}
|
||||||
return position;
|
return position;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const linkProps = computed(() => kebabifyObject(_props.link as unknown as Record<string, unknown>));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.link {
|
.link {
|
||||||
transition-duration: 0s;
|
transition-duration: 0s;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link.pulsing {
|
.link.pulsing {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<line
|
<line
|
||||||
stroke-width="15px"
|
stroke-width="15px"
|
||||||
stroke="white"
|
stroke="white"
|
||||||
v-bind="link"
|
v-bind="linkProps"
|
||||||
:x1="startPosition.x"
|
:x1="startPosition.x"
|
||||||
:y1="startPosition.y"
|
:y1="startPosition.y"
|
||||||
:x2="endPosition.x"
|
:x2="endPosition.x"
|
||||||
|
@ -13,6 +13,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Link } from "features/links/links";
|
import type { Link } from "features/links/links";
|
||||||
import type { FeatureNode } from "game/layers";
|
import type { FeatureNode } from "game/layers";
|
||||||
|
import { kebabifyObject } from "util/vue";
|
||||||
import { computed, toRefs } from "vue";
|
import { computed, toRefs } from "vue";
|
||||||
|
|
||||||
const _props = defineProps<{
|
const _props = defineProps<{
|
||||||
|
@ -54,4 +55,6 @@ const endPosition = computed(() => {
|
||||||
}
|
}
|
||||||
return position;
|
return position;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const linkProps = computed(() => kebabifyObject(_props.link as unknown as Record<string, unknown>));
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -95,18 +95,6 @@ export function addTooltip<T extends TooltipOptions>(
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (options.pinnable) {
|
|
||||||
if ("pinned" in element) {
|
|
||||||
console.error(
|
|
||||||
"Cannot add pinnable tooltip to element that already has a property called 'pinned'"
|
|
||||||
);
|
|
||||||
options.pinnable = false;
|
|
||||||
deletePersistent(options.pinned as Persistent<boolean>);
|
|
||||||
} else {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
(element as any).pinned = options.pinned;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const elementComponent = element[Component];
|
const elementComponent = element[Component];
|
||||||
element[Component] = TooltipComponent as GenericComponent;
|
element[Component] = TooltipComponent as GenericComponent;
|
||||||
const elementGatherProps = element[GatherProps].bind(element);
|
const elementGatherProps = element[GatherProps].bind(element);
|
||||||
|
|
|
@ -345,19 +345,35 @@ export abstract class InternalFormula<T extends [FormulaSource] | FormulaSource[
|
||||||
public static sgn = InternalFormula.sign;
|
public static sgn = InternalFormula.sign;
|
||||||
|
|
||||||
public static round(value: FormulaSource) {
|
public static round(value: FormulaSource) {
|
||||||
return new Formula({ inputs: [value], evaluate: Decimal.round });
|
return new Formula({
|
||||||
|
inputs: [value],
|
||||||
|
evaluate: Decimal.round,
|
||||||
|
invert: ops.invertPassthrough
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static floor(value: FormulaSource) {
|
public static floor(value: FormulaSource) {
|
||||||
return new Formula({ inputs: [value], evaluate: Decimal.floor });
|
return new Formula({
|
||||||
|
inputs: [value],
|
||||||
|
evaluate: Decimal.floor,
|
||||||
|
invert: ops.invertPassthrough
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ceil(value: FormulaSource) {
|
public static ceil(value: FormulaSource) {
|
||||||
return new Formula({ inputs: [value], evaluate: Decimal.ceil });
|
return new Formula({
|
||||||
|
inputs: [value],
|
||||||
|
evaluate: Decimal.ceil,
|
||||||
|
invert: ops.invertPassthrough
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static trunc(value: FormulaSource) {
|
public static trunc(value: FormulaSource) {
|
||||||
return new Formula({ inputs: [value], evaluate: Decimal.trunc });
|
return new Formula({
|
||||||
|
inputs: [value],
|
||||||
|
evaluate: Decimal.trunc,
|
||||||
|
invert: ops.invertPassthrough
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static add<T extends GenericFormula>(value: T, other: FormulaSource): T;
|
public static add<T extends GenericFormula>(value: T, other: FormulaSource): T;
|
||||||
|
@ -459,7 +475,7 @@ export abstract class InternalFormula<T extends [FormulaSource] | FormulaSource[
|
||||||
return new Formula({
|
return new Formula({
|
||||||
inputs: [value, min, max],
|
inputs: [value, min, max],
|
||||||
evaluate: Decimal.clamp,
|
evaluate: Decimal.clamp,
|
||||||
invert: ops.passthrough as InvertFunction<[FormulaSource, FormulaSource, FormulaSource]>
|
invert: ops.invertPassthrough
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
import Decimal, { DecimalSource } from "util/bignum";
|
import Decimal, { DecimalSource } from "util/bignum";
|
||||||
import Formula, { hasVariable, unrefFormulaSource } from "./formulas";
|
import Formula, { hasVariable, unrefFormulaSource } from "./formulas";
|
||||||
import { FormulaSource, GenericFormula, InvertFunction, SubstitutionStack } from "./types";
|
import {
|
||||||
|
FormulaSource,
|
||||||
|
GenericFormula,
|
||||||
|
InvertFunction,
|
||||||
|
InvertibleFormula,
|
||||||
|
SubstitutionStack
|
||||||
|
} from "./types";
|
||||||
|
|
||||||
const ln10 = Decimal.ln(10);
|
const ln10 = Decimal.ln(10);
|
||||||
|
|
||||||
|
@ -8,6 +14,15 @@ export function passthrough<T extends GenericFormula | DecimalSource>(value: T):
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function invertPassthrough(value: DecimalSource, ...inputs: FormulaSource[]) {
|
||||||
|
const variable = inputs.find(input => hasVariable(input)) as InvertibleFormula | undefined;
|
||||||
|
if (variable == null) {
|
||||||
|
console.error("Could not invert due to no input being a variable");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return variable.invert(value);
|
||||||
|
}
|
||||||
|
|
||||||
export function invertNeg(value: DecimalSource, lhs: FormulaSource) {
|
export function invertNeg(value: DecimalSource, lhs: FormulaSource) {
|
||||||
if (hasVariable(lhs)) {
|
if (hasVariable(lhs)) {
|
||||||
return lhs.invert(Decimal.neg(value));
|
return lhs.invert(Decimal.neg(value));
|
||||||
|
|
|
@ -297,9 +297,9 @@ export function createSequentialModifier<
|
||||||
getFormula: modifiers.every(m => m.getFormula != null)
|
getFormula: modifiers.every(m => m.getFormula != null)
|
||||||
? (gain: FormulaSource) =>
|
? (gain: FormulaSource) =>
|
||||||
modifiers
|
modifiers
|
||||||
.filter(m => unref(m.enabled) !== false)
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
.reduce((acc, curr) => curr.getFormula!(acc), gain)
|
.reduce((acc, curr) => Formula.if(acc, curr.enabled ?? true,
|
||||||
|
acc => curr.getFormula!(acc), acc => acc), gain)
|
||||||
: undefined,
|
: undefined,
|
||||||
enabled: modifiers.some(m => m.enabled != null)
|
enabled: modifiers.some(m => m.enabled != null)
|
||||||
? computed(() => modifiers.filter(m => unref(m.enabled) !== false).length > 0)
|
? computed(() => modifiers.filter(m => unref(m.enabled) !== false).length > 0)
|
||||||
|
|
|
@ -222,7 +222,7 @@ export function createCostRequirement<T extends CostRequirementOptions>(
|
||||||
Decimal.gte(
|
Decimal.gte(
|
||||||
req.resource.value,
|
req.resource.value,
|
||||||
unref(req.cost as ProcessedComputable<DecimalSource>)
|
unref(req.cost as ProcessedComputable<DecimalSource>)
|
||||||
)
|
) ? 1 : 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,11 @@ export function camelToTitle(camel: string): string {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function camelToKebab(camel: string) {
|
||||||
|
// Split off first character so function works on upper camel (pascal) case
|
||||||
|
return (camel[0] + camel.slice(1).replace(/[A-Z]/g, c => `-${c}`)).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
export function isFunction<T, S extends ReadonlyArray<unknown>, R>(
|
export function isFunction<T, S extends ReadonlyArray<unknown>, R>(
|
||||||
functionOrValue: ((...args: S) => T) | R
|
functionOrValue: ((...args: S) => T) | R
|
||||||
): functionOrValue is (...args: S) => T {
|
): functionOrValue is (...args: S) => T {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import {
|
||||||
unref,
|
unref,
|
||||||
watchEffect
|
watchEffect
|
||||||
} from "vue";
|
} from "vue";
|
||||||
|
import { camelToKebab } from "./common";
|
||||||
|
|
||||||
export function coerceComponent(
|
export function coerceComponent(
|
||||||
component: CoercableComponent,
|
component: CoercableComponent,
|
||||||
|
@ -241,3 +242,10 @@ export function trackHover(element: VueFeature): Ref<boolean> {
|
||||||
|
|
||||||
return isHovered;
|
return isHovered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function kebabifyObject(object: Record<string, unknown>) {
|
||||||
|
return Object.keys(object).reduce((acc, curr) => {
|
||||||
|
acc[camelToKebab(curr)] = object[curr];
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, unknown>);
|
||||||
|
}
|
||||||
|
|
|
@ -47,6 +47,10 @@ describe("Creating conversion", () => {
|
||||||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||||
expect(unref(conversion.currentGain)).compare_tolerance(100);
|
expect(unref(conversion.currentGain)).compare_tolerance(100);
|
||||||
});
|
});
|
||||||
|
test("Zero", () => {
|
||||||
|
baseResource.value = Decimal.dZero;
|
||||||
|
expect(unref(conversion.currentGain)).compare_tolerance(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe("Calculates actualGain correctly", () => {
|
describe("Calculates actualGain correctly", () => {
|
||||||
let conversion: GenericConversion;
|
let conversion: GenericConversion;
|
||||||
|
@ -69,6 +73,10 @@ describe("Creating conversion", () => {
|
||||||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||||
expect(unref(conversion.actualGain)).compare_tolerance(100);
|
expect(unref(conversion.actualGain)).compare_tolerance(100);
|
||||||
});
|
});
|
||||||
|
test("Zero", () => {
|
||||||
|
baseResource.value = Decimal.dZero;
|
||||||
|
expect(unref(conversion.actualGain)).compare_tolerance(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe("Calculates currentAt correctly", () => {
|
describe("Calculates currentAt correctly", () => {
|
||||||
let conversion: GenericConversion;
|
let conversion: GenericConversion;
|
||||||
|
@ -95,6 +103,10 @@ describe("Creating conversion", () => {
|
||||||
Decimal.pow(100, 2).times(10)
|
Decimal.pow(100, 2).times(10)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
test("Zero", () => {
|
||||||
|
baseResource.value = Decimal.dZero;
|
||||||
|
expect(unref(conversion.currentAt)).compare_tolerance(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe("Calculates nextAt correctly", () => {
|
describe("Calculates nextAt correctly", () => {
|
||||||
let conversion: GenericConversion;
|
let conversion: GenericConversion;
|
||||||
|
@ -117,6 +129,10 @@ describe("Creating conversion", () => {
|
||||||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||||
expect(unref(conversion.nextAt)).compare_tolerance(Decimal.pow(101, 2).times(10));
|
expect(unref(conversion.nextAt)).compare_tolerance(Decimal.pow(101, 2).times(10));
|
||||||
});
|
});
|
||||||
|
test("Zero", () => {
|
||||||
|
baseResource.value = Decimal.dZero;
|
||||||
|
expect(unref(conversion.nextAt)).compare_tolerance(Decimal.dTen);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
test("Converts correctly", () => {
|
test("Converts correctly", () => {
|
||||||
const conversion = createCumulativeConversion(() => ({
|
const conversion = createCumulativeConversion(() => ({
|
||||||
|
@ -193,6 +209,10 @@ describe("Creating conversion", () => {
|
||||||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||||
expect(unref(conversion.currentGain)).compare_tolerance(100);
|
expect(unref(conversion.currentGain)).compare_tolerance(100);
|
||||||
});
|
});
|
||||||
|
test("Zero", () => {
|
||||||
|
baseResource.value = Decimal.dZero;
|
||||||
|
expect(unref(conversion.currentGain)).compare_tolerance(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe("Calculates actualGain correctly", () => {
|
describe("Calculates actualGain correctly", () => {
|
||||||
let conversion: GenericConversion;
|
let conversion: GenericConversion;
|
||||||
|
@ -216,6 +236,10 @@ describe("Creating conversion", () => {
|
||||||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||||
expect(unref(conversion.actualGain)).compare_tolerance(99);
|
expect(unref(conversion.actualGain)).compare_tolerance(99);
|
||||||
});
|
});
|
||||||
|
test("Zero", () => {
|
||||||
|
baseResource.value = Decimal.dZero;
|
||||||
|
expect(unref(conversion.actualGain)).compare_tolerance(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe("Calculates currentAt correctly", () => {
|
describe("Calculates currentAt correctly", () => {
|
||||||
let conversion: GenericConversion;
|
let conversion: GenericConversion;
|
||||||
|
@ -243,6 +267,10 @@ describe("Creating conversion", () => {
|
||||||
Decimal.pow(100, 2).times(10)
|
Decimal.pow(100, 2).times(10)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
test("Zero", () => {
|
||||||
|
baseResource.value = Decimal.dZero;
|
||||||
|
expect(unref(conversion.currentAt)).compare_tolerance(Decimal.pow(1, 2).times(10));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe("Calculates nextAt correctly", () => {
|
describe("Calculates nextAt correctly", () => {
|
||||||
let conversion: GenericConversion;
|
let conversion: GenericConversion;
|
||||||
|
@ -266,6 +294,10 @@ describe("Creating conversion", () => {
|
||||||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||||
expect(unref(conversion.nextAt)).compare_tolerance(Decimal.pow(101, 2).times(10));
|
expect(unref(conversion.nextAt)).compare_tolerance(Decimal.pow(101, 2).times(10));
|
||||||
});
|
});
|
||||||
|
test("Zero", () => {
|
||||||
|
baseResource.value = Decimal.dZero;
|
||||||
|
expect(unref(conversion.nextAt)).compare_tolerance(Decimal.pow(2, 2).times(10));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
test("Converts correctly", () => {
|
test("Converts correctly", () => {
|
||||||
const conversion = createIndependentConversion(() => ({
|
const conversion = createIndependentConversion(() => ({
|
||||||
|
|
|
@ -13,9 +13,13 @@ import { InvertibleIntegralFormula } from "game/formulas/types";
|
||||||
|
|
||||||
type FormulaFunctions = keyof GenericFormula & keyof typeof Formula & keyof typeof Decimal;
|
type FormulaFunctions = keyof GenericFormula & keyof typeof Formula & keyof typeof Decimal;
|
||||||
|
|
||||||
const testValues = [-1, "0", Decimal.dOne] as const;
|
const testValues = [-2, "0", new Decimal(10.5)] as const;
|
||||||
|
|
||||||
const invertibleZeroParamFunctionNames = [
|
const invertibleZeroParamFunctionNames = [
|
||||||
|
"round",
|
||||||
|
"floor",
|
||||||
|
"ceil",
|
||||||
|
"trunc",
|
||||||
"neg",
|
"neg",
|
||||||
"recip",
|
"recip",
|
||||||
"log10",
|
"log10",
|
||||||
|
@ -48,10 +52,6 @@ const invertibleZeroParamFunctionNames = [
|
||||||
const nonInvertibleZeroParamFunctionNames = [
|
const nonInvertibleZeroParamFunctionNames = [
|
||||||
"abs",
|
"abs",
|
||||||
"sign",
|
"sign",
|
||||||
"round",
|
|
||||||
"floor",
|
|
||||||
"ceil",
|
|
||||||
"trunc",
|
|
||||||
"pLog10",
|
"pLog10",
|
||||||
"absLog10",
|
"absLog10",
|
||||||
"factorial",
|
"factorial",
|
||||||
|
@ -85,6 +85,10 @@ const integrableZeroParamFunctionNames = [
|
||||||
] as const;
|
] as const;
|
||||||
const nonIntegrableZeroParamFunctionNames = [
|
const nonIntegrableZeroParamFunctionNames = [
|
||||||
...nonInvertibleZeroParamFunctionNames,
|
...nonInvertibleZeroParamFunctionNames,
|
||||||
|
"round",
|
||||||
|
"floor",
|
||||||
|
"ceil",
|
||||||
|
"trunc",
|
||||||
"lambertw",
|
"lambertw",
|
||||||
"ssqrt"
|
"ssqrt"
|
||||||
] as const;
|
] as const;
|
||||||
|
@ -151,7 +155,7 @@ describe("Formula Equality Checking", () => {
|
||||||
describe("Formula aliases", () => {
|
describe("Formula aliases", () => {
|
||||||
function testAliases<T extends FormulaFunctions>(
|
function testAliases<T extends FormulaFunctions>(
|
||||||
aliases: T[],
|
aliases: T[],
|
||||||
args: Parameters<(typeof Formula)[T]>
|
args: Parameters<typeof Formula[T]>
|
||||||
) {
|
) {
|
||||||
describe(aliases[0], () => {
|
describe(aliases[0], () => {
|
||||||
let formula: GenericFormula;
|
let formula: GenericFormula;
|
||||||
|
@ -246,7 +250,7 @@ describe("Creating Formulas", () => {
|
||||||
|
|
||||||
function checkFormula<T extends FormulaFunctions>(
|
function checkFormula<T extends FormulaFunctions>(
|
||||||
functionName: T,
|
functionName: T,
|
||||||
args: Readonly<Parameters<(typeof Formula)[T]>>
|
args: Readonly<Parameters<typeof Formula[T]>>
|
||||||
) {
|
) {
|
||||||
let formula: GenericFormula;
|
let formula: GenericFormula;
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
|
@ -270,7 +274,7 @@ describe("Creating Formulas", () => {
|
||||||
// It's a lot of tests, but I'd rather be exhaustive
|
// It's a lot of tests, but I'd rather be exhaustive
|
||||||
function testFormulaCall<T extends FormulaFunctions>(
|
function testFormulaCall<T extends FormulaFunctions>(
|
||||||
functionName: T,
|
functionName: T,
|
||||||
args: Readonly<Parameters<(typeof Formula)[T]>>
|
args: Readonly<Parameters<typeof Formula[T]>>
|
||||||
) {
|
) {
|
||||||
if ((functionName === "slog" || functionName === "layeradd") && args[0] === -1) {
|
if ((functionName === "slog" || functionName === "layeradd") && args[0] === -1) {
|
||||||
// These cases in particular take a long time, so skip them
|
// These cases in particular take a long time, so skip them
|
||||||
|
@ -488,18 +492,18 @@ describe("Inverting", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Inverting nested formulas", () => {
|
test("Inverting nested formulas", () => {
|
||||||
const formula = Formula.add(variable, constant).times(constant);
|
const formula = Formula.add(variable, constant).times(constant).floor();
|
||||||
expect(formula.invert(100)).compare_tolerance(0);
|
expect(formula.invert(100)).compare_tolerance(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Inverting with non-invertible sections", () => {
|
describe("Inverting with non-invertible sections", () => {
|
||||||
test("Non-invertible constant", () => {
|
test("Non-invertible constant", () => {
|
||||||
const formula = Formula.add(variable, constant.ceil());
|
const formula = Formula.add(variable, constant.sign());
|
||||||
expect(formula.isInvertible()).toBe(true);
|
expect(formula.isInvertible()).toBe(true);
|
||||||
expect(() => formula.invert(10)).not.toLogError();
|
expect(() => formula.invert(10)).not.toLogError();
|
||||||
});
|
});
|
||||||
test("Non-invertible variable", () => {
|
test("Non-invertible variable", () => {
|
||||||
const formula = Formula.add(variable.ceil(), constant);
|
const formula = Formula.add(variable.sign(), constant);
|
||||||
expect(formula.isInvertible()).toBe(false);
|
expect(formula.isInvertible()).toBe(false);
|
||||||
expect(() => formula.invert(10)).toLogError();
|
expect(() => formula.invert(10)).toLogError();
|
||||||
});
|
});
|
||||||
|
|
|
@ -83,7 +83,7 @@ describe("Creating cost requirement", () => {
|
||||||
cost: 10,
|
cost: 10,
|
||||||
cumulativeCost: false
|
cumulativeCost: false
|
||||||
}));
|
}));
|
||||||
expect(unref(requirement.requirementMet)).toBe(true);
|
expect(unref(requirement.requirementMet)).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Requirement not met when not meeting the cost", () => {
|
test("Requirement not met when not meeting the cost", () => {
|
||||||
|
@ -92,7 +92,7 @@ describe("Creating cost requirement", () => {
|
||||||
cost: 100,
|
cost: 100,
|
||||||
cumulativeCost: false
|
cumulativeCost: false
|
||||||
}));
|
}));
|
||||||
expect(unref(requirement.requirementMet)).toBe(false);
|
expect(unref(requirement.requirementMet)).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("canMaximize works correctly", () => {
|
describe("canMaximize works correctly", () => {
|
||||||
|
|
Loading…
Reference in a new issue