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>
175 lines
8.8 KiB
C#
175 lines
8.8 KiB
C#
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();
|
||
}
|
||
}
|
||
}
|