WebGL: show alliance request+duration icon, show ally and team mate targets too, some optimization (#3971)

## Description:

Show nuke icons during replay too (when there's no localPlayer).
Show alliance request envelope icon, and duration in alliance icon
(weren't calculated yet).
Show ally and team mates' targets too (weren't calculated yet).

Remove unnecessary allocations. Nukes loop allocated two new sets,
transitive targets was a new set and now uses predicate with fallback to
localPlayer.targets, localPlayer.allies and localPlayer.embargoes were
both put in new set instead of using .includes directly.

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

tryout33
This commit is contained in:
VariableVince
2026-05-20 03:17:26 +02:00
committed by GitHub
parent c82b078dab
commit 513057a62c
4 changed files with 137 additions and 66 deletions
+7 -1
View File
@@ -474,9 +474,15 @@ export class GameView implements GameMap {
f.railroadDirty = this.railroadCache.railroadDirty;
f.trailDirtyRowMin = this.trailManager.dirtyRowMin;
f.trailDirtyRowMax = this.trailManager.dirtyRowMax;
f.playerStatus = computePlayerStatus(this._playerStates, this._unitStates, {
localPlayerID: this._myPlayer?.smallID() ?? 0,
localPlayerSmallID: this._myPlayer?.smallID() ?? 0,
localPlayerID: this._myPlayer?.id() ?? "",
tileState: this._map.tileStateBuffer(),
tick: gu.tick,
allianceDuration: this._config.allianceDuration(),
isTransitiveTarget: (sid) =>
this._myPlayer?.hasTransitiveTarget(sid) ?? false,
});
const rel = buildRelationMatrix(this._playerStates);
f.relationMatrix = rel.matrix;
+26
View File
@@ -522,6 +522,32 @@ export class PlayerView {
return result;
}
hasTransitiveTarget(sid: number): boolean {
if (this.state.targets.includes(sid)) return true;
for (const allyID of this.state.allies) {
const ally = this.game.playerBySmallID(allyID) as PlayerView;
if (ally && ally.state.targets.includes(sid)) {
return true;
}
}
const myTeam = this.static.team;
if (myTeam !== null) {
for (const p of this.game.playerViews()) {
if (
p !== this &&
p.static.team === myTeam &&
p.state.targets.includes(sid)
) {
return true;
}
}
}
return false;
}
isTraitor(): boolean {
return this.state.isTraitor;
}