Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
243 changes: 178 additions & 65 deletions src/client/hud/layers/RadialMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import { Controller } from "../../Controller";
import { CloseViewEvent } from "../../InputHandler";
import { PlaySoundEffectEvent } from "../../sound/Sounds";
import { getSvgAspectRatio, translateText } from "../../Utils";
import { getSvgAspectRatio, renderDuration, translateText } from "../../Utils";
import {
CenterButtonElement,
COLORS,
MenuElement,
MenuElementParams,
TooltipKey,
Expand Down Expand Up @@ -332,10 +333,20 @@
.attr("d", arc)
.attr("fill", (d) => {
const disabled = this.params === null || d.data.disabled(this.params);
const color = disabled
? this.config.disabledColor
: (resolveColor(d.data, this.params) ?? "#1e3a5f");
const opacity = disabled ? 0.4 : 0.82;

const isAllianceCooldown =
d.data.id === "ally_request" &&
(this.params?.playerActions?.interaction
?.allianceRequestCooldownRemaining ?? 0) > 0;

const color = isAllianceCooldown
? COLORS.allianceTimeLeft
: disabled
? this.config.disabledColor
: (resolveColor(d.data, this.params) ?? "#1e3a5f");

//const opacity = isAllianceCooldown ? 0.82 : disabled ? 0.4 : 1;
const opacity = disabled ? 0.4 : 1;

if (d.data.id === this.selectedItemId && this.currentLevel > level) {
return color;
Expand All @@ -349,9 +360,18 @@
? "not-allowed"
: "pointer",
)
.style("opacity", (d) =>
this.params === null || d.data.disabled(this.params) ? 0.5 : 1,
)

.style("opacity", (d) => {
const disabled = this.params === null || d.data.disabled(this.params);
const isAllianceCooldown =

Check failure on line 366 in src/client/hud/layers/RadialMenu.ts

View workflow job for this annotation

GitHub Actions / 🔍 Lint

'isAllianceCooldown' is assigned a value but never used. (@typescript-eslint/no-unused-vars)
d.data.id === "ally_request" &&
(this.params?.playerActions?.interaction
?.allianceRequestCooldownRemaining ?? 0) > 0;
//to remove the fade down change 0.85 to 1
//return isAllianceCooldown ? 0.82 : disabled ? 0.4 : 1;
return disabled ? 0.4 : 1;
})

.style(
"transition",
`filter ${this.config.menuTransitionDuration / 2}ms, fill ${this.config.menuTransitionDuration / 2}ms`,
Expand All @@ -362,11 +382,11 @@
arcs.each((d) => {
if (d.data.timerFraction && this.params) {
const fraction = d.data.timerFraction(this.params);
const disabled = this.params === null || d.data.disabled(this.params);
const disabled = d.data.disabled(this.params);
const baseColor = disabled
? this.config.disabledColor
: (resolveColor(d.data, this.params) ?? "#1e3a5f");
const opacity = disabled ? 0.4 : 0.82;
const opacity = disabled ? 0.4 : 0.82;

const normalColor =
d3.color(baseColor)?.copy({ opacity: opacity })?.toString() ??
Expand Down Expand Up @@ -419,11 +439,25 @@
) {
path.attr("filter", "url(#glow)");

const color =
this.params === null || d.data.disabled(this.params)
const isAllianceCooldown =
d.data.id === "ally_request" &&
(this.params?.playerActions?.interaction
?.allianceRequestCooldownRemaining ?? 0) > 0;
const color = isAllianceCooldown
? COLORS.allianceTimeLeft
: this.params === null || d.data.disabled(this.params)
? this.config.disabledColor
: (resolveColor(d.data, this.params) ?? "#1e3a5f");
path.attr("fill", color);

const opacity = isAllianceCooldown
? 0.82
: this.params === null || d.data.disabled(this.params)
? 0.4
: 0.82;
path.attr(
"fill",
d3.color(color)?.copy({ opacity: opacity })?.toString() ?? color,
);
}
});

Expand Down Expand Up @@ -484,13 +518,27 @@
)
return;
path.style("filter", null);
const color = disabled
? this.config.disabledColor
: (resolveColor(d.data, this.params) ?? "#333333");
const opacity = disabled ? 0.4 : 0.82;
const isAllianceCooldown =
d.data.id === "ally_request" &&
(this.params?.playerActions?.interaction
?.allianceRequestCooldownRemaining ?? 0) > 0;
const color = isAllianceCooldown
? COLORS.allianceTimeLeft
: disabled
? this.config.disabledColor
: (resolveColor(d.data, this.params) ?? "#333333");
//const opacity = isAllianceCooldown ? 0.82 : disabled ? 0.4 : 0.82;
const opacity = disabled ? 0.4 : 0.82

if (d.data.timerFraction) {
path.attr("fill", `url(#timer-gradient-${d.data.id})`);
//something has to go here

path.attr(
"fill",
d3.color(color)?.copy({ opacity: opacity })?.toString() ?? color,
);

//path.attr("fill", `url(#timer-gradient-${d.data.id})`);
} else {
path.attr(
"fill",
Expand Down Expand Up @@ -596,6 +644,15 @@
const contentId = d.data.id;
const content = d3.select(`g[data-id="${contentId}"]`);
const disabled = this.isItemDisabled(d.data);
const isAllianceCooldown =
d.data.id === "ally_request" &&
(this.params?.playerActions?.interaction
?.allianceRequestCooldownRemaining ?? 0) > 0;

content.attr(
"data-cooldown-active",
isAllianceCooldown ? "true" : "false",
);

if (d.data.renderType && this.params) {
const stateKey = this.getStateKeyByType(
Expand Down Expand Up @@ -627,7 +684,7 @@
.attr("fill", "white")
.attr("font-size", d.data.fontSize ?? "12px")
.attr("font-family", "Arial, sans-serif")
.style("opacity", disabled ? 0.5 : 1)
.style("opacity", isAllianceCooldown ? 0.82 : disabled ? 0.5 : 1)
.text(d.data.text);
} else {
const imgSel = content
Expand All @@ -637,18 +694,20 @@
.attr("height", this.config.iconSize)
.attr("x", arc.centroid(d)[0] - this.config.iconSize / 2)
.attr("y", arc.centroid(d)[1] - this.config.iconSize / 2)
.attr("opacity", disabled ? 0.5 : 1);
.attr("opacity", isAllianceCooldown ? 0.82 : disabled ? 0.5 : 1);

getSvgAspectRatio(d.data.icon!).then((aspect) => {
if (!aspect || aspect === 1) return;

let width = this.config.iconSize;
let height = this.config.iconSize;
const biggerLength = Math.round(width * aspect);
if (aspect > 1) {
width = biggerLength;
} else {
height = biggerLength;

if (aspect !== null && aspect !== 1) {
const biggerLength = Math.round(width * aspect);

if (aspect > 1) {
width = biggerLength;
} else {
height = biggerLength;
}
}

imgSel
Expand All @@ -660,14 +719,16 @@

if (this.params && d.data.cooldown?.(this.params)) {
const cooldown = Math.ceil(d.data.cooldown?.(this.params));

content
.append("text")
.attr("class", `cooldown-text`)
.text(cooldown + "s")
.text(renderDuration(cooldown))
.attr("fill", "white")
.attr("opacity", disabled ? 0.5 : 1)
.attr("font-size", "14px")
.attr("opacity", isAllianceCooldown ? 0.82 : disabled ? 0.5 : 1)
.attr("font-size", "20px")
.attr("font-weight", "bold")
.attr("text-anchor", "middle")
.attr("x", arc.centroid(d)[0] - this.config.iconSize / 4)
.attr("y", arc.centroid(d)[1] + this.config.iconSize / 2 + 7);
}
Expand Down Expand Up @@ -1119,20 +1180,25 @@
this.menuPaths.forEach((path, itemId) => {
const item = this.findMenuItem(itemId);
if (item) {
const isAllianceCooldown =
item.id === "ally_request" &&
(this.params?.playerActions?.interaction
?.allianceRequestCooldownRemaining ?? 0) > 0;
const disabled = this.isItemDisabled(item);
const color = disabled
? this.config.disabledColor
: (resolveColor(item, this.params) ?? "#333333");
const opacity = disabled ? 0.4 : 0.82;

const color = isAllianceCooldown
? COLORS.allianceTimeLeft
: disabled
? this.config.disabledColor
: (resolveColor(item, this.params) ?? "#333333");
const opacity = isAllianceCooldown ? 0.82 : disabled ? 0.4 : 0.82;
// Update path appearance (skip fill for timer items — gradient handles it)
if (!item.timerFraction) {
path.attr(
"fill",
d3.color(color)?.copy({ opacity: opacity })?.toString() ?? color,
);
}
path.style("opacity", disabled ? 0.5 : 1);
path.style("opacity", isAllianceCooldown ? 0.82 : disabled ? 0.5 : 1);
path.style("cursor", disabled ? "not-allowed" : "pointer");

// Update icon/text appearance using the same logic as renderIconsAndText
Expand All @@ -1144,27 +1210,54 @@
// Update text opacity
const textElement = icon.select("text");
if (!textElement.empty()) {
textElement.style("opacity", disabled ? 0.5 : 1);
textElement.style(
"opacity",
isAllianceCooldown ? 0.82 : disabled ? 0.5 : 1,
);
}

// Update image opacity
// Update image opacity and position
const imageElement = icon.select("image");
if (!imageElement.empty()) {
imageElement.attr("opacity", disabled ? 0.5 : 1);

imageElement.attr(
"opacity",
isAllianceCooldown ? 0.82 : disabled ? 0.5 : 1,
);
}

// Update cooldown text if applicable
const cooldownElement = icon.select(".cooldown-text");
if (this.params && !cooldownElement.empty() && item.cooldown) {
if (this.params && item.cooldown) {
const cooldown = Math.ceil(item.cooldown(this.params));
let cooldownText = icon.select<SVGTextElement>(".cooldown-text");

if (cooldown <= 0) {
cooldownElement.remove();
cooldownText.remove();
} else {
cooldownElement.text(cooldown + "s");
if (cooldownText.empty()) {
const cx = parseFloat(icon.attr("data-cx") ?? "0");
const cy = parseFloat(icon.attr("data-cy") ?? "0");

cooldownText = icon
.append("text")
.attr("class", "cooldown-text")
.attr("fill", "white")
.attr("font-size", "20px")
.attr("font-weight", "bold")
.attr("text-anchor", "middle")
.attr("x", cx)
.attr("y", cy + this.config.iconSize / 2 + 7);
}

cooldownText
.text(renderDuration(cooldown))
.attr(
"opacity",
isAllianceCooldown ? 0.82 : disabled ? 0.5 : 1,
);
}
}
}

// Update timer gradient
this.maybeUpdateTimerGradient(item, color, opacity);
}
Expand All @@ -1191,29 +1284,39 @@
);
const prevState = icon.attr("data-prev-state");

if (stateKey && stateKey === prevState) {
// State unchanged, skip re-render to preserve animations
} else {
const cx = parseFloat(icon.attr("data-cx") || "0");
const cy = parseFloat(icon.attr("data-cy") || "0");
const cooldownActive =
(this.params?.playerActions?.interaction
?.allianceRequestCooldownRemaining ?? 0) > 0;

if (stateKey) {
icon.attr("data-prev-state", stateKey);
} else {
icon.selectAll("*").remove();
}
const previousCooldownActive = icon.attr("data-cooldown-active") === "true";

this.renderAllyExtendIcon(
icon.node()! as SVGGElement,
cx,
cy,
this.config.iconSize,
disabled,
this.params,
item.icon,
true,
);
const cooldownChanged = cooldownActive !== previousCooldownActive;

const stateChanged = stateKey !== prevState;

if (!cooldownChanged && !stateChanged) {
return;
}

icon.attr("data-cooldown-active", cooldownActive ? "true" : "false");

const cx = parseFloat(icon.attr("data-cx") || "0");
const cy = parseFloat(icon.attr("data-cy") || "0");

if (stateKey) {
icon.attr("data-prev-state", stateKey);
// State unchanged, skip re-render to preserve animations
}
this.renderAllyExtendIcon(
icon.node()! as SVGGElement,
cx,
cy,
this.config.iconSize,
disabled,
this.params,
item.icon,
true,
);
}

private maybeUpdateTimerGradient(
Expand All @@ -1224,7 +1327,6 @@
if (!item.timerFraction || !this.params) {
return;
}

const fraction = item.timerFraction(this.params);
const gradient = this.menuElement.select(`#timer-gradient-${item.id}`);
if (!gradient.empty()) {
Expand Down Expand Up @@ -1279,6 +1381,11 @@
icon?: string,
update?: boolean,
): void {
const generation =
Number(content.getAttribute("data-render-generation") ?? "0") + 1;

content.setAttribute("data-render-generation", generation.toString());

if (update) {
while (content.firstChild) content.removeChild(content.firstChild);
}
Expand All @@ -1292,6 +1399,12 @@
const iconUrl = icon ?? "";

getSvgAspectRatio(iconUrl).then((ratio) => {
if (
Number(content.getAttribute("data-render-generation")) !== generation
) {
return;
}

const width = smallSize * (ratio ?? 1);
const gap = 2;
const totalWidth = width * 2 + gap;
Expand Down
Loading
Loading