mirror of
https://github.com/thepaperpilot/Planar-Pioneers.git
synced 2024-11-21 16:13:54 +00:00
Setup basic mining mechanic
This commit is contained in:
parent
e892341140
commit
0f68a188c9
4 changed files with 200 additions and 124 deletions
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
@ -8,5 +8,7 @@
|
|||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"volar.autoCompleteRefs": false,
|
||||
"emmet.showExpandedAbbreviation": "never"
|
||||
}
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
/**
|
||||
* @module
|
||||
* @hidden
|
||||
*/
|
||||
import { main } from "data/projEntry";
|
||||
import { createCumulativeConversion } from "features/conversion";
|
||||
import { jsx } from "features/feature";
|
||||
import { createHotkey } from "features/hotkey";
|
||||
import { createReset } from "features/reset";
|
||||
import MainDisplay from "features/resources/MainDisplay.vue";
|
||||
import { createResource } from "features/resources/resource";
|
||||
import { addTooltip } from "features/tooltips/tooltip";
|
||||
import { createResourceTooltip } from "features/trees/tree";
|
||||
import { BaseLayer, createLayer } from "game/layers";
|
||||
import type { DecimalSource } from "util/bignum";
|
||||
import { render } from "util/vue";
|
||||
import { createLayerTreeNode, createResetButton } from "../common";
|
||||
|
||||
const id = "p";
|
||||
const layer = createLayer(id, function (this: BaseLayer) {
|
||||
const name = "Prestige";
|
||||
const color = "#4BDC13";
|
||||
const points = createResource<DecimalSource>(0, "prestige points");
|
||||
|
||||
const conversion = createCumulativeConversion(() => ({
|
||||
formula: x => x.div(10).sqrt(),
|
||||
baseResource: main.points,
|
||||
gainResource: points
|
||||
}));
|
||||
|
||||
const reset = createReset(() => ({
|
||||
thingsToReset: (): Record<string, unknown>[] => [layer]
|
||||
}));
|
||||
|
||||
const treeNode = createLayerTreeNode(() => ({
|
||||
layerID: id,
|
||||
color,
|
||||
reset
|
||||
}));
|
||||
addTooltip(treeNode, {
|
||||
display: createResourceTooltip(points),
|
||||
pinnable: true
|
||||
});
|
||||
|
||||
const resetButton = createResetButton(() => ({
|
||||
conversion,
|
||||
tree: main.tree,
|
||||
treeNode
|
||||
}));
|
||||
|
||||
const hotkey = createHotkey(() => ({
|
||||
description: "Reset for prestige points",
|
||||
key: "p",
|
||||
onPress: resetButton.onClick
|
||||
}));
|
||||
|
||||
return {
|
||||
name,
|
||||
color,
|
||||
points,
|
||||
display: jsx(() => (
|
||||
<>
|
||||
<MainDisplay resource={points} color={color} />
|
||||
{render(resetButton)}
|
||||
</>
|
||||
)),
|
||||
treeNode,
|
||||
hotkey
|
||||
};
|
||||
});
|
||||
|
||||
export default layer;
|
|
@ -1,51 +1,208 @@
|
|||
import Spacer from "components/layout/Spacer.vue";
|
||||
import {
|
||||
BoardNode,
|
||||
ProgressDisplay,
|
||||
Shape,
|
||||
createBoard,
|
||||
getUniqueNodeID
|
||||
} from "features/boards/board";
|
||||
import { jsx } from "features/feature";
|
||||
import { createResource, trackBest, trackOOMPS, trackTotal } from "features/resources/resource";
|
||||
import type { GenericTree } from "features/trees/tree";
|
||||
import { branchedResetPropagation, createTree } from "features/trees/tree";
|
||||
import { globalBus } from "game/events";
|
||||
import MainDisplay from "features/resources/MainDisplay.vue";
|
||||
import { createResource } from "features/resources/resource";
|
||||
import Formula, { calculateCost } from "game/formulas/formulas";
|
||||
import type { BaseLayer, GenericLayer } from "game/layers";
|
||||
import { createLayer } from "game/layers";
|
||||
import { State } from "game/persistence";
|
||||
import type { Player } from "game/player";
|
||||
import player from "game/player";
|
||||
import type { DecimalSource } from "util/bignum";
|
||||
import Decimal, { format, formatTime } from "util/bignum";
|
||||
import Decimal, { DecimalSource } from "lib/break_eternity";
|
||||
import { format, formatTime } from "util/bignum";
|
||||
import { render } from "util/vue";
|
||||
import { computed, toRaw } from "vue";
|
||||
import prestige from "./layers/prestige";
|
||||
import { ComputedRef, computed, reactive } from "vue";
|
||||
|
||||
export interface ResourceState {
|
||||
type: Resources;
|
||||
amount: DecimalSource;
|
||||
}
|
||||
|
||||
const mineLootTable = {
|
||||
dirt: 120,
|
||||
sand: 60,
|
||||
gravel: 40,
|
||||
wood: 30,
|
||||
stone: 24,
|
||||
coal: 20,
|
||||
copper: 15,
|
||||
iron: 12,
|
||||
silver: 10,
|
||||
gold: 8,
|
||||
emerald: 6,
|
||||
platinum: 5,
|
||||
diamond: 4,
|
||||
berylium: 3,
|
||||
unobtainium: 2,
|
||||
ultimatum: 1
|
||||
} as const;
|
||||
|
||||
export type Resources = keyof typeof mineLootTable;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
export const main = createLayer("main", function (this: BaseLayer) {
|
||||
const points = createResource<DecimalSource>(10);
|
||||
const best = trackBest(points);
|
||||
const total = trackTotal(points);
|
||||
const energy = createResource<DecimalSource>(0, "energy");
|
||||
|
||||
const pointGain = computed(() => {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let gain = new Decimal(1);
|
||||
return gain;
|
||||
});
|
||||
globalBus.on("update", diff => {
|
||||
points.value = Decimal.add(points.value, Decimal.times(pointGain.value, diff));
|
||||
});
|
||||
const oomps = trackOOMPS(points, pointGain);
|
||||
const resourceLevelFormula = Formula.variable(0).add(1);
|
||||
function getResourceLevel(amount: DecimalSource) {
|
||||
const currentLevel = Decimal.floor(
|
||||
resourceLevelFormula.invertIntegral(
|
||||
Decimal.add(amount, resourceLevelFormula.evaluateIntegral())
|
||||
)
|
||||
);
|
||||
// TODO sum last x purchases?
|
||||
const requiredForCurrentLevel = calculateCost(resourceLevelFormula, currentLevel, true);
|
||||
const requiredForNextLevel = calculateCost(
|
||||
resourceLevelFormula,
|
||||
Decimal.add(currentLevel, 1),
|
||||
true
|
||||
);
|
||||
return Decimal.sub(amount, requiredForCurrentLevel)
|
||||
.div(Decimal.sub(requiredForNextLevel, requiredForCurrentLevel))
|
||||
.toNumber();
|
||||
}
|
||||
|
||||
const tree = createTree(() => ({
|
||||
nodes: [[prestige.treeNode]],
|
||||
branches: [],
|
||||
onReset() {
|
||||
points.value = toRaw(this.resettingNode.value) === toRaw(prestige.treeNode) ? 0 : 10;
|
||||
best.value = points.value;
|
||||
total.value = points.value;
|
||||
const resourceMinedCooldown: Partial<Record<Resources, number>> = reactive({});
|
||||
|
||||
const board = createBoard(board => ({
|
||||
startNodes: () => [{ position: { x: 0, y: 0 }, type: "mine", state: 0 }],
|
||||
types: {
|
||||
mine: {
|
||||
shape: Shape.Diamond,
|
||||
size: 50,
|
||||
title: "Mine",
|
||||
label: node => (node === board.selectedNode.value ? null : { text: "Click me!" }),
|
||||
progress: node =>
|
||||
node == board.selectedNode.value
|
||||
? new Decimal(node.state as DecimalSource).toNumber()
|
||||
: 0,
|
||||
progressDisplay: ProgressDisplay.Outline,
|
||||
progressColor: "var(--accent2)"
|
||||
},
|
||||
resource: {
|
||||
shape: Shape.Circle,
|
||||
size: 50,
|
||||
title: node => (node.state as unknown as ResourceState).type,
|
||||
progress: node => getResourceLevel((node.state as unknown as ResourceState).amount),
|
||||
progressDisplay: ProgressDisplay.Outline,
|
||||
progressColor: "var(--accent3)",
|
||||
draggable: true
|
||||
}
|
||||
},
|
||||
resetPropagation: branchedResetPropagation
|
||||
})) as GenericTree;
|
||||
style: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
overflow: "hidden"
|
||||
},
|
||||
links() {
|
||||
const mine = board.nodes.value.find(n => n.type === "mine") as BoardNode;
|
||||
return Object.keys(resourceMinedCooldown).map(resource => ({
|
||||
startNode: mine,
|
||||
endNode: resourceNodes.value[resource as Resources],
|
||||
stroke: "var(--accent3)",
|
||||
strokeWidth: 5
|
||||
}));
|
||||
}
|
||||
}));
|
||||
|
||||
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) {
|
||||
let node = resourceNodes.value[type];
|
||||
if (node == null) {
|
||||
let x = 0;
|
||||
x = board.nodes.value
|
||||
.filter(n => n.position.y < 50 && n.position.y > -50)
|
||||
.reduce((x, node) => Math.max(x, node.position.x + 100), 0);
|
||||
node = {
|
||||
id: getUniqueNodeID(board),
|
||||
position: { x, y: 0 },
|
||||
type: "resource",
|
||||
state: { type, amount }
|
||||
};
|
||||
board.nodes.value.push(node);
|
||||
} else {
|
||||
const state = node.state as unknown as ResourceState;
|
||||
node.state = {
|
||||
...state,
|
||||
amount: Decimal.add(state.amount, amount)
|
||||
} as unknown as State;
|
||||
}
|
||||
}
|
||||
|
||||
// Amount of completions that could give you the exact average of each item without any partials
|
||||
const sumMineWeights = (Object.values(mineLootTable) as number[]).reduce((a, b) => a + b);
|
||||
const resourceNames = Object.keys(mineLootTable) as Resources[];
|
||||
|
||||
this.on("preUpdate", diff => {
|
||||
Object.keys(resourceMinedCooldown).forEach(resource => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
resourceMinedCooldown[resource as Resources]! -= diff;
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
if (resourceMinedCooldown[resource as Resources]! <= 0) {
|
||||
delete resourceMinedCooldown[resource as Resources];
|
||||
}
|
||||
});
|
||||
|
||||
if (board.selectedNode.value?.type === "mine") {
|
||||
const mine = board.selectedNode.value;
|
||||
const progress = Decimal.add(mine.state as DecimalSource, diff);
|
||||
const completions = progress.floor();
|
||||
mine.state = Decimal.sub(progress, completions);
|
||||
const allResourceCompletions = completions.div(sumMineWeights).floor();
|
||||
if (allResourceCompletions.gt(0)) {
|
||||
resourceNames.forEach(resource => {
|
||||
grantResource(
|
||||
resource as Resources,
|
||||
Decimal.times(
|
||||
mineLootTable[resource as Resources] as number,
|
||||
allResourceCompletions
|
||||
)
|
||||
);
|
||||
resourceMinedCooldown[resource as Resources] = 0.3;
|
||||
});
|
||||
}
|
||||
const remainder = Decimal.sub(completions, allResourceCompletions).toNumber();
|
||||
for (let i = 0; i < remainder; i++) {
|
||||
const random = Math.floor(Math.random() * sumMineWeights);
|
||||
let weight = 0;
|
||||
for (let i = 0; i < resourceNames.length; i++) {
|
||||
const resource = resourceNames[i];
|
||||
weight += mineLootTable[resource];
|
||||
if (random <= weight) {
|
||||
grantResource(resource, 1);
|
||||
resourceMinedCooldown[resource] = 0.3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO increment energy based on its modifier
|
||||
});
|
||||
|
||||
return {
|
||||
name: "Tree",
|
||||
links: tree.links,
|
||||
name: "World",
|
||||
board,
|
||||
energy,
|
||||
display: jsx(() => (
|
||||
<>
|
||||
{player.devSpeed === 0 ? <div>Game Paused</div> : null}
|
||||
|
@ -55,21 +212,10 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
{player.offlineTime != null && player.offlineTime !== 0 ? (
|
||||
<div>Offline Time: {formatTime(player.offlineTime)}</div>
|
||||
) : null}
|
||||
<div>
|
||||
{Decimal.lt(points.value, "1e1000") ? <span>You have </span> : null}
|
||||
<h2>{format(points.value)}</h2>
|
||||
{Decimal.lt(points.value, "1e1e6") ? <span> points</span> : null}
|
||||
</div>
|
||||
{Decimal.gt(pointGain.value, 0) ? <div>({oomps.value})</div> : null}
|
||||
<Spacer />
|
||||
{render(tree)}
|
||||
<MainDisplay resource={energy} />
|
||||
{render(board)}
|
||||
</>
|
||||
)),
|
||||
points,
|
||||
best,
|
||||
total,
|
||||
oomps,
|
||||
tree
|
||||
))
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -80,7 +226,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
export const getInitialLayers = (
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||
player: Partial<Player>
|
||||
): Array<GenericLayer> => [main, prestige];
|
||||
): Array<GenericLayer> => [main];
|
||||
|
||||
/**
|
||||
* A computed ref whose value is true whenever the game is over.
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"$schema": "./projInfo-schema.json",
|
||||
|
||||
"title": "Profectus",
|
||||
"description": "A project made in Profectus",
|
||||
"id": "",
|
||||
"author": "",
|
||||
"title": "Planar Pioneers",
|
||||
"description": "A game about controlling and exploiting planes!",
|
||||
"id": "planar-pioneers",
|
||||
"author": "thepaperpilot",
|
||||
"discordName": "",
|
||||
"discordLink": "",
|
||||
|
||||
|
|
Loading…
Reference in a new issue