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(LuneContent.Heroes.Count, s.Hud.HeroDetail.RecruitButtons.Count, "every hero can be recruited");
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();
}
}
}