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 { /// /// H1: Sylvara in the real scene. SylvaraHud checks the HUD (four heroes to recruit, the tab /// "Ultimate & Skin" with four rule cards and two skin cards, the command slot of the hero /// card, commands from the cards) and that her figure, clips and skin material reach the /// field. SylvaraBilder is the capture tool for the H1 evidence (1920×1080): recruiting, /// the ultimate tab, the planning formation, the leap, the Mondsicheltanz and the Blutmond /// skin; -testFilter "Luneraria.UI.Tests.H1HeroViewsTests.SylvaraBilder", LUNE_EVIDENCE /// names the folder below docs/port/screenshots (default h1/spiel). /// public sealed class H1HeroViewsTests { 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 SylvaraHud() { 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(4, s.Hud.HeroDetail.RecruitButtons.Count, "four heroes to recruit"); Assert.IsTrue(s.Hud.HeroDetail.RecruitButtons.ContainsKey("held_sylvara"), "Sylvara can be recruited"); s.Click(s.Hud.HeroDetail.RecruitButtons["held_sylvara"]); yield return HudSession.Frames(2); s.Sync(); Assert.AreEqual("held_sylvara", s.Me.Draft.Hero?.HeroId, "the recruit button buys Sylvara"); 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 Blutmond"); Assert.IsTrue(s.Hud.HeroDetail.RuleCards["gruppe"].On, "default rule Gruppe is marked"); s.Click(s.Hud.HeroDetail.RuleCards["zweite_reihe"]); yield return HudSession.Frames(2); s.Sync(); Assert.AreEqual("zweite_reihe", s.Me.Draft.Hero.Ultimate, "a rule card sets the rule"); s.Click(s.Hud.HeroDetail.SkinCards["blutmond"]); yield return HudSession.Frames(2); s.Sync(); Assert.AreEqual("blutmond", 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("ZWEITE REIHE", 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, "Sylvara fights"); Assert.AreEqual("blutmond", hero.Def.Skin); yield return HudSession.Frames(3); LuneUnitView view = ViewOf(hero); Assert.IsNotNull(view, "Sylvara has a view"); Animator animator = view.GetComponentInChildren(); Assert.IsNotNull(animator, "skinned figure"); Assert.IsTrue(animator.HasState(0, Animator.StringToHash("leap")) && animator.HasState(0, Animator.StringToHash("ultimate")), "leap and ultimate clips"); string[] materials = view.GetComponentsInChildren().SelectMany(r => r.sharedMaterials).Where(m => m != null).Select(m => m.name).Distinct().ToArray(); Assert.Contains("AI_Sylvara_Blutmond", materials, "the Blutmond material is dressed: " + string.Join(", ", materials)); Assert.Contains("AI_SylvaraSichel_Blutmond", 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 Sylvara 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 SylvaraBilder() { string evidence = Environment.GetEnvironmentVariable("LUNE_EVIDENCE"); string folder = "docs/port/screenshots/" + (string.IsNullOrEmpty(evidence) ? "h1/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_sylvara")); 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, "Sylvara 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.LeapSerial > 0 || !hero.Alive); s.Driver.Paused = true; s.Rig.LookAt(hero.Position, 11f, true); yield return new WaitForSecondsRealtime(.3f); yield return s.Shot(folder + "05-mondsprung.png"); s.Driver.Paused = false; yield return Until(s, () => hero.UltimateSerial > 0 || !hero.Alive); s.Driver.Paused = true; s.Rig.LookAt(hero.Position, 11f, true); yield return new WaitForSecondsRealtime(.2f); yield return s.Shot(folder + "06-mondsicheltanz.png"); yield return new WaitForSecondsRealtime(.6f); yield return s.Shot(folder + "07-mondsicheltanz-wirbel.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("blutmond")); s.Hud.OpenHero(LuneHeroDetail.TabUltimate); yield return new WaitForSecondsRealtime(.8f); yield return s.Shot(folder + "09-skin-blutmond-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-blutmond-kampf.png"); s.Close(); } } }