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 { /// /// 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). /// 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(FindObjectsSortMode.None).FirstOrDefault(v => v.Unit == unit); } /// Steps the combat in single simulation steps until the condition holds (or the combat ends). static IEnumerator Until(HudSession s, Func 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(); Assert.IsNotNull(animator, "skinned figure"); Assert.IsTrue(animator.HasState(0, Animator.StringToHash("ultimate")), "ultimate clip"); string[] materials = view.GetComponentsInChildren().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(); } } }