generated from nhcarrigan/template
chore: community feedback fixes and UI improvements #102
@@ -183,6 +183,7 @@ export const defaultQuests: Array<Quest> = [
|
||||
{ amount: 1500, type: "essence" },
|
||||
{ amount: 75, type: "crystals" },
|
||||
{ targetId: "knight_1", type: "upgrade" },
|
||||
{ targetId: "peasant_2", type: "upgrade" },
|
||||
],
|
||||
status: "locked",
|
||||
zoneId: "shadow_marshes",
|
||||
@@ -282,6 +283,7 @@ export const defaultQuests: Array<Quest> = [
|
||||
{ amount: 40_000_000, type: "gold" },
|
||||
{ amount: 12_000, type: "essence" },
|
||||
{ amount: 300, type: "crystals" },
|
||||
{ targetId: "peasant_3", type: "upgrade" },
|
||||
],
|
||||
status: "locked",
|
||||
zoneId: "volcanic_depths",
|
||||
|
||||
@@ -162,6 +162,34 @@ export const defaultUpgrades: Array<Upgrade> = [
|
||||
target: "adventurer",
|
||||
unlocked: false,
|
||||
},
|
||||
{
|
||||
adventurerId: "peasant",
|
||||
costCrystals: 0,
|
||||
costEssence: 20,
|
||||
costGold: 0,
|
||||
description:
|
||||
"Organised labour guilds and proper scheduling make peasants ten times more productive.",
|
||||
id: "peasant_2",
|
||||
multiplier: 10,
|
||||
name: "Guild Organisation",
|
||||
purchased: false,
|
||||
target: "adventurer",
|
||||
unlocked: false,
|
||||
},
|
||||
{
|
||||
adventurerId: "peasant",
|
||||
costCrystals: 50,
|
||||
costEssence: 0,
|
||||
costGold: 0,
|
||||
description:
|
||||
"Magical augmentation through crystalline resonance supercharges even the humblest worker.",
|
||||
id: "peasant_3",
|
||||
multiplier: 50,
|
||||
name: "Crystal Augmentation",
|
||||
purchased: false,
|
||||
target: "adventurer",
|
||||
unlocked: false,
|
||||
},
|
||||
{
|
||||
adventurerId: "militia",
|
||||
costCrystals: 0,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/* eslint-disable max-lines-per-function -- Large header with many resource and action elements */
|
||||
/* eslint-disable complexity -- Many conditional resource and badge render paths */
|
||||
import { useGame } from "../../context/gameContext.js";
|
||||
import { RESOURCE_CAP } from "../../engine/tick.js";
|
||||
import { RESOURCE_CAP, computeGoldPerSecond } from "../../engine/tick.js";
|
||||
import type { Resource } from "@elysium/types";
|
||||
import type { JSX } from "react";
|
||||
|
||||
@@ -80,11 +80,13 @@ const ResourceBar = ({
|
||||
const { formatNumber, syncError, state } = useGame();
|
||||
const { gold, essence, crystals } = resources;
|
||||
let partyCombatPower = 0;
|
||||
let goldPerSecond = 0;
|
||||
if (state !== null) {
|
||||
for (const adventurer of state.adventurers) {
|
||||
const contribution = adventurer.combatPower * adventurer.count;
|
||||
partyCombatPower = partyCombatPower + contribution;
|
||||
}
|
||||
goldPerSecond = computeGoldPerSecond(state);
|
||||
}
|
||||
const resourceValues = [ gold, essence, crystals ];
|
||||
const anyFull = resourceValues.some((v) => {
|
||||
@@ -113,6 +115,11 @@ const ResourceBar = ({
|
||||
</span>
|
||||
: null}
|
||||
</div>
|
||||
<div className="resource">
|
||||
<span className="resource-icon">{"📈"}</span>
|
||||
<span className="resource-value">{formatNumber(goldPerSecond)}</span>
|
||||
<span className="resource-label">{"Gold/s"}</span>
|
||||
</div>
|
||||
<div className={`resource${essenceFull
|
||||
? " resource-full"
|
||||
: ""}`}>
|
||||
|
||||
@@ -123,6 +123,78 @@ const capResource = (value: number): number => {
|
||||
return Math.min(value, RESOURCE_CAP);
|
||||
};
|
||||
|
||||
/**
|
||||
* Pure function — applies one game tick to the state.
|
||||
* DeltaSeconds: time elapsed since last tick.
|
||||
* Returns a new GameState (does not mutate the original).
|
||||
* @param state - The current game state.
|
||||
* @param deltaSeconds - Time elapsed since last tick in seconds.
|
||||
* @returns A new GameState with the tick applied.
|
||||
*/
|
||||
/**
|
||||
* Computes the effective gold earned per second across all adventurers,
|
||||
* including all active multipliers (upgrades, prestige, equipment, etc.).
|
||||
* @param state - The current game state.
|
||||
* @returns Gold per second as a number.
|
||||
*/
|
||||
export const computeGoldPerSecond = (state: GameState): number => {
|
||||
const equippedItems: Array<Equipment> = state.equipment.filter((item) => {
|
||||
return item.equipped;
|
||||
});
|
||||
const equipmentGoldMultiplier = equippedItems.reduce((mult, item) => {
|
||||
return mult * (item.bonus.goldMultiplier ?? 1);
|
||||
}, 1);
|
||||
const setGoldMultiplier = computeSetBonuses(
|
||||
equippedItems.map((item) => {
|
||||
return item.id;
|
||||
}),
|
||||
EQUIPMENT_SETS,
|
||||
).goldMultiplier;
|
||||
|
||||
const runestonesIncome = state.prestige.runestonesIncomeMultiplier ?? 1;
|
||||
const echoIncome = state.transcendence?.echoIncomeMultiplier ?? 1;
|
||||
const craftedGoldMultiplier = state.exploration?.craftedGoldMultiplier ?? 1;
|
||||
const companionBonus = getActiveCompanionBonus(
|
||||
state.companions?.activeCompanionId,
|
||||
state.companions?.unlockedCompanionIds ?? [],
|
||||
);
|
||||
const companionGoldMult
|
||||
= companionBonus?.type === "passiveGold"
|
||||
? 1 + companionBonus.value
|
||||
: 1;
|
||||
|
||||
let goldPerSecond = 0;
|
||||
for (const adventurer of state.adventurers) {
|
||||
if (!adventurer.unlocked || adventurer.count === 0) {
|
||||
continue;
|
||||
}
|
||||
const upgradeMultiplier = state.upgrades.
|
||||
filter((upgrade) => {
|
||||
const isGlobal = upgrade.target === "global";
|
||||
const isThisAdventurer
|
||||
= upgrade.target === "adventurer"
|
||||
&& upgrade.adventurerId === adventurer.id;
|
||||
return upgrade.purchased && (isGlobal || isThisAdventurer);
|
||||
}).
|
||||
reduce((mult, upgrade) => {
|
||||
return mult * upgrade.multiplier;
|
||||
}, 1);
|
||||
const contribution
|
||||
= adventurer.goldPerSecond
|
||||
* adventurer.count
|
||||
* upgradeMultiplier
|
||||
* state.prestige.productionMultiplier
|
||||
* runestonesIncome
|
||||
* echoIncome
|
||||
* equipmentGoldMultiplier
|
||||
* setGoldMultiplier
|
||||
* craftedGoldMultiplier
|
||||
* companionGoldMult;
|
||||
goldPerSecond = goldPerSecond + contribution;
|
||||
}
|
||||
return goldPerSecond;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pure function — applies one game tick to the state.
|
||||
* DeltaSeconds: time elapsed since last tick.
|
||||
|
||||
Reference in New Issue
Block a user