champions-of-luneraria/Assets/Luneraria/UI/Hud/LuneLanePanels.cs
Martin Stickelbroeck 2b86c0d3b5 U3B/U3C Zwischenstand: HUD-Bereiche, Eingabe und Befehle
Das G3-HUD steht im Spiel; die Abnahme (U3D) folgt.

- U3B: alle Bereiche und Komponenten aus Godot übertragen (LuneHud,
  Lanes, Bossgrotte, nächste Welle, Kaufkarten, Armee, Held mit Items und
  Talenten, Angriffschampions, Team, Ereignisse, Minimap, Tooltip,
  Optionen, Partieende). Porträts aus den echten Modellen, einmal gerendert.
- Offene G3-Punkte umgesetzt: „1 WELLE“ als Band am Porträtrand,
  Schadens- und Rüstungssymbole auf den Karten, Armeewert, Heldenporträts
  auf der Minimap. Befehlsplatz für die Ultimates der geplanten Helden
  reserviert (verborgen).
- U3C: LuneGame verdrahtet Befehle (gleiche Schnittstelle wie die Bots),
  Bereit mit 1-s-Sperre nach dem Kampf, Tempo und Pause, Tasten wie in G3,
  Kamera-Ziele, Auswahl im Feld, Planungsvorschau und Aufstellungsflächen.
  Ersetzt die U2-Debug-Anzeige. Bot-Partien und Benchmark unverändert.
- Szenen- und Bibliotheksbauer idempotent: Animator-Controller und
  Post-Processing-Profil werden an Ort und Stelle aktualisiert. Die Szene
  bekommt bei jedem Bau neue Objekt-IDs, der Inhalt ist gleich.
- Prüfung (Port von verify_g3, Teile A–H): 699 Prüfungen ohne Fehler.
  EditMode 23/23, PlayMode 12/12, Fingerabdrücke der Bot-Partien
  unverändert (DCE95C96556F3A1A, 7B8E43AEFC0D60C5).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 01:45:02 +02:00

530 lines
26 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using Luneraria.Core;
using UnityEngine;
using UnityEngine.UIElements;
namespace Luneraria.UI
{
/// <summary>
/// One lane in the lane overview (Godot LuneLaneIndicator): name and hotkey, the threat level
/// (text, symbol and colour), the tower chain from the own base to the enemy base, the two lane
/// players with their heroes, announced champions or the boss, and in combat the unit count of
/// both sides. A click moves the camera. The threat rises at once but only falls after a short
/// hold, so it does not flicker.
/// </summary>
public sealed class LuneLaneIndicator : LuneButton
{
public const float Hold = 2.5f;
public readonly string Lane;
public readonly string Hotkey;
public int Level { get; private set; }
/// <summary>The threat badge pulses (a lane just turned critical; off with reduced motion).</summary>
public bool Pulsing { get { return _pulse > 0f; } }
public LuneHudModel.LaneInfo Data { get; private set; }
public readonly LuneTowerIndicator[] Towers = new LuneTowerIndicator[4];
readonly LuneStatusBadge _badge;
readonly Label _own;
readonly Label _enemy;
readonly LunePortraitElement _ownHero;
readonly LunePortraitElement _enemyHero;
readonly Label _army;
readonly VisualElement _dangers;
readonly LuneGlyphElement _mine;
readonly LuneGlyphElement _ownShape;
readonly LuneGlyphElement _enemyShape;
float _lowerHold;
float _pulse;
string _signature = "";
public LuneLaneIndicator(string lane, string hotkey) : base(null, LuneButtons.HudRow)
{
Lane = lane;
Hotkey = hotkey;
style.minHeight = 92f;
style.flexDirection = FlexDirection.Column;
style.alignItems = Align.Stretch;
style.justifyContent = Justify.FlexStart;
style.paddingLeft = 10f;
style.paddingRight = 9f;
style.paddingTop = 6f;
style.paddingBottom = 6f;
var column = (LuneBox)LuneUi.Box(true, 3f, this);
VisualElement head = LuneUi.Box(false, 6f, column);
LuneUi.Glyph("lane_" + lane, LuneUiTheme.BronzeLight, 17f, head);
LuneUi.Label(LuneUi.Upper(LuneMap.LaneNames[lane]), "HudLane", head);
_mine = LuneUi.Glyph("star", LuneUiTheme.BronzeLight, 12f, head);
LuneUi.Show(_mine, false);
LuneUi.Spacer(head);
_badge = new LuneStatusBadge();
head.Add(_badge);
VisualElement chain = LuneUi.Box(false, 3f, column);
_ownShape = LuneUi.Glyph("emblem_0", LuneUiTheme.Team[0], 13f, chain);
for (int index = 0; index < 4; index++)
{
var tower = new LuneTowerIndicator();
chain.Add(tower);
Towers[index] = tower;
int captured = index;
LuneTooltip.Attach(tower, () => TowerTip(captured));
if (index == 1)
{
VisualElement middle = LuneUi.Box(false, 4f, chain);
middle.style.flexGrow = 1f;
middle.style.justifyContent = Justify.Center;
_army = LuneUi.Label("", "HudValue", middle);
_dangers = LuneUi.Box(false, 2f, middle);
}
}
_enemyShape = LuneUi.Glyph("emblem_1", LuneUiTheme.Team[1], 13f, chain);
VisualElement names = LuneUi.Box(false, 5f, column);
// Heroes of both lane players (Dota-style "who stands where"), committed heroes only.
_ownHero = new LunePortraitElement();
_ownHero.style.width = 22f;
_ownHero.style.height = 22f;
names.Add(_ownHero);
_own = LuneUi.Clip(LuneUi.Label("", "HudMuted", names));
_own.style.flexGrow = 1f;
_own.style.flexBasis = 0f;
_enemy = LuneUi.Clip(LuneUi.Label("", "HudMuted", names));
_enemy.style.flexGrow = 1f;
_enemy.style.flexBasis = 0f;
_enemy.style.unityTextAlign = TextAnchor.MiddleRight;
_enemyHero = new LunePortraitElement();
_enemyHero.style.width = 22f;
_enemyHero.style.height = 22f;
names.Add(_enemyHero);
LuneTooltip.Attach(this, Tip);
}
/// <summary>Applies a lane from LuneHudModel.Lane.</summary>
public void Apply(LuneHudModel.LaneInfo entry, int ownTeam, float delta, bool reducedMotion)
{
Data = entry;
int threat = entry.Threat.Level;
if (threat >= Level)
{
if (threat == LuneLaneThreat.Critical && Level != threat && !reducedMotion)
_pulse = 1.6f;
Level = threat;
_lowerHold = Hold;
}
else
{
_lowerHold -= delta;
if (_lowerHold <= 0f)
{
Level = threat;
_lowerHold = Hold;
}
}
Color tint = LuneUiTheme.Threat[Level];
_badge.SetState(LuneLaneThreat.Names[Level], tint, Level >= 2 ? LuneLaneThreat.Glyphs[Level] : "", Level == LuneLaneThreat.Critical);
_ownShape.Glyph = "emblem_" + ownTeam;
_ownShape.Color = LuneUiTheme.TeamColor(ownTeam);
_enemyShape.Glyph = "emblem_" + (1 - ownTeam);
_enemyShape.Color = LuneUiTheme.TeamColor(1 - ownTeam);
for (int index = 0; index < 4; index++)
{
LuneHudModel.BuildingInfo tower = entry.Towers[index];
Towers[index].Team = tower.Team;
Towers[index].Tier = tower.Tier;
Towers[index].SetState(tower.Alive, (float)tower.Fraction, tower.Attackable);
}
_own.text = entry.OwnPlayer;
LuneUi.SetColor(_own, entry.OwnIsMe ? LuneUiTheme.BronzeLight : LuneUiTheme.Muted);
_enemy.text = entry.EnemyPlayer;
ShowHero(_ownHero, entry.OwnHero);
ShowHero(_enemyHero, entry.EnemyHero);
LuneUi.Show(_mine, entry.OwnIsMe);
_army.text = entry.HasCounts ? entry.OwnCount + " : " + entry.EnemyCount : "";
string signature = string.Join(",", entry.Dangers.Select(d => d.Kind + ":" + d.Team + ":" + d.ChampionId));
if (signature != _signature)
{
_signature = signature;
_dangers.Clear();
foreach (Announcement danger in entry.Dangers)
{
bool hostile = danger.Team != ownTeam;
LuneUi.Glyph(danger.Kind == "boss" ? "crown" : "champion", hostile ? LuneUiTheme.Danger : LuneUiTheme.TeamColor(danger.Team), 16f, _dangers);
}
}
if (_pulse > 0f)
{
_pulse = Mathf.Max(0f, _pulse - delta);
_badge.style.opacity = _pulse > 0f ? .55f + .45f * Mathf.Abs(Mathf.Cos(_pulse * Mathf.PI * 2f)) : 1f;
}
else if (_badge.style.opacity != 1f)
{
_badge.style.opacity = 1f;
}
LuneTooltip.Current?.Refresh(this);
}
static void ShowHero(LunePortraitElement portrait, LuneHudModel.HeroBrief hero)
{
LuneUi.Show(portrait, hero != null);
if (hero != null)
portrait.ShowModel(hero.Model);
}
LuneTip Tip()
{
if (Data == null)
return null;
var lines = new List<string>();
foreach (string reason in Data.Threat.Reasons)
lines.Add("• " + reason);
if (lines.Count == 0)
lines.Add("Keine Bedrohung aus Türmen, Kampflage oder Ankündigungen.");
var tip = new LuneTip
{
Title = Data.Title + "-LANE · " + LuneLaneThreat.Names[Level], Glyph = "lane_" + Lane,
Subtitle = PlayerText(Data.OwnPlayer, Data.OwnHero) + " gegen " + PlayerText(Data.EnemyPlayer, Data.EnemyHero),
Text = string.Join("\n", lines),
};
for (int index = 0; index < 2; index++)
tip.Stat("tower", "Eigene " + LuneHudModel.BuildingTitle(Data.Towers[index].Id), TowerValue(Data.Towers[index]));
for (int index = 2; index < 4; index++)
tip.Stat("tower", "Gegner " + LuneHudModel.BuildingTitle(Data.Towers[index].Id), TowerValue(Data.Towers[index]));
if (Data.HasCounts)
tip.Stat("melee", "Einheiten", Data.OwnCount + " eigene · " + Data.EnemyCount + " gegnerische");
var notes = new List<string>();
foreach (Announcement danger in Data.Dangers)
{
string side = LuneUiTheme.TeamName(danger.Team);
notes.Add(danger.Kind == "boss" ? "Schlundkrone (" + side + ") greift an" : LuneContent.Champions[danger.ChampionId].Name + " (" + side + ") angekündigt");
}
tip.Note = (notes.Count > 0 ? string.Join("; ", notes) + "\n" : "") + "Klick: Kamera auf die Lane" + (Hotkey.Length > 0 ? " (" + Hotkey + ")" : "");
return tip;
}
static string PlayerText(string player, LuneHudModel.HeroBrief hero)
{
return hero == null ? player : player + " (" + hero.Name + ", Stufe " + hero.Level + ")";
}
LuneTip TowerTip(int index)
{
if (Data == null)
return null;
LuneHudModel.BuildingInfo tower = Data.Towers[index];
string text = !tower.Alive ? "Zerstört – die Ruine blockiert nicht." : tower.Attackable ? "Angreifbar." : "Noch geschützt: erst fällt der Turm davor.";
return new LuneTip { Title = LuneHudModel.BuildingTitle(tower.Id) + " · " + LuneUiTheme.TeamName(tower.Team), Glyph = "tower", GlyphColor = LuneUiTheme.TeamColor(tower.Team), Text = text }
.Stat("heart", "Leben", TowerValue(tower));
}
public static string TowerValue(LuneHudModel.BuildingInfo tower)
{
if (!tower.Alive)
return "zerstört";
return LuneUiTheme.Number(tower.Hp) + " / " + LuneUiTheme.Number(tower.MaxHp) + " (" + LuneUiTheme.Round(tower.Fraction * 100.0) + " %)";
}
}
/// <summary>
/// The boss grotto and the Schlundkrone at a glance (Godot LuneBossIndicator): BOSS VERFÜGBAR,
/// BOSS UMKÄMPFT, BOSS EROBERT, EINSATZ NÄCHSTE WELLE, BOSS GREIFT AN, COOLDOWN – X RUNDEN. When
/// a team owns the boss the card names target lane, deployment wave and the bounty the defenders
/// earn; the player who steers the boss chooses its lane here. A click moves the camera.
/// </summary>
public sealed class LuneBossIndicator : LunePanel
{
public event Action FocusRequested;
public event Action<string> LaneChosen;
public LuneHudModel.BossInfo Data { get; private set; }
public readonly LunePortraitElement Portrait;
public bool Compact { get; private set; }
readonly LuneStatusBadge _badge;
readonly Label _line;
readonly Label _risk;
readonly LuneHpBar _bar;
readonly VisualElement _choice;
public readonly Dictionary<string, LuneButton> LaneButtons = new Dictionary<string, LuneButton>();
readonly LuneGlyphElement _owner;
string _signature = "";
int _ownTeam;
int _round;
bool _planning = true;
public LuneBossIndicator() : base(LunePanels.HudTight)
{
VisualElement row = LuneUi.Box(false, 10f, this);
row.style.alignItems = Align.FlexStart;
Portrait = new LunePortraitElement();
Portrait.style.width = 64f;
Portrait.style.height = 64f;
row.Add(Portrait);
_owner = LuneUi.Glyph("emblem_2", LuneUiTheme.Team[2], 18f, Portrait);
_owner.style.position = Position.Absolute;
_owner.style.left = 2f;
_owner.style.bottom = 2f;
VisualElement column = LuneUi.Box(true, 3f, row);
column.style.flexGrow = 1f;
column.style.flexShrink = 1f;
column.style.minWidth = 0f;
VisualElement head = LuneUi.Box(false, 6f, column);
LuneUi.Glyph("grotto", LuneUiTheme.Team[2], 15f, head);
LuneUi.Label("BOSSGROTTE · G", "HudCaps", head);
_badge = new LuneStatusBadge();
_badge.style.alignSelf = Align.FlexStart;
column.Add(_badge);
_line = LuneUi.Wrap(LuneUi.Label("", "HudText", column));
_risk = LuneUi.Wrap(LuneUi.Label("", "HudMuted", column));
_bar = new LuneHpBar(0f, 5f);
LuneUi.Show(_bar, false);
column.Add(_bar);
_choice = LuneUi.Box(false, 4f, column);
LuneUi.Show(_choice, false);
foreach (string lane in LuneMap.Lanes)
{
var button = new LuneButton(LuneUi.Upper(LuneMap.LaneNames[lane]), LuneButtons.HudToggle, _choice);
button.ToggleMode = true;
button.style.flexGrow = 1f;
string captured = lane;
button.Clicked += () => LaneChosen?.Invoke(captured);
LaneButtons[lane] = button;
}
RegisterCallback<PointerDownEvent>(evt =>
{
if (evt.button == 0)
FocusRequested?.Invoke();
});
LuneTooltip.Attach(this, Tip);
}
/// <summary>Short form while the right column shows a selected unit: badge only.</summary>
public void SetCompact(bool value)
{
if (value == Compact)
return;
Compact = value;
Portrait.style.width = value ? 40f : 64f;
Portrait.style.height = value ? 40f : 64f;
_signature = "";
if (Data != null)
Apply(Data, _ownTeam, _round, _planning);
}
public void Apply(LuneHudModel.BossInfo boss, int ownTeam, int round, bool planning)
{
string signature = boss + "|" + ownTeam + "|" + round + "|" + planning;
if (signature == _signature)
return;
_signature = signature;
Data = boss;
_ownTeam = ownTeam;
_round = round;
_planning = planning;
Portrait.ShowModel("schlundkrone");
int owner = boss.Team;
bool own = owner == ownTeam;
string lane = LuneUi.Upper(LuneMap.LaneNames.TryGetValue(boss.Lane, out string name) ? name : "?");
string side = LuneUiTheme.TeamName(owner);
bool showOwner = owner >= 0;
_owner.Glyph = "emblem_" + Mathf.Clamp(owner, 0, 2);
_owner.Color = LuneUiTheme.TeamColor(owner);
LuneUi.Show(_bar, false);
LuneUi.Show(_choice, false);
_risk.text = "";
switch (boss.State)
{
case "available":
_badge.SetState("BOSS VERFÜGBAR", LuneUiTheme.Team[2], "crown");
_line.text = "Einheiten mit „Grotte“ entsenden. Wer den Boss besiegt, schickt ihn in der Folgewelle gegen den Gegner.";
break;
case "contested":
_badge.SetState("BOSS UMKÄMPFT", LuneUiTheme.Warn, "melee");
_line.text = "Expeditionen kämpfen in der Grotte; sie fehlen ihren Lanes bis Kampfende.";
break;
case "conquered":
_badge.SetState("BOSS EROBERT · " + LuneUi.Upper(side), LuneUiTheme.TeamColor(owner), "crown", true);
_line.text = "Einsatz in Welle " + boss.DeployRound + " für " + (own ? "dein Team" : side) + ".";
break;
case "failed":
_badge.SetState("EXPEDITION GESCHEITERT", LuneUiTheme.Muted, "close");
_line.text = "Der Boss hat überlebt; niemand erhält ihn.";
break;
case "deploy_next":
_badge.SetState("EINSATZ NÄCHSTE WELLE", own ? LuneUiTheme.TeamColor(owner) : LuneUiTheme.Danger, "crown", true);
if (own)
{
_line.text = "Deine Schlundkrone greift in Welle " + boss.DeployRound + " auf " + lane + " an.";
_risk.text = "Fällt sie, erhält " + LuneUiTheme.TeamName(1 - ownTeam) + " " + LuneUiTheme.Number(boss.Bounty) + " Gold Kopfgeld.";
}
else
{
_line.text = side + ": Schlundkrone greift in Welle " + boss.DeployRound + " auf " + lane + " an.";
_risk.text = "Besiegt ihr sie, erhält dein Team " + LuneUiTheme.Number(boss.Bounty) + " Gold Kopfgeld.";
}
if (boss.Chooser && planning)
{
LuneUi.Show(_choice, true);
foreach (KeyValuePair<string, LuneButton> pair in LaneButtons)
pair.Value.On = pair.Key == boss.Lane;
_risk.text += " Du wählst die Lane:";
}
break;
case "deploying":
_badge.SetState("BOSS GREIFT AN · " + lane, own ? LuneUiTheme.TeamColor(owner) : LuneUiTheme.Danger, "warning", true);
_line.text = own ? "Deine Schlundkrone greift " + lane + " an." : "Gegnerische Schlundkrone auf " + lane + "!";
_risk.text = "Kopfgeld für die Verteidiger: " + LuneUiTheme.Number(boss.Bounty) + " Gold.";
if (boss.HasHp)
{
LuneUi.Show(_bar, true);
_bar.Fraction = (float)(boss.Hp / Math.Max(1.0, boss.MaxHp));
_bar.Fill = LuneUiTheme.TeamColor(owner);
}
break;
case "defeated":
_badge.SetState("SCHLUNDKRONE BESIEGT", !own ? LuneUiTheme.Good : LuneUiTheme.Muted, "check");
_line.text = "Das Kopfgeld von " + LuneUiTheme.Number(boss.Bounty) + " Gold geht an " + (own ? "den Gegner" : "dein Team") + ".";
break;
default:
int left = boss.RoundsLeft;
_badge.SetState("COOLDOWN – " + left + (left == 1 ? " RUNDE" : " RUNDEN"), LuneUiTheme.Muted, "clock");
_line.text = "Grotte wieder offen ab Welle " + boss.NextRound + ".";
break;
}
LuneUi.Show(_risk, _risk.text.Length > 0 && !Compact);
LuneUi.Show(_line, !Compact);
LuneUi.Show(_owner, showOwner && !Compact);
if (Compact)
LuneUi.Show(_choice, false);
LuneTooltip.Current?.Refresh(this);
}
/// <summary>Live boss HP during its attack, without rebuilding the texts.</summary>
public void SetBossHp(float fraction)
{
if (LuneUi.Visible(_bar))
_bar.Fraction = fraction;
}
public string BadgeText { get { return _badge.Text; } }
public string LineText { get { return _line.text; } }
static LuneTip Tip()
{
return new LuneTip
{
Title = "Bossgrotte · Schlundkrone", Glyph = "crown", GlyphColor = LuneUiTheme.Team[2],
Text = "Expeditionen kämpfen zuerst gegeneinander; der Boss erwacht, wenn höchstens ein Team übrig ist. Sieg: Der Boss greift in der Folgewelle für die Sieger an, die Verteidiger erhalten bei seinem Fall ein hohes Kopfgeld. Danach ist die Grotte "
+ LuneContent.BossLockRounds + " Runden gesperrt.",
Note = "Klick oder G: Kamera zur Grotte",
};
}
}
/// <summary>
/// What the coming wave brings (Godot LuneNextWave): monster types with counts (identical for
/// both sides and every lane), new types, the armour most of the wave wears and the damage type
/// that hits it for 130 %, announced attack champions and an announced boss. Dangers for the
/// own team are highlighted. In combat the panel shrinks to one line about the following wave.
/// </summary>
public sealed class LuneNextWave : LunePanel
{
readonly Label _title;
readonly Label _round;
readonly VisualElement _rows;
readonly VisualElement _extra;
readonly Label _note;
string _signature = "";
public bool Compact { get; private set; }
public LuneNextWave() : base(LunePanels.HudTight)
{
VisualElement column = LuneUi.Box(true, 4f, this);
VisualElement head = LuneUi.Box(false, 0f, column);
_title = LuneUi.Label("NÄCHSTE WELLE", "HudCaps", head);
_title.style.flexGrow = 1f;
_round = LuneUi.Label("", "HudValue", head);
_rows = LuneUi.Box(true, 2f, column);
_note = LuneUi.Wrap(LuneUi.Label("", "HudMuted", column));
_extra = LuneUi.Box(true, 3f, column);
}
public string NoteText { get { return _note.text; } }
public void Apply(LuneHudModel.WaveInfo wave, int ownTeam, bool fighting)
{
string signature = wave + "|" + ownTeam + "|" + fighting;
if (signature == _signature)
return;
_signature = signature;
Compact = fighting;
_title.text = fighting ? "DANACH" : "NÄCHSTE WELLE";
_round.text = "WELLE " + wave.Round;
_rows.Clear();
_extra.Clear();
if (fighting)
{
_note.text = string.Join(", ", wave.Monsters.Select(m => m.Count + "× " + m.Name + (m.New ? " (neu)" : ""))) + " je Lane";
return;
}
foreach (LuneHudModel.MonsterGroup monster in wave.Monsters)
{
VisualElement row = LuneUi.Box(false, 7f, _rows);
row.pickingMode = PickingMode.Position;
var portrait = new LunePortraitElement();
portrait.style.width = 30f;
portrait.style.height = 30f;
row.Add(portrait);
portrait.ShowModel(monster.Id);
LuneUi.Label(monster.Count + "×", "HudValue", row).style.minWidth = 30f;
Label title = LuneUi.Clip(LuneUi.Label(monster.Name, "HudText", row));
title.style.flexGrow = 1f;
LuneUi.Glyph("armor", LuneTypeColors.Armor(monster.Armor), 13f, row);
LuneUi.SetColor(LuneUi.Label(LuneStats.ArmorName(monster.Armor), "HudMuted", row), LuneTypeColors.Armor(monster.Armor));
if (monster.New)
{
var badge = new LuneStatusBadge();
badge.SetState("NEU", LuneUiTheme.Warn);
row.Add(badge);
}
LuneHudModel.MonsterGroup data = monster;
int round = wave.Round;
LuneTooltip.Attach(row, () => new LuneTip { Title = data.Name, Subtitle = "Monster der Welle " + round, Note = "Beide Teams erhalten auf jeder Lane dieselbe Welle." }
.Stat("heart", "Leben", LuneUiTheme.Number(data.Hp)).Stat("sword", "Schaden/Treffer", LuneUiTheme.Decimal(data.Damage))
.Stat("range", "Reichweite", LuneUiTheme.Decimal(data.Range) + " m").Stat("armor", "Rüstung", LuneStats.ArmorName(data.Armor)));
}
// Counter hint as in Legion TD 2: the armour most of the wave wears and the damage type
// that hits it for 130 % (DamageMatrix).
int[] armour = new int[3];
foreach (LuneHudModel.MonsterGroup monster in wave.Monsters)
armour[Mathf.Clamp(monster.Armor, 0, 2)] += monster.Count;
int main = Array.IndexOf(armour, armour.Max());
int counter = 0;
for (int attack = 0; attack < 3; attack++)
{
if (Math.Abs(LuneUnit.DamageMatrix[attack, main] - 1.30) < 1e-9)
counter = attack;
}
_note.text = wave.Count + " Monster je Lane · beide Seiten gleich\nMeist " + LuneStats.ArmorName(main) + ": " + LuneStats.DamageName(counter) + " trifft stark";
if (wave.Champions.Count == 0 && wave.Boss == null)
return;
LuneUi.Label("ANGEKÜNDIGT", "HudCaps", _extra);
foreach (LuneHudModel.ChampionNotice entry in wave.Champions)
{
bool hostile = !entry.Own;
VisualElement row = LuneUi.Box(false, 6f, _extra);
LuneUi.Glyph("champion", hostile ? LuneUiTheme.Danger : LuneUiTheme.Champion, 15f, row);
LuneUi.Clip(LuneUi.Label(entry.Name + " → " + LuneUi.Upper(LuneMap.LaneNames[entry.Lane]), "HudText", row)).style.flexGrow = 1f;
var badge = new LuneStatusBadge();
badge.SetState(hostile ? "GEGEN EUCH" : "FÜR EUCH", hostile ? LuneUiTheme.Danger : LuneUiTheme.Good);
row.Add(badge);
}
if (wave.Boss != null)
{
bool hostile = !wave.Boss.Own;
VisualElement row = LuneUi.Box(false, 6f, _extra);
LuneUi.Glyph("crown", hostile ? LuneUiTheme.Danger : LuneUiTheme.TeamColor(ownTeam), 16f, row);
LuneUi.Clip(LuneUi.Label("Schlundkrone → " + LuneUi.Upper(LuneMap.LaneNames[wave.Boss.Lane]), "HudText", row)).style.flexGrow = 1f;
var badge = new LuneStatusBadge();
badge.SetState(hostile ? "GEGEN EUCH" : "FÜR EUCH", hostile ? LuneUiTheme.Danger : LuneUiTheme.Good, "crown");
row.Add(badge);
}
}
}
}