feat: show affected adventurer name on upgrade cards (#70)
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m7s
CI / Lint, Build & Test (push) Successful in 1m9s

## Summary

- Adds a `🗡️ Affects: {Name}` label to upgrade cards that target a specific adventurer
- Resolves player confusion caused by class-based language (e.g. "doubles cleric output") without specifying which adventurer tiers count as that class
- Label appears in all three card states: available, purchased, and locked

## Test plan

- [ ] Verify adventurer-targeted upgrade cards display the correct adventurer name
- [ ] Verify global, click, boss, and prestige upgrade cards show no affects label
- [ ] Confirm lint, build, and tests all pass

Closes #56

Reviewed-on: #70
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #70.
This commit is contained in:
2026-03-19 11:29:29 -07:00
committed by Naomi Carrigan
parent ca2edb090e
commit 7e10757e68
+34 -2
View File
@@ -11,7 +11,7 @@ import { type JSX, useState } from "react";
import { useGame } from "../../context/gameContext.js"; import { useGame } from "../../context/gameContext.js";
import { cdnImage } from "../../utils/cdn.js"; import { cdnImage } from "../../utils/cdn.js";
import { LockToggle } from "../ui/lockToggle.js"; import { LockToggle } from "../ui/lockToggle.js";
import type { Upgrade } from "@elysium/types"; import type { Adventurer, Upgrade } from "@elysium/types";
interface UpgradeCardProperties { interface UpgradeCardProperties {
readonly upgrade: Upgrade; readonly upgrade: Upgrade;
@@ -20,6 +20,7 @@ interface UpgradeCardProperties {
readonly currentCrystals: number; readonly currentCrystals: number;
readonly unlockHint: string | undefined; readonly unlockHint: string | undefined;
readonly formatNumber: (n: number)=> string; readonly formatNumber: (n: number)=> string;
readonly adventurers: ReadonlyArray<Adventurer>;
} }
/** /**
@@ -31,6 +32,7 @@ interface UpgradeCardProperties {
* @param props.currentCrystals - The current crystals amount. * @param props.currentCrystals - The current crystals amount.
* @param props.unlockHint - Optional hint for how to unlock this upgrade. * @param props.unlockHint - Optional hint for how to unlock this upgrade.
* @param props.formatNumber - The number formatting utility function. * @param props.formatNumber - The number formatting utility function.
* @param props.adventurers - The list of adventurers, used to resolve the affected adventurer name.
* @returns The JSX element. * @returns The JSX element.
*/ */
const UpgradeCard = ({ const UpgradeCard = ({
@@ -40,8 +42,14 @@ const UpgradeCard = ({
currentCrystals, currentCrystals,
unlockHint, unlockHint,
formatNumber, formatNumber,
adventurers,
}: UpgradeCardProperties): JSX.Element => { }: UpgradeCardProperties): JSX.Element => {
const { buyUpgrade } = useGame(); const { buyUpgrade } = useGame();
const adventurerName = upgrade.adventurerId === undefined
? undefined
: adventurers.find((adventurer) => {
return adventurer.id === upgrade.adventurerId;
})?.name;
const canAfford const canAfford
= currentGold >= upgrade.costGold = currentGold >= upgrade.costGold
&& currentEssence >= upgrade.costEssence && currentEssence >= upgrade.costEssence
@@ -64,6 +72,13 @@ const UpgradeCard = ({
{upgrade.name} {upgrade.name}
</span> </span>
<span className="upgrade-desc">{upgrade.description}</span> <span className="upgrade-desc">{upgrade.description}</span>
{adventurerName === undefined
? null
: <span className="upgrade-target">
{"🗡️ Affects: "}
{adventurerName}
</span>
}
</div> </div>
); );
} }
@@ -79,6 +94,13 @@ const UpgradeCard = ({
<div className="upgrade-info"> <div className="upgrade-info">
<h3>{upgrade.name}</h3> <h3>{upgrade.name}</h3>
<p>{upgrade.description}</p> <p>{upgrade.description}</p>
{adventurerName === undefined
? null
: <p className="upgrade-target">
{"🗡️ Affects: "}
{adventurerName}
</p>
}
<p className="upgrade-multiplier"> <p className="upgrade-multiplier">
{"×"} {"×"}
{upgrade.multiplier} {upgrade.multiplier}
@@ -130,6 +152,13 @@ const UpgradeCard = ({
{upgrade.name} {upgrade.name}
</h3> </h3>
<p>{upgrade.description}</p> <p>{upgrade.description}</p>
{adventurerName === undefined
? null
: <p className="upgrade-target">
{"🗡️ Affects: "}
{adventurerName}
</p>
}
<p className="upgrade-multiplier"> <p className="upgrade-multiplier">
{"×"} {"×"}
{upgrade.multiplier} {upgrade.multiplier}
@@ -181,7 +210,7 @@ const UpgradePanel = (): JSX.Element => {
); );
} }
const { bosses, quests, upgrades, resources } = state; const { adventurers, bosses, quests, upgrades, resources } = state;
const purchased = upgrades.filter((upgrade) => { const purchased = upgrades.filter((upgrade) => {
return upgrade.purchased; return upgrade.purchased;
}); });
@@ -240,6 +269,7 @@ const UpgradePanel = (): JSX.Element => {
{available.map((upgrade) => { {available.map((upgrade) => {
return ( return (
<UpgradeCard <UpgradeCard
adventurers={adventurers}
currentCrystals={resources.crystals} currentCrystals={resources.crystals}
currentEssence={resources.essence} currentEssence={resources.essence}
currentGold={resources.gold} currentGold={resources.gold}
@@ -253,6 +283,7 @@ const UpgradePanel = (): JSX.Element => {
{purchased.map((upgrade) => { {purchased.map((upgrade) => {
return ( return (
<UpgradeCard <UpgradeCard
adventurers={adventurers}
currentCrystals={resources.crystals} currentCrystals={resources.crystals}
currentEssence={resources.essence} currentEssence={resources.essence}
currentGold={resources.gold} currentGold={resources.gold}
@@ -267,6 +298,7 @@ const UpgradePanel = (): JSX.Element => {
? locked.map((upgrade) => { ? locked.map((upgrade) => {
return ( return (
<UpgradeCard <UpgradeCard
adventurers={adventurers}
currentCrystals={resources.crystals} currentCrystals={resources.crystals}
currentEssence={resources.essence} currentEssence={resources.essence}
currentGold={resources.gold} currentGold={resources.gold}