mirror of
https://github.com/thepaperpilot/Planar-Pioneers.git
synced 2024-11-28 11:01:42 +00:00
Implement influences
This commit is contained in:
parent
2a362a95c3
commit
44844f0de7
2 changed files with 339 additions and 66 deletions
|
@ -2,7 +2,7 @@ import ModalVue from "components/Modal.vue";
|
||||||
import SpacerVue from "components/layout/Spacer.vue";
|
import SpacerVue from "components/layout/Spacer.vue";
|
||||||
import StickyVue from "components/layout/Sticky.vue";
|
import StickyVue from "components/layout/Sticky.vue";
|
||||||
import { GenericAchievement, createAchievement } from "features/achievements/achievement";
|
import { GenericAchievement, createAchievement } from "features/achievements/achievement";
|
||||||
import { BoardNode } from "features/boards/board";
|
import { BoardNode, getUniqueNodeID } from "features/boards/board";
|
||||||
import { jsx } from "features/feature";
|
import { jsx } from "features/feature";
|
||||||
import { createRepeatable } from "features/repeatable";
|
import { createRepeatable } from "features/repeatable";
|
||||||
import { createResource } from "features/resources/resource";
|
import { createResource } from "features/resources/resource";
|
||||||
|
@ -18,7 +18,7 @@ import {
|
||||||
createMultiplicativeModifier,
|
createMultiplicativeModifier,
|
||||||
createSequentialModifier
|
createSequentialModifier
|
||||||
} from "game/modifiers";
|
} from "game/modifiers";
|
||||||
import { noPersist, persistent } from "game/persistence";
|
import { State, noPersist, persistent } from "game/persistence";
|
||||||
import { createCostRequirement } from "game/requirements";
|
import { createCostRequirement } from "game/requirements";
|
||||||
import { adjectives, colors, uniqueNamesGenerator } from "unique-names-generator";
|
import { adjectives, colors, uniqueNamesGenerator } from "unique-names-generator";
|
||||||
import Decimal, { DecimalSource } from "util/bignum";
|
import Decimal, { DecimalSource } from "util/bignum";
|
||||||
|
@ -28,7 +28,14 @@ import { Computable, ProcessedComputable, convertComputable } from "util/compute
|
||||||
import { VueFeature, render, renderRow, trackHover } from "util/vue";
|
import { VueFeature, render, renderRow, trackHover } from "util/vue";
|
||||||
import { ComputedRef, Ref, computed, ref, unref } from "vue";
|
import { ComputedRef, Ref, computed, ref, unref } from "vue";
|
||||||
import { createCollapsibleModifierSections, createFormulaPreview, estimateTime } from "./common";
|
import { createCollapsibleModifierSections, createFormulaPreview, estimateTime } from "./common";
|
||||||
import { main, mineLootTable, resourceNames } from "./projEntry";
|
import {
|
||||||
|
InfluenceState,
|
||||||
|
Influences,
|
||||||
|
influences as influenceTypes,
|
||||||
|
main,
|
||||||
|
mineLootTable,
|
||||||
|
resourceNames
|
||||||
|
} from "./projEntry";
|
||||||
import type { ResourceState, Resources, PortalState } from "./projEntry";
|
import type { ResourceState, Resources, PortalState } from "./projEntry";
|
||||||
import { getColor, getName, sfc32 } from "./utils";
|
import { getColor, getName, sfc32 } from "./utils";
|
||||||
|
|
||||||
|
@ -39,7 +46,12 @@ export type Treasure = GenericAchievement & {
|
||||||
resourceMulti: DecimalSource;
|
resourceMulti: DecimalSource;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createPlane(id: string, tier: Resources, seed: number) {
|
export function createPlane(
|
||||||
|
id: string,
|
||||||
|
tier: Resources,
|
||||||
|
seed: number,
|
||||||
|
influences: InfluenceState[]
|
||||||
|
) {
|
||||||
return createLayer(id, function (this: BaseLayer) {
|
return createLayer(id, function (this: BaseLayer) {
|
||||||
const random = sfc32(0, seed >> 0, seed >> 32, 1);
|
const random = sfc32(0, seed >> 0, seed >> 32, 1);
|
||||||
for (let i = 0; i < 12; i++) random();
|
for (let i = 0; i < 12; i++) random();
|
||||||
|
@ -49,8 +61,21 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
const background = getColor([0.18, 0.2, 0.25], random);
|
const background = getColor([0.18, 0.2, 0.25], random);
|
||||||
const resource = createResource<DecimalSource>(0, getName(random));
|
const resource = createResource<DecimalSource>(0, getName(random));
|
||||||
const tierIndex = resourceNames.indexOf(tier);
|
const tierIndex = resourceNames.indexOf(tier);
|
||||||
|
let difficultyRand = random();
|
||||||
|
if (influences.some(i => i.type === "increaseDiff")) {
|
||||||
|
difficultyRand = difficultyRand / 2 + 0.5;
|
||||||
|
}
|
||||||
|
if (influences.some(i => i.type === "decreaseDiff")) {
|
||||||
|
difficultyRand = difficultyRand / 2;
|
||||||
|
}
|
||||||
const difficulty = random() + tierIndex + 1;
|
const difficulty = random() + tierIndex + 1;
|
||||||
const length = Math.ceil(random() * (tierIndex + 2));
|
const rewardsLevel = influences.some(i => i.type === "increaseRewards")
|
||||||
|
? difficulty + 1
|
||||||
|
: difficulty;
|
||||||
|
let length = Math.ceil(random() * (tierIndex + 2));
|
||||||
|
if (influences.some(i => i.type === "increaseLength")) {
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
|
||||||
const resourceModifiers: WithRequired<Modifier, "description" | "invert">[] = [];
|
const resourceModifiers: WithRequired<Modifier, "description" | "invert">[] = [];
|
||||||
const resourceGainModifier = createSequentialModifier(() => resourceModifiers);
|
const resourceGainModifier = createSequentialModifier(() => resourceModifiers);
|
||||||
|
@ -62,21 +87,30 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
cost: FormulaSource;
|
cost: FormulaSource;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
|
|
||||||
function prepareFeature(
|
function prepareFeature({
|
||||||
feature: VueFeature,
|
feature,
|
||||||
canClick: Computable<boolean>,
|
canClick,
|
||||||
modifier: WithRequired<Modifier, "description" | "invert">,
|
modifier,
|
||||||
cost: FormulaSource,
|
cost,
|
||||||
previewModifier: WithRequired<Modifier, "invert"> = modifier
|
previewModifier,
|
||||||
) {
|
showETA
|
||||||
|
}: {
|
||||||
|
feature: VueFeature;
|
||||||
|
canClick: Computable<boolean>;
|
||||||
|
modifier: WithRequired<Modifier, "description" | "invert">;
|
||||||
|
cost: FormulaSource;
|
||||||
|
previewModifier?: WithRequired<Modifier, "invert">;
|
||||||
|
showETA?: Computable<boolean | undefined>;
|
||||||
|
}) {
|
||||||
canClick = convertComputable(canClick);
|
canClick = convertComputable(canClick);
|
||||||
|
showETA = convertComputable(showETA);
|
||||||
|
|
||||||
const isHovering = trackHover(feature);
|
const isHovering = trackHover(feature);
|
||||||
previews.push({
|
previews.push({
|
||||||
shouldShowPreview: computed(
|
shouldShowPreview: computed(
|
||||||
() => unref(canClick as ProcessedComputable<boolean>) && isHovering.value
|
() => unref(canClick as ProcessedComputable<boolean>) && isHovering.value
|
||||||
),
|
),
|
||||||
modifier: previewModifier,
|
modifier: previewModifier ?? modifier,
|
||||||
cost
|
cost
|
||||||
});
|
});
|
||||||
resourceModifiers.push(modifier);
|
resourceModifiers.push(modifier);
|
||||||
|
@ -84,7 +118,10 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
unrefFormulaSource(cost)
|
unrefFormulaSource(cost)
|
||||||
);
|
);
|
||||||
addTooltip(feature, {
|
addTooltip(feature, {
|
||||||
display: eta,
|
display:
|
||||||
|
showETA == null
|
||||||
|
? eta
|
||||||
|
: () => (unref(showETA as ProcessedComputable<boolean>) ? eta.value : ""),
|
||||||
direction: Direction.Down
|
direction: Direction.Down
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -101,10 +138,15 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
.times(10)
|
.times(10)
|
||||||
.times(costFormula.evaluate())
|
.times(costFormula.evaluate())
|
||||||
);
|
);
|
||||||
|
const influenceTreasures: Influences[] = [];
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
const featureWeights = {
|
const featureWeights = {
|
||||||
upgrades: 16,
|
upgrades: 32,
|
||||||
repeatables: i <= 1 ? 0 : 8
|
repeatables: i <= 1 ? 0 : 16
|
||||||
|
// conversion: i <= 3 ? 0 : 8,
|
||||||
|
// xp: i <= 5 ? 0 : 4,
|
||||||
|
// dimensions: i <= 7 ? 0 : 2,
|
||||||
|
// prestige: i <= 7 && i < length - 1 ? 0 : 1
|
||||||
};
|
};
|
||||||
const type = pickRandom(featureWeights, random);
|
const type = pickRandom(featureWeights, random);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -177,12 +219,13 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
},
|
},
|
||||||
visibility: upgradeVisibility
|
visibility: upgradeVisibility
|
||||||
}));
|
}));
|
||||||
prepareFeature(
|
prepareFeature({
|
||||||
upgrade,
|
feature: upgrade,
|
||||||
() => !upgrade.bought.value && upgrade.canPurchase.value,
|
canClick: () => upgrade.canPurchase.value,
|
||||||
modifier,
|
modifier,
|
||||||
cost
|
cost,
|
||||||
);
|
showETA: () => !upgrade.bought.value
|
||||||
|
});
|
||||||
upgrades.push(upgrade);
|
upgrades.push(upgrade);
|
||||||
}
|
}
|
||||||
features.push(upgrades);
|
features.push(upgrades);
|
||||||
|
@ -193,6 +236,7 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
const repeatableTypeWeights = {
|
const repeatableTypeWeights = {
|
||||||
add: 1.5,
|
add: 1.5,
|
||||||
mult: 3
|
mult: 3
|
||||||
|
// pow was too hard to implement such that the cost would be invertible
|
||||||
};
|
};
|
||||||
const upgradeType = pickRandom(repeatableTypeWeights, random);
|
const upgradeType = pickRandom(repeatableTypeWeights, random);
|
||||||
// Repeatables will estimate 5 purchases between each increment of `n`
|
// Repeatables will estimate 5 purchases between each increment of `n`
|
||||||
|
@ -279,23 +323,30 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
}),
|
}),
|
||||||
visibility: repeatableVisibility
|
visibility: repeatableVisibility
|
||||||
}));
|
}));
|
||||||
prepareFeature(
|
prepareFeature({
|
||||||
repeatable,
|
feature: repeatable,
|
||||||
() => unref(repeatable.canClick),
|
canClick: () => unref(repeatable.canClick),
|
||||||
modifier,
|
modifier,
|
||||||
cost,
|
cost,
|
||||||
previewModifier
|
previewModifier
|
||||||
);
|
});
|
||||||
repeatables.push(repeatable);
|
repeatables.push(repeatable);
|
||||||
}
|
}
|
||||||
features.push(repeatables);
|
features.push(repeatables);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const treasureWeights = {
|
const treasureWeights = {
|
||||||
cache: 100,
|
cache: influences.some(i => i.type === "increaseCaches") ? 10 : 1,
|
||||||
generation: 10,
|
generation: influences.some(i => i.type === "increaseGens") ? 10 : 1,
|
||||||
resourceMulti: 5,
|
resourceMulti: influences.some(i => i.type === "increaseResourceMults") ? 10 : 1,
|
||||||
energyMulti: 5
|
energyMulti: influences.some(i => i.type === "increaseEnergyMults") ? 2.5 : 0.25,
|
||||||
|
influences:
|
||||||
|
Object.keys(main.influenceNodes.value).length + influenceTreasures.length ===
|
||||||
|
Object.keys(influenceTypes).length
|
||||||
|
? 0
|
||||||
|
: influences.some(i => i.type === "increaseInfluences")
|
||||||
|
? 20
|
||||||
|
: 2
|
||||||
};
|
};
|
||||||
const treasureType = pickRandom(treasureWeights, random);
|
const treasureType = pickRandom(treasureWeights, random);
|
||||||
let description = "";
|
let description = "";
|
||||||
|
@ -307,8 +358,8 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
let resourceMulti: DecimalSource;
|
let resourceMulti: DecimalSource;
|
||||||
switch (treasureType) {
|
switch (treasureType) {
|
||||||
case "cache":
|
case "cache":
|
||||||
randomResource = getRandomResource(random);
|
randomResource = getRandomResource(random, influences);
|
||||||
description = `Gain ${format(difficulty)}x your current ${randomResource}.`;
|
description = `Gain ${format(rewardsLevel)}x your current ${randomResource}.`;
|
||||||
onComplete = () =>
|
onComplete = () =>
|
||||||
main.grantResource(
|
main.grantResource(
|
||||||
randomResource,
|
randomResource,
|
||||||
|
@ -317,29 +368,61 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
main.resourceNodes.value[randomResource]
|
main.resourceNodes.value[randomResource]
|
||||||
?.state as unknown as ResourceState | null
|
?.state as unknown as ResourceState | null
|
||||||
)?.amount ?? 0,
|
)?.amount ?? 0,
|
||||||
difficulty
|
rewardsLevel
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "generation":
|
case "generation":
|
||||||
randomResource = getRandomResource(random);
|
randomResource = getRandomResource(random, influences);
|
||||||
const gain = Decimal.div(difficulty, 120).times(mineLootTable[randomResource]);
|
const gain = Decimal.div(rewardsLevel, 120).times(
|
||||||
|
mineLootTable[randomResource]
|
||||||
|
);
|
||||||
description = `Gain ${format(gain)} ${randomResource}/s while plane is active.`;
|
description = `Gain ${format(gain)} ${randomResource}/s while plane is active.`;
|
||||||
update = diff => main.grantResource(randomResource, Decimal.times(diff, gain));
|
update = diff => main.grantResource(randomResource, Decimal.times(diff, gain));
|
||||||
link = computed(() => main.resourceNodes.value[randomResource]);
|
link = computed(() => main.resourceNodes.value[randomResource]);
|
||||||
break;
|
break;
|
||||||
case "resourceMulti":
|
case "resourceMulti":
|
||||||
effectedResource = randomResource = getRandomResource(random);
|
effectedResource = randomResource = getRandomResource(random, influences);
|
||||||
resourceMulti = Decimal.div(difficulty, 17).pow_base(2);
|
resourceMulti = Decimal.div(rewardsLevel, 17).pow_base(2);
|
||||||
description = `Gain ${format(
|
description = `Gain ${format(
|
||||||
resourceMulti
|
resourceMulti
|
||||||
)}x ${randomResource} while plane is active.`;
|
)}x ${randomResource} while plane is active.`;
|
||||||
break;
|
break;
|
||||||
case "energyMulti":
|
case "energyMulti":
|
||||||
effectedResource = "energy";
|
effectedResource = "energy";
|
||||||
resourceMulti = Decimal.div(difficulty, 17);
|
resourceMulti = Decimal.div(rewardsLevel, 17);
|
||||||
description = `Gain ${format(resourceMulti)}x energy while plane is active.`;
|
description = `Gain ${format(resourceMulti)}x energy while plane is active.`;
|
||||||
break;
|
break;
|
||||||
|
case "influences":
|
||||||
|
const randomInfluence = pickRandom(
|
||||||
|
(Object.keys(influenceTypes) as Influences[]).reduce((acc, curr) => {
|
||||||
|
acc[curr] =
|
||||||
|
curr in main.influenceNodes.value ||
|
||||||
|
influenceTreasures.includes(curr)
|
||||||
|
? 0
|
||||||
|
: 1;
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<Influences, number>),
|
||||||
|
random
|
||||||
|
);
|
||||||
|
influenceTreasures.push(randomInfluence);
|
||||||
|
description = `Gain a new portal influence`;
|
||||||
|
onComplete = () =>
|
||||||
|
main.board.placeInAvailableSpace({
|
||||||
|
id: getUniqueNodeID(main.board),
|
||||||
|
position: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
...main.board.types.portal.nodes.value.find(
|
||||||
|
n => (n.state as unknown as PortalState).id === id
|
||||||
|
)!.position
|
||||||
|
},
|
||||||
|
type: "influence",
|
||||||
|
state: {
|
||||||
|
type: randomInfluence,
|
||||||
|
data: influenceTypes[randomInfluence].initialData
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
const milestoneVisibility = visibility;
|
const milestoneVisibility = visibility;
|
||||||
const cost = nextCost.value;
|
const cost = nextCost.value;
|
||||||
|
@ -510,6 +593,7 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
return {
|
return {
|
||||||
tier: persistent(tier),
|
tier: persistent(tier),
|
||||||
seed: persistent(seed),
|
seed: persistent(seed),
|
||||||
|
influences: persistent(influences as unknown as State[]),
|
||||||
name,
|
name,
|
||||||
color,
|
color,
|
||||||
resource,
|
resource,
|
||||||
|
@ -539,7 +623,7 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
style="display: inline"
|
style="display: inline"
|
||||||
onClick={() => (showModifiersModal.value = true)}
|
onClick={() => (showModifiersModal.value = true)}
|
||||||
>
|
>
|
||||||
open modifiers
|
modifiers
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</StickyVue>
|
</StickyVue>
|
||||||
|
@ -578,8 +662,23 @@ export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using separate method from what's used in mining, because planes are influenced by influences and not things like dowsing
|
// Using separate method from what's used in mining, because planes are influenced by influences and not things like dowsing
|
||||||
function getRandomResource(random: () => number) {
|
function getRandomResource(random: () => number, influences: InfluenceState[]) {
|
||||||
const sumResourceWeights = (Object.values(mineLootTable) as number[]).reduce((a, b) => a + b);
|
influences = influences.filter(
|
||||||
|
i => i.type === "increaseResources" || i.type === "decreaseResources"
|
||||||
|
);
|
||||||
|
const sumResourceWeights = (Object.keys(mineLootTable) as Resources[]).reduce((a, b) => {
|
||||||
|
let weight = mineLootTable[b];
|
||||||
|
influences
|
||||||
|
.filter(i => i.data === b)
|
||||||
|
.forEach(influence => {
|
||||||
|
if (influence.type === "increaseResources") {
|
||||||
|
weight *= 1000;
|
||||||
|
} else {
|
||||||
|
weight /= 1000;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return a + weight;
|
||||||
|
}, 0);
|
||||||
const resourceWeightsKeys = Object.keys(mineLootTable) as Resources[];
|
const resourceWeightsKeys = Object.keys(mineLootTable) as Resources[];
|
||||||
const r = Math.floor(random() * sumResourceWeights);
|
const r = Math.floor(random() * sumResourceWeights);
|
||||||
let weight = 0;
|
let weight = 0;
|
||||||
|
|
|
@ -66,7 +66,7 @@ export interface EmpowererState {
|
||||||
|
|
||||||
export interface PortalGeneratorState {
|
export interface PortalGeneratorState {
|
||||||
tier: Resources | undefined;
|
tier: Resources | undefined;
|
||||||
influences: string[];
|
influences: Influences[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PortalState {
|
export interface PortalState {
|
||||||
|
@ -74,6 +74,11 @@ export interface PortalState {
|
||||||
powered: boolean;
|
powered: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InfluenceState {
|
||||||
|
type: Influences;
|
||||||
|
data: State;
|
||||||
|
}
|
||||||
|
|
||||||
export const mineLootTable = {
|
export const mineLootTable = {
|
||||||
dirt: 120,
|
dirt: 120,
|
||||||
sand: 60,
|
sand: 60,
|
||||||
|
@ -216,6 +221,95 @@ const passives = {
|
||||||
|
|
||||||
export type Passives = keyof typeof passives;
|
export type Passives = keyof typeof passives;
|
||||||
|
|
||||||
|
export const influences = {
|
||||||
|
increaseResources: {
|
||||||
|
description: (state: InfluenceState) => {
|
||||||
|
const resources = state.data as Resources[];
|
||||||
|
if (resources.length === 0) {
|
||||||
|
return "Increase resource odds - Drag a resource to me!";
|
||||||
|
}
|
||||||
|
if (resources.length === 1) {
|
||||||
|
return `Increase ${resources[0]}'s odds`;
|
||||||
|
}
|
||||||
|
return `Increase ${resources.length} resources' odds`;
|
||||||
|
},
|
||||||
|
cost: 2,
|
||||||
|
initialData: []
|
||||||
|
},
|
||||||
|
decreaseResources: {
|
||||||
|
description: (state: InfluenceState) => {
|
||||||
|
const resources = state.data as Resources[];
|
||||||
|
if (resources.length === 0) {
|
||||||
|
return "Decrease resource odds - Drag a resource to me!";
|
||||||
|
}
|
||||||
|
if (resources.length === 1) {
|
||||||
|
return `Decrease ${resources[0]}'s odds`;
|
||||||
|
}
|
||||||
|
return `Decrease ${resources.length} resources' odds`;
|
||||||
|
},
|
||||||
|
cost: 2,
|
||||||
|
initialData: []
|
||||||
|
},
|
||||||
|
increaseLength: {
|
||||||
|
description: "Increase length",
|
||||||
|
cost: 100,
|
||||||
|
initialData: undefined
|
||||||
|
},
|
||||||
|
increaseCaches: {
|
||||||
|
description: "Increase caches odds",
|
||||||
|
cost: 10,
|
||||||
|
initialData: undefined
|
||||||
|
},
|
||||||
|
increaseGens: {
|
||||||
|
description: "Increase generators odds",
|
||||||
|
cost: 10,
|
||||||
|
initialData: undefined
|
||||||
|
},
|
||||||
|
increaseInfluences: {
|
||||||
|
description: "Increase influences odds",
|
||||||
|
cost: 10,
|
||||||
|
initialData: undefined
|
||||||
|
},
|
||||||
|
increaseEnergyMults: {
|
||||||
|
description: "Increase energy mults odds",
|
||||||
|
cost: 10,
|
||||||
|
initialData: undefined
|
||||||
|
},
|
||||||
|
increaseResourceMults: {
|
||||||
|
description: "Increase resource mults odds",
|
||||||
|
cost: 10,
|
||||||
|
initialData: undefined
|
||||||
|
},
|
||||||
|
increaseDiff: {
|
||||||
|
description: "Increase difficulty/rewards odds",
|
||||||
|
cost: 10,
|
||||||
|
initialData: undefined
|
||||||
|
},
|
||||||
|
decreaseDiff: {
|
||||||
|
description: "Decrease difficulty/rewards odds",
|
||||||
|
cost: 10,
|
||||||
|
initialData: undefined
|
||||||
|
},
|
||||||
|
increaseRewards: {
|
||||||
|
description: "Increase rewards level",
|
||||||
|
cost: 1e4,
|
||||||
|
initialData: undefined
|
||||||
|
}
|
||||||
|
// relic: {
|
||||||
|
// description: "Max length/difficulty, add tier-unique relic",
|
||||||
|
// cost: 1e6,
|
||||||
|
// initialData: undefined
|
||||||
|
// }
|
||||||
|
} as const satisfies Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
description: string | ((state: InfluenceState) => string);
|
||||||
|
cost: DecimalSource;
|
||||||
|
initialData?: State;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
export type Influences = keyof typeof influences;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hidden
|
* @hidden
|
||||||
*/
|
*/
|
||||||
|
@ -242,6 +336,13 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
iron: board.types.portalGenerator.nodes.value[0]
|
iron: board.types.portalGenerator.nodes.value[0]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const influenceNodes: ComputedRef<Record<Influences, BoardNode>> = computed(() => ({
|
||||||
|
...board.types.influence.nodes.value.reduce((acc, curr) => {
|
||||||
|
acc[(curr.state as unknown as InfluenceState).type] = curr;
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<Influences, BoardNode>)
|
||||||
|
}));
|
||||||
|
|
||||||
const resourceLevels = computed(() =>
|
const resourceLevels = computed(() =>
|
||||||
resourceNames.reduce((acc, curr) => {
|
resourceNames.reduce((acc, curr) => {
|
||||||
const amount =
|
const amount =
|
||||||
|
@ -336,11 +437,12 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
id: "deselect",
|
id: "deselect",
|
||||||
icon: "close",
|
icon: "close",
|
||||||
tooltip: (node: BoardNode) => ({
|
tooltip: (node: BoardNode) => ({
|
||||||
text:
|
text: "tools" in (node.state as object) ? "Disconnect tools" : "Disconnect resources"
|
||||||
"resources" in (node.state as object) ? "Disconnect resources" : "Disconnect tools"
|
|
||||||
}),
|
}),
|
||||||
onClick(node: BoardNode) {
|
onClick(node: BoardNode) {
|
||||||
if ("resources" in (node.state as object)) {
|
if (Array.isArray(node.state)) {
|
||||||
|
node.state = [];
|
||||||
|
} else if ("resources" in (node.state as object)) {
|
||||||
node.state = { ...(node.state as object), resources: [] };
|
node.state = { ...(node.state as object), resources: [] };
|
||||||
} else if ("tools" in (node.state as object)) {
|
} else if ("tools" in (node.state as object)) {
|
||||||
node.state = { ...(node.state as object), tools: [] };
|
node.state = { ...(node.state as object), tools: [] };
|
||||||
|
@ -349,6 +451,9 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
board.selectedNode.value = null;
|
board.selectedNode.value = null;
|
||||||
},
|
},
|
||||||
visibility: (node: BoardNode) => {
|
visibility: (node: BoardNode) => {
|
||||||
|
if (Array.isArray(node.state)) {
|
||||||
|
return node.state.length > 0;
|
||||||
|
}
|
||||||
if ("resources" in (node.state as object)) {
|
if ("resources" in (node.state as object)) {
|
||||||
return (node.state as { resources: Resources[] }).resources.length > 0;
|
return (node.state as { resources: Resources[] }).resources.length > 0;
|
||||||
}
|
}
|
||||||
|
@ -886,11 +991,9 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
}-tier portal`
|
}-tier portal`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if ((board as GenericBoard).draggingNode.value?.type === "resource") {
|
const draggingNode = (board as GenericBoard).draggingNode.value;
|
||||||
const resource = (
|
if (draggingNode?.type === "resource") {
|
||||||
(board as GenericBoard).draggingNode.value
|
const resource = (draggingNode.state as unknown as ResourceState).type;
|
||||||
?.state as unknown as ResourceState
|
|
||||||
).type;
|
|
||||||
const text =
|
const text =
|
||||||
(node.state as unknown as PortalGeneratorState).tier === resource
|
(node.state as unknown as PortalGeneratorState).tier === resource
|
||||||
? "Disconnect"
|
? "Disconnect"
|
||||||
|
@ -899,8 +1002,17 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
text,
|
text,
|
||||||
color: "var(--accent2)"
|
color: "var(--accent2)"
|
||||||
};
|
};
|
||||||
|
} else if (draggingNode?.type === "influence") {
|
||||||
|
const influence = (draggingNode.state as unknown as InfluenceState).type;
|
||||||
|
const { influences } = node.state as unknown as PortalGeneratorState;
|
||||||
|
if (influences.includes(influence)) {
|
||||||
|
return { text: "Disconnect", color: "var(--accent2)" };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
text: "Add influence",
|
||||||
|
color: "var(--accent2)"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
// TODO handle influences
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
actionDistance: Math.PI / 4,
|
actionDistance: Math.PI / 4,
|
||||||
|
@ -937,12 +1049,18 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
while (`portal-${id}` in layers) {
|
while (`portal-${id}` in layers) {
|
||||||
id++;
|
id++;
|
||||||
}
|
}
|
||||||
|
const { tier, influences } =
|
||||||
|
node.state as unknown as PortalGeneratorState;
|
||||||
addLayer(
|
addLayer(
|
||||||
createPlane(
|
createPlane(
|
||||||
`portal-${id}`,
|
`portal-${id}`,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
tier!,
|
||||||
(node.state as unknown as PortalGeneratorState).tier!,
|
Math.floor(Math.random() * 4294967296),
|
||||||
Math.floor(Math.random() * 4294967296)
|
influences.map(
|
||||||
|
influence =>
|
||||||
|
influenceNodes.value[influence]
|
||||||
|
.state as unknown as InfluenceState
|
||||||
|
)
|
||||||
),
|
),
|
||||||
player
|
player
|
||||||
);
|
);
|
||||||
|
@ -974,7 +1092,8 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
tier: droppedType === currentType ? undefined : droppedType
|
tier: droppedType === currentType ? undefined : droppedType
|
||||||
};
|
};
|
||||||
} else if (otherNode.type === "influence") {
|
} else if (otherNode.type === "influence") {
|
||||||
const droppedInfluence = otherNode.state as string;
|
const droppedInfluence = (otherNode.state as unknown as InfluenceState)
|
||||||
|
.type;
|
||||||
const currentInfluences = (node.state as unknown as PortalGeneratorState)
|
const currentInfluences = (node.state as unknown as PortalGeneratorState)
|
||||||
.influences;
|
.influences;
|
||||||
if (currentInfluences.includes(droppedInfluence)) {
|
if (currentInfluences.includes(droppedInfluence)) {
|
||||||
|
@ -1022,6 +1141,42 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
outlineColor: node =>
|
outlineColor: node =>
|
||||||
(layers[(node.state as unknown as PortalState).id] as GenericPlane).background,
|
(layers[(node.state as unknown as PortalState).id] as GenericPlane).background,
|
||||||
draggable: true
|
draggable: true
|
||||||
|
},
|
||||||
|
influence: {
|
||||||
|
shape: Shape.Circle,
|
||||||
|
size: 50,
|
||||||
|
title: node => (node.state as unknown as InfluenceState).type,
|
||||||
|
label: node => {
|
||||||
|
if (node === board.selectedNode.value) {
|
||||||
|
const state = node.state as unknown as InfluenceState;
|
||||||
|
const desc = influences[state.type].description;
|
||||||
|
return { text: typeof desc === "function" ? desc(state) : desc };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
actionDistance: Math.PI / 4,
|
||||||
|
actions: [deselectAllAction],
|
||||||
|
canAccept: (node, otherNode) => {
|
||||||
|
if (otherNode.type !== "resource") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Array.isArray(node.state);
|
||||||
|
},
|
||||||
|
onDrop: (node, otherNode) => {
|
||||||
|
if (otherNode.type !== "resource") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const resource = (otherNode.state as unknown as ResourceState).type;
|
||||||
|
const resources = node.state as Resources[];
|
||||||
|
if (resources.includes(resource)) {
|
||||||
|
node.state = resources.filter(r => r !== resource);
|
||||||
|
} else {
|
||||||
|
node.state = [...resources, resource];
|
||||||
|
}
|
||||||
|
board.selectedNode.value = node;
|
||||||
|
},
|
||||||
|
outlineColor: "var(--danger)",
|
||||||
|
draggable: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
|
@ -1098,21 +1253,25 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (portalGenerator.value != null) {
|
if (portalGenerator.value != null) {
|
||||||
if ((portalGenerator.value.state as unknown as PortalGeneratorState).tier != null) {
|
const state = portalGenerator.value.state as unknown as PortalGeneratorState;
|
||||||
|
if (state.tier != null) {
|
||||||
links.push({
|
links.push({
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
startNode: portalGenerator.value,
|
||||||
startNode: portalGenerator.value!,
|
endNode: resourceNodes.value[state.tier],
|
||||||
endNode:
|
|
||||||
resourceNodes.value[
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
(portalGenerator.value.state as unknown as PortalGeneratorState)
|
|
||||||
.tier!
|
|
||||||
],
|
|
||||||
stroke: "var(--foreground)",
|
stroke: "var(--foreground)",
|
||||||
strokeWidth: 4
|
strokeWidth: 4
|
||||||
});
|
});
|
||||||
// TODO link to influences
|
|
||||||
}
|
}
|
||||||
|
state.influences.forEach(influence => {
|
||||||
|
console.log(influence);
|
||||||
|
links.push({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
startNode: portalGenerator.value!,
|
||||||
|
endNode: influenceNodes.value[influence],
|
||||||
|
stroke: "var(--foreground)",
|
||||||
|
strokeWidth: 4
|
||||||
|
});
|
||||||
|
});
|
||||||
(board as GenericBoard).types.portal.nodes.value.forEach(node => {
|
(board as GenericBoard).types.portal.nodes.value.forEach(node => {
|
||||||
const plane = layers[(node.state as unknown as PortalState).id] as GenericPlane;
|
const plane = layers[(node.state as unknown as PortalState).id] as GenericPlane;
|
||||||
plane.links.value.forEach(n => {
|
plane.links.value.forEach(n => {
|
||||||
|
@ -1142,6 +1301,19 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
return links;
|
return links;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Object.values(influenceNodes.value).forEach(node => {
|
||||||
|
const state = node.state as unknown as InfluenceState;
|
||||||
|
if (state.type === "increaseResources" || state.type === "decreaseResources") {
|
||||||
|
(state.data as Resources[]).forEach(resource => {
|
||||||
|
links.push({
|
||||||
|
startNode: node,
|
||||||
|
endNode: resourceNodes.value[resource],
|
||||||
|
stroke: "var(--foreground)",
|
||||||
|
strokeWidth: 4
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
return links;
|
return links;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -1597,6 +1769,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
passives,
|
passives,
|
||||||
resourceNodes,
|
resourceNodes,
|
||||||
toolNodes,
|
toolNodes,
|
||||||
|
influenceNodes,
|
||||||
grantResource,
|
grantResource,
|
||||||
activePortals,
|
activePortals,
|
||||||
display: jsx(() => (
|
display: jsx(() => (
|
||||||
|
@ -1630,7 +1803,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
style="display: inline"
|
style="display: inline"
|
||||||
onClick={() => (showModifiersModal.value = true)}
|
onClick={() => (showModifiersModal.value = true)}
|
||||||
>
|
>
|
||||||
open modifiers
|
modifiers
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
{player.devSpeed === 0 ? (
|
{player.devSpeed === 0 ? (
|
||||||
|
@ -1662,7 +1835,8 @@ export const getInitialLayers = (
|
||||||
createPlane(
|
createPlane(
|
||||||
`portal-${id}`,
|
`portal-${id}`,
|
||||||
layer.tier ?? "dirt",
|
layer.tier ?? "dirt",
|
||||||
layer.seed ?? Math.floor(Math.random() * 4294967296)
|
layer.seed ?? Math.floor(Math.random() * 4294967296),
|
||||||
|
(layer.influences ?? []) as unknown as InfluenceState[]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
id++;
|
id++;
|
||||||
|
|
Loading…
Reference in a new issue