Nicht abgenommen: Nach dem ersten Spieltest wurde entschieden, Champions of Luneraria nach Unity 6 zu portieren. Dieser Stand ist die Referenz für das HUD im Unity-Projekt (../luneraria-unity). - HUD neu aus Komponenten mit eigenem Theme, Porträts aus den echten Modellen (einmal gerendert, zwischengespeichert), Lane-Übersicht mit deterministischer Bedrohung aus öffentlichem Zustand, Bossgrotte, nächste Welle, Ereignisse, Minimap mit zusammengefassten Armeen, Held/Items/Talente, Einheitendetails, Angriffschampions, Bereit-Sperre, UI-Größe, Team-Formen statt nur Farben - Privatsphäre über LuneHudModel: fremdes Gold und fremde Entwürfe erscheinen nie - Keine Regeländerung: Regeln 91/91, M2 73/73, Netz 43/43; verify_g3 715/715; verify_m1 38/38 und verify_m2 14/14 mit angepassten UI-Treibern - Spieltest bis Welle 8 über die echte Oberfläche, Befunde in G3-HUD.md - HELDEN-KONZEPT.md: vom Projektinhaber vorgegebene Helden (nicht umgesetzt) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
89 lines
4.3 KiB
GDScript
89 lines
4.3 KiB
GDScript
class_name LuneTeamPanel
|
||
extends VBoxContainer
|
||
## The own team: per seat the name, lane, hero (committed hero of the others, own draft for
|
||
## the viewer), readiness during planning and whether a human, a bot or – after a disconnect –
|
||
## a bot on a human's seat plays it. Gold or plans of the others are never shown.
|
||
|
||
var _rows: Array[Dictionary] = []
|
||
var _header: Label
|
||
var _emblem: LuneGlyph
|
||
var _signature: String = ""
|
||
|
||
func _init() -> void:
|
||
add_theme_constant_override("separation", 3)
|
||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
var head := HBoxContainer.new()
|
||
head.add_theme_constant_override("separation", 6)
|
||
head.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
add_child(head)
|
||
_emblem = LuneGlyph.make("emblem_0", LuneUiTheme.TEAM[0], 15.0, head)
|
||
_header = LuneUiTheme.label("DEIN TEAM", "HudCaps", head)
|
||
for index: int in range(3):
|
||
var row := HBoxContainer.new()
|
||
row.add_theme_constant_override("separation", 6)
|
||
row.mouse_filter = Control.MOUSE_FILTER_PASS
|
||
row.custom_minimum_size.y = 28
|
||
add_child(row)
|
||
var status := LuneGlyph.make("human", LuneUiTheme.MUTED, 15.0, row)
|
||
var portrait := LunePortraitRect.new()
|
||
portrait.custom_minimum_size = Vector2(26, 26)
|
||
portrait.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||
row.add_child(portrait)
|
||
var name_label := LuneUiTheme.label("", "HudText", row)
|
||
name_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
name_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
||
name_label.clip_text = true
|
||
var lane_label := LuneUiTheme.label("", "HudMuted", row)
|
||
var badge := LuneStatusBadge.new()
|
||
row.add_child(badge)
|
||
var entry: Dictionary = {"row": row, "status": status, "portrait": portrait, "name": name_label, "lane": lane_label, "badge": badge, "data": {}}
|
||
_rows.append(entry)
|
||
LuneTooltip.attach(row, _tip.bind(index))
|
||
|
||
func apply(members: Array, team: int, planning: bool, networked: bool) -> void:
|
||
var signature: String = "%s|%d|%s|%s" % [str(members), team, planning, networked]
|
||
if signature == _signature:
|
||
return
|
||
_signature = signature
|
||
_emblem.glyph = "emblem_%d" % team
|
||
_emblem.color = LuneUiTheme.team_color(team)
|
||
_header.text = "DEIN TEAM · %s" % LuneUiTheme.team_name(team).to_upper()
|
||
for index: int in range(mini(3, members.size())):
|
||
var member: Dictionary = members[index]
|
||
var row: Dictionary = _rows[index]
|
||
row.data = member
|
||
var status: String = str(member.status)
|
||
(row.status as LuneGlyph).glyph = {"self": "star", "human": "human", "bot": "bot", "offline": "offline"}.get(status, "human")
|
||
(row.status as LuneGlyph).color = LuneUiTheme.BRONZE_LIGHT if status == "self" else (LuneUiTheme.DANGER if status == "offline" else LuneUiTheme.MUTED)
|
||
var name_label: Label = row.name
|
||
name_label.text = str(member.name)
|
||
name_label.add_theme_color_override("font_color", LuneUiTheme.BRONZE_LIGHT if member.is_self else LuneUiTheme.TEXT)
|
||
(row.lane as Label).text = LuneMap.LANE_NAMES[member.lane].to_upper()
|
||
var portrait: LunePortraitRect = row.portrait
|
||
var hero_id: String = str(member.hero_id)
|
||
portrait.visible = not hero_id.is_empty()
|
||
if not hero_id.is_empty():
|
||
portrait.show_model(str(LuneContent.HEROES[hero_id].model))
|
||
var badge: LuneStatusBadge = row.badge
|
||
if status == "offline":
|
||
badge.set_state("BOT ÜBERNIMMT", LuneUiTheme.DANGER, "offline")
|
||
elif status == "bot":
|
||
badge.set_state("BOT", LuneUiTheme.MUTED, "bot")
|
||
elif planning and member.ready:
|
||
badge.set_state("BEREIT", LuneUiTheme.GOOD, "check")
|
||
elif planning:
|
||
badge.set_state("PLANT", LuneUiTheme.WARN, "clock")
|
||
else:
|
||
badge.set_state("IM KAMPF", LuneUiTheme.INFO)
|
||
|
||
func _tip(index: int) -> Dictionary:
|
||
var member: Dictionary = _rows[index].data
|
||
if member.is_empty():
|
||
return {}
|
||
var kind: String = {"self": "Du", "human": "Mensch", "bot": "Bot", "offline": "Verbindung getrennt – ein Bot spielt den Platz weiter"}.get(str(member.status), "")
|
||
var hero: String = "kein Held"
|
||
if not str(member.hero_id).is_empty():
|
||
hero = "%s · Stufe %d" % [LuneContent.HEROES[member.hero_id].name, int(member.hero_level)]
|
||
return {"title": str(member.name), "subtitle": "%s-Lane · %s" % [LuneMap.LANE_NAMES[member.lane], DataCatalog.FACTION_NAMES.get(member.bund, "")],
|
||
"stats": [["human", "Spieler", kind], ["crown", "Held", hero], ["check", "Planung", "bereit" if member.ready else "plant noch"]],
|
||
"note": "Gold und laufende Planung anderer Spieler bleiben privat." if not member.is_self else ""}
|