champions-of-luneraria/Assets/Luneraria/Tests/UI/PlayMode/H2HeroViewsTests.cs
Martin Stickelbroeck 542a9646c8 H2 Brunhild: Figur, Skin Eiswalküre, Oberfläche, Nachweise
Meshy-Figur Brunhild (28.706 Dreiecke mit Lane-Fassung und Speer) mit
Ultimate-Clip Jump Attack, 113 Credits. Skin Eiswalküre über skin_variant.py
(Farbband über Rot, Mindestsättigung schützt Hauttöne). Heldenwahl bei fünf
Helden kompakter; Tests auf fünf Helden angehoben.
Kern 619/619 (h2 22), EditMode 34/34, PlayMode 19/19, Verify 718/0,
Selbsttest 30/30, Golden 0, Fingerabdruck unverändert; A/B mit Sylvara:
Karte gleich, Mid nah -4 %.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:21:50 +02:00

175 lines
8.8 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;
using System.Linq;
using Luneraria.Core;
using Luneraria.View;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace Luneraria.UI.Tests
{
/// <summary>
/// H2: Brunhild in the real scene (derived from the H1 test). BrunhildHud checks recruiting,
/// the tab "Ultimate & Skin" (four rules, two skins), the command slot, her figure with the
/// ultimate clip and the Eiswalküre material on body and spear, and the ultimate in combat.
/// BrunhildBilder captures the H2 evidence (1920×1080); LUNE_EVIDENCE names the folder below
/// docs/port/screenshots (default h2/spiel).
/// </summary>
public sealed class H2HeroViewsTests
{
static void Send(HudSession s, Command command)
{
CommandResult result = s.Match.Submit(HudSession.Human, command);
Assert.IsTrue(result.Ok, command.Type + ": " + result.Message);
s.Game.RebuildPreview();
s.Sync();
}
static LuneUnit Hero(HudSession s)
{
return s.Match.Combat?.Units.FirstOrDefault(u => u.Kind == "hero" && u.OwnerSlot == HudSession.Human);
}
static LuneUnitView ViewOf(LuneUnit unit)
{
return UnityEngine.Object.FindObjectsByType<LuneUnitView>(FindObjectsSortMode.None).FirstOrDefault(v => v.Unit == unit);
}
/// <summary>Steps the combat in single simulation steps until the condition holds (or the combat ends).</summary>
static IEnumerator Until(HudSession s, Func<bool> done, double limit = 60.0)
{
double time = 0.0;
while (!done() && time < limit && s.Runner.Current == LuneMatchRunner.Stage.Combat)
{
s.Runner.Advance(.05);
time += .05;
if ((int)(time / .05) % 10 == 0)
yield return null;
}
yield return HudSession.Frames(2);
s.Sync();
}
[UnityTest, Timeout(600000)]
public IEnumerator BrunhildHud()
{
var s = new HudSession();
yield return s.Open(1920, 1080, seed: 4, startRound: 6, extraGold: 1500);
s.Hud.OpenHero();
yield return HudSession.Frames(2);
s.Sync();
Assert.AreEqual(LuneContent.Heroes.Count, s.Hud.HeroDetail.RecruitButtons.Count, "every hero can be recruited");
Assert.IsTrue(s.Hud.HeroDetail.RecruitButtons.ContainsKey("held_brunhild"), "Brunhild can be recruited");
s.Click(s.Hud.HeroDetail.RecruitButtons["held_brunhild"]);
yield return HudSession.Frames(2);
s.Sync();
Assert.AreEqual("held_brunhild", s.Me.Draft.Hero?.HeroId, "the recruit button buys Brunhild");
s.Hud.OpenHero(LuneHeroDetail.TabUltimate);
yield return HudSession.Frames(2);
s.Sync();
Assert.AreEqual(4, s.Hud.HeroDetail.RuleCards.Count, "four trigger rules");
Assert.AreEqual(2, s.Hud.HeroDetail.SkinCards.Count, "standard look and Eiswalküre");
Assert.IsTrue(s.Hud.HeroDetail.RuleCards["gruppe"].On, "default rule Gruppe is marked");
s.Click(s.Hud.HeroDetail.RuleCards["held"]);
yield return HudSession.Frames(2);
s.Sync();
Assert.AreEqual("held", s.Me.Draft.Hero.Ultimate, "a rule card sets the rule");
s.Click(s.Hud.HeroDetail.SkinCards["eiswalkuere"]);
yield return HudSession.Frames(2);
s.Sync();
Assert.AreEqual("eiswalkuere", s.Me.Draft.Hero.Skin, "a skin card sets the skin");
Assert.IsTrue(HudSession.Visible(s.Hud.HeroCard.CommandSlot), "the hero card shows the ultimate");
StringAssert.Contains("HELDENJAGD", s.Hud.HeroCard.CommandSlot.Text, "the command slot names the rule");
s.Hud.CloseModal();
s.Game.Key(KeyCode.Space);
yield return HudSession.Frames(2);
LuneUnit hero = Hero(s);
Assert.IsNotNull(hero, "Brunhild fights");
Assert.AreEqual("eiswalkuere", hero.Def.Skin);
yield return HudSession.Frames(3);
LuneUnitView view = ViewOf(hero);
Assert.IsNotNull(view, "Brunhild has a view");
Animator animator = view.GetComponentInChildren<Animator>();
Assert.IsNotNull(animator, "skinned figure");
Assert.IsTrue(animator.HasState(0, Animator.StringToHash("ultimate")), "ultimate clip");
string[] materials = view.GetComponentsInChildren<Renderer>().SelectMany(r => r.sharedMaterials).Where(m => m != null).Select(m => m.name).Distinct().ToArray();
Assert.Contains("AI_Brunhild_Eiswalkuere", materials, "the Blutmond material is dressed: " + string.Join(", ", materials));
Assert.Contains("AI_BrunhildSpeer_Eiswalkuere", materials, "both sickles in Blutmond");
yield return Until(s, () => hero.UltimateSerial > 0 || !hero.Alive);
Assert.IsTrue(hero.UltimateSerial > 0 || !hero.Alive, "the ultimate fires (or Brunhild fell first)");
if (hero.UltimateSerial > 0)
StringAssert.Contains("GENUTZT", s.Hud.HeroCard.CommandSlot.Text, "the card reports the fired ultimate");
s.Close();
}
[UnityTest, Timeout(900000), Explicit("Bildwerkzeug: nur gezielt per -testFilter")]
public IEnumerator BrunhildBilder()
{
string evidence = Environment.GetEnvironmentVariable("LUNE_EVIDENCE");
string folder = "docs/port/screenshots/" + (string.IsNullOrEmpty(evidence) ? "h2/spiel" : evidence) + "/";
var s = new HudSession();
yield return s.Open(1920, 1080, seed: 4, startRound: 6, extraGold: 1500);
yield return s.Starter();
s.Leave();
s.Hud.OpenHero();
yield return new WaitForSecondsRealtime(.6f);
yield return s.Shot(folder + "01-heldenwahl.png");
Send(s, Command.HeroBuy("held_brunhild"));
s.Hud.OpenHero(LuneHeroDetail.TabValues);
yield return new WaitForSecondsRealtime(.6f);
yield return s.Shot(folder + "02-heldenfenster.png");
s.Hud.OpenHero(LuneHeroDetail.TabUltimate);
yield return new WaitForSecondsRealtime(.8f);
yield return s.Shot(folder + "03-ultimate-und-skin.png");
s.Hud.CloseModal();
yield return new WaitForSecondsRealtime(.3f);
LuneUnit waiting = s.View.Preview?.Units.FirstOrDefault(u => u.Kind == "hero" && u.OwnerSlot == HudSession.Human);
Assert.IsNotNull(waiting, "Brunhild in the planning preview");
s.Rig.LookAt(waiting.Position, 9f, true);
yield return new WaitForSecondsRealtime(.6f);
yield return s.Shot(folder + "04-aufstellung.png");
s.Game.Key(KeyCode.Space);
yield return HudSession.Frames(2);
LuneUnit hero = Hero(s);
yield return Until(s, () => hero.UltimateSerial > 0 || !hero.Alive);
s.Driver.Paused = true;
s.Rig.LookAt(hero.Position, 11f, true);
yield return new WaitForSecondsRealtime(.35f);
yield return s.Shot(folder + "05-walkuerensturz.png");
s.Rig.LookAt(hero.Position, 11f, true);
yield return new WaitForSecondsRealtime(.2f);
yield return s.Shot(folder + "06-betaeubt.png");
yield return new WaitForSecondsRealtime(.6f);
yield return s.Shot(folder + "07-nach-dem-sturz.png");
s.Rig.LookAt(hero.Position, 20f, true);
yield return new WaitForSecondsRealtime(.4f);
yield return s.Shot(folder + "08-kampf-lane.png");
s.Driver.Paused = false;
yield return s.FinishCombat();
// Space is blocked for a moment after a combat (no accidental skip of the planning).
float waited = 0f;
while (s.Hud.ReadyBlocked() && waited < 5f)
{
waited += Time.unscaledDeltaTime;
yield return null;
}
Send(s, Command.HeroSkin("eiswalkuere"));
s.Hud.OpenHero(LuneHeroDetail.TabUltimate);
yield return new WaitForSecondsRealtime(.8f);
yield return s.Shot(folder + "09-skin-eiswalkuere-fenster.png");
s.Hud.CloseModal();
int round = s.Match.RoundNumber;
s.Game.Key(KeyCode.Space);
yield return HudSession.Frames(2);
Assert.AreEqual(LuneMatchRunner.Stage.Combat, s.Runner.Current, "combat of round " + round);
hero = Hero(s);
yield return s.Fight(9.0);
s.Driver.Paused = true;
s.Rig.LookAt(hero.Position, 9f, true);
yield return new WaitForSecondsRealtime(.5f);
yield return s.Shot(folder + "10-skin-eiswalkuere-kampf.png");
s.Close();
}
}
}