Meshy-Figur Sylvara (20.709 Dreiecke, Lane-Fassung 4.999) mit zwei Sicheln als eigene Modelle, Clips leap/ultimate, 116 Credits. Skin-System: hero_skin als kosmetische Planungswahl, Blutmond als Varianten-Skin (skin_variant.py, AI_*_Blutmond, Dress mit Skin). Heldenfenster mit Reiter Ultimate & Skin, Befehlsplatz der Heldenkarte, Mondring. Ultimate zündet nicht im Sprungschritt. Kern 500/500, EditMode 30/30, PlayMode 15/15, Verify 718/0, Selbsttest 30/30, Fingerabdrücke unverändert; Balance 50 % wie Ringborke/Funkenlanze; Leistung gleich der Funkenlanze-Heldin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
180 lines
9.2 KiB
C#
180 lines
9.2 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>
|
||
/// 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).
|
||
/// </summary>
|
||
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<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 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<Animator>();
|
||
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<Renderer>().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();
|
||
}
|
||
}
|
||
}
|