S3 Neutrallager und Fog of War mit Spähern (LoL, Dota 2)
Erweiterte Regeln: in jeder dritten Runde ein neutraler Wächter in jeder Lanemitte; wer beim Fall mehr Einheiten (dann mehr Leben) in 8 m hat, nimmt das Lager: Glutsegen (+10 % Schaden), Mondschild (Schild 10 %), Beute (50 Gold je Spieler). Fog of War (LuneFog, nur Darstellung): Gegner sichtbar in 9 m um eigene Einheiten, 10 m um Gebäude, 12 m um Späher; Späher (40 Gold, 3 Runden, Teamwirkung) zeigen in der Planung die gegnerische Armee ihrer Lane. HUD: Teampanel SPÄHER und LAGER, Lager-Sechseck, Nebel in Feld, Minimap, Namensschildern und Lane-Zählung. Kern 597/597 (s3 31), EditMode 33/33, PlayMode 18/18, Verify 718/0, Selbsttest 30/30, Golden 0, Fingerabdruck unverändert. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
@ -90,6 +90,23 @@ namespace Luneraria.Core
|
||||||
public double CoreRange = 7.5;
|
public double CoreRange = 7.5;
|
||||||
public double CoreRepair = 1000.0;
|
public double CoreRepair = 1000.0;
|
||||||
|
|
||||||
|
// S3: neutral camps (League of Legends buff camps) under the extended rules.
|
||||||
|
/// <summary>A guardian stands at the middle of every lane in rounds divisible by this.</summary>
|
||||||
|
public int CampEvery = 3;
|
||||||
|
public double CampHp = 1500.0;
|
||||||
|
public double CampDamage = 30.0;
|
||||||
|
public double CampRange = 2.5;
|
||||||
|
/// <summary>Units within this distance decide which team takes a fallen guardian.</summary>
|
||||||
|
public double CampClaimRadius = 8.0;
|
||||||
|
/// <summary>Combats a lane buff lasts; Glutsegen damage, Mondschild shield share, Beute gold per player.</summary>
|
||||||
|
public int CampBuffRounds = 2;
|
||||||
|
public double CampDamageBuff = 0.10;
|
||||||
|
public double CampShieldBuff = 0.10;
|
||||||
|
public int CampLootGold = 50;
|
||||||
|
/// <summary>S3 wards (Dota 2): price and rounds a ward watches its lane.</summary>
|
||||||
|
public int WardCost = 40;
|
||||||
|
public int WardRounds = 3;
|
||||||
|
|
||||||
public static LuneBalance Default() { return new LuneBalance(); }
|
public static LuneBalance Default() { return new LuneBalance(); }
|
||||||
|
|
||||||
public int CoreUpgradeCost(int level) { return CoreLevelPrice * (level + 1); }
|
public int CoreUpgradeCost(int level) { return CoreLevelPrice * (level + 1); }
|
||||||
|
|
|
||||||
|
|
@ -628,6 +628,10 @@ namespace Luneraria.Core
|
||||||
MatchState.Boss.GlyphReady = (int[])source.GlyphReady.Clone();
|
MatchState.Boss.GlyphReady = (int[])source.GlyphReady.Clone();
|
||||||
if (source.CoreLevel != null && source.CoreLevel.Length == 2)
|
if (source.CoreLevel != null && source.CoreLevel.Length == 2)
|
||||||
MatchState.Boss.CoreLevel = (int[])source.CoreLevel.Clone();
|
MatchState.Boss.CoreLevel = (int[])source.CoreLevel.Clone();
|
||||||
|
if (source.CampBuff != null && source.CampBuff.Length == 6)
|
||||||
|
MatchState.Boss.CampBuff = (int[])source.CampBuff.Clone();
|
||||||
|
if (source.Wards != null && source.Wards.Length == 6)
|
||||||
|
MatchState.Boss.Wards = (int[])source.Wards.Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyLobby(List<LobbyEntry> entries)
|
public void ApplyLobby(List<LobbyEntry> entries)
|
||||||
|
|
@ -867,7 +871,9 @@ namespace Luneraria.Core
|
||||||
Claim = MatchState.Boss.Claim != null ? MatchState.Boss.Claim.Clone() : null,
|
Claim = MatchState.Boss.Claim != null ? MatchState.Boss.Claim.Clone() : null,
|
||||||
Blessing = (int[])MatchState.Boss.Blessing.Clone(),
|
Blessing = (int[])MatchState.Boss.Blessing.Clone(),
|
||||||
GlyphReady = (int[])MatchState.Boss.GlyphReady.Clone(),
|
GlyphReady = (int[])MatchState.Boss.GlyphReady.Clone(),
|
||||||
CoreLevel = (int[])MatchState.Boss.CoreLevel.Clone()
|
CoreLevel = (int[])MatchState.Boss.CoreLevel.Clone(),
|
||||||
|
CampBuff = (int[])MatchState.Boss.CampBuff.Clone(),
|
||||||
|
Wards = (int[])MatchState.Boss.Wards.Clone()
|
||||||
};
|
};
|
||||||
if (MatchState.Combat != null)
|
if (MatchState.Combat != null)
|
||||||
state.DestroyedCores.AddRange(MatchState.Combat.DestroyedCores);
|
state.DestroyedCores.AddRange(MatchState.Combat.DestroyedCores);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ namespace Luneraria.Core
|
||||||
public string BuildingId = "";
|
public string BuildingId = "";
|
||||||
public int Xp;
|
public int Xp;
|
||||||
public List<string> XpHeroes = new List<string>();
|
public List<string> XpHeroes = new List<string>();
|
||||||
|
/// <summary>S3 camp guardians: the team that takes the camp, -1 for none.</summary>
|
||||||
|
public int ClaimTeam = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -321,7 +323,7 @@ namespace Luneraria.Core
|
||||||
if (heading.LengthSquared() > 0.000001)
|
if (heading.LengthSquared() > 0.000001)
|
||||||
unit.Facing = GdMath.Atan2(heading.X, heading.Y);
|
unit.Facing = GdMath.Atan2(heading.X, heading.Y);
|
||||||
unit.LeapTarget = null;
|
unit.LeapTarget = null;
|
||||||
if (unit.Zone == "lane")
|
if (unit.Zone == "lane" && unit.Kind != "camp")
|
||||||
UpdateProgress(unit, plan.Value);
|
UpdateProgress(unit, plan.Value);
|
||||||
}
|
}
|
||||||
foreach (LuneUnit unit in living)
|
foreach (LuneUnit unit in living)
|
||||||
|
|
@ -428,7 +430,8 @@ namespace Luneraria.Core
|
||||||
bool mobileAlive = !GrottoResolved;
|
bool mobileAlive = !GrottoResolved;
|
||||||
foreach (LuneUnit unit in Units)
|
foreach (LuneUnit unit in Units)
|
||||||
{
|
{
|
||||||
if (unit.Alive && unit.IsMobile() && unit.Zone == "lane")
|
// S3: a camp guardian alone does not hold the combat open.
|
||||||
|
if (unit.Alive && unit.IsMobile() && unit.Zone == "lane" && unit.Kind != "camp")
|
||||||
{
|
{
|
||||||
mobileAlive = true;
|
mobileAlive = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -467,6 +470,7 @@ namespace Luneraria.Core
|
||||||
switch (unit.Kind)
|
switch (unit.Kind)
|
||||||
{
|
{
|
||||||
case "monster": xp = 12 + RoundNumber; break;
|
case "monster": xp = 12 + RoundNumber; break;
|
||||||
|
case "camp": xp = 30 + 2 * RoundNumber; break;
|
||||||
case "champion": xp = 30 + 2 * RoundNumber; break;
|
case "champion": xp = 30 + 2 * RoundNumber; break;
|
||||||
case "boss": xp = LuneContent.BossXp; break;
|
case "boss": xp = LuneContent.BossXp; break;
|
||||||
case "troop":
|
case "troop":
|
||||||
|
|
@ -481,9 +485,35 @@ namespace Luneraria.Core
|
||||||
ev.XpHeroes.Add(other.PersistentUid);
|
ev.XpHeroes.Add(other.PersistentUid);
|
||||||
}
|
}
|
||||||
ev.Xp = xp;
|
ev.Xp = xp;
|
||||||
|
if (unit.Kind == "camp")
|
||||||
|
ev.ClaimTeam = CampClaim(unit);
|
||||||
Events.Add(ev);
|
Events.Add(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// S3: the team with more living units near a fallen guardian takes the camp, on equal
|
||||||
|
/// numbers the one with more health there; an exact tie (mirrored armies) takes nothing.
|
||||||
|
/// Units dying in the same step do not count (health above zero), so order never decides.
|
||||||
|
/// </summary>
|
||||||
|
int CampClaim(LuneUnit camp)
|
||||||
|
{
|
||||||
|
var count = new int[2];
|
||||||
|
var health = new double[2];
|
||||||
|
foreach (LuneUnit other in Units)
|
||||||
|
{
|
||||||
|
if (other.Hp > 0.0 && other.Team < 2 && other.IsMobile() && other.Zone == camp.Zone && other.Position.DistanceTo(camp.Position) <= Balance.CampClaimRadius)
|
||||||
|
{
|
||||||
|
count[other.Team]++;
|
||||||
|
health[other.Team] += other.Hp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count[0] != count[1])
|
||||||
|
return count[0] > count[1] ? 0 : 1;
|
||||||
|
if (Math.Abs(health[0] - health[1]) > 0.5)
|
||||||
|
return health[0] > health[1] ? 0 : 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------- targeting and movement
|
// ---------------------------------------------------------------- targeting and movement
|
||||||
static bool Hostile(LuneUnit unit, LuneUnit other)
|
static bool Hostile(LuneUnit unit, LuneUnit other)
|
||||||
{
|
{
|
||||||
|
|
@ -497,11 +527,11 @@ namespace Luneraria.Core
|
||||||
{
|
{
|
||||||
if (!current.IsBuilding() || BuildingAttackable(current, gates))
|
if (!current.IsBuilding() || BuildingAttackable(current, gates))
|
||||||
{
|
{
|
||||||
if (!unit.IsBuilding() || unit.Position.DistanceTo(current.Position) <= unit.AttackRange())
|
if (!unit.IsStationary() || unit.Position.DistanceTo(current.Position) <= unit.AttackRange())
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
double radius = unit.IsBuilding() ? unit.AttackRange() : Balance.AggroRadius;
|
double radius = unit.IsStationary() ? unit.AttackRange() : Balance.AggroRadius;
|
||||||
LuneUnit best = null;
|
LuneUnit best = null;
|
||||||
double bestDistance = double.PositiveInfinity;
|
double bestDistance = double.PositiveInfinity;
|
||||||
string priority = unit.Def.Priority;
|
string priority = unit.Def.Priority;
|
||||||
|
|
@ -539,7 +569,7 @@ namespace Luneraria.Core
|
||||||
bestDistance = d;
|
bestDistance = d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (best != null || unit.IsBuilding())
|
if (best != null || unit.IsStationary())
|
||||||
return best;
|
return best;
|
||||||
// Buildings: nearby attackable ones; at the end of a lane the whole base is in reach.
|
// Buildings: nearby attackable ones; at the end of a lane the whole base is in reach.
|
||||||
for (int i = 0; i < buildings.Count; i++)
|
for (int i = 0; i < buildings.Count; i++)
|
||||||
|
|
@ -582,6 +612,8 @@ namespace Luneraria.Core
|
||||||
{
|
{
|
||||||
if (unit.LeapTarget != null)
|
if (unit.LeapTarget != null)
|
||||||
return new KeyValuePair<Vec2, double>(LeapLanding(unit, unit.LeapTarget), unit.Progress);
|
return new KeyValuePair<Vec2, double>(LeapLanding(unit, unit.LeapTarget), unit.Progress);
|
||||||
|
if (unit.Kind == "camp")
|
||||||
|
return new KeyValuePair<Vec2, double>(unit.Position, unit.Progress);
|
||||||
double stepLength = unit.Speed() * Balance.MarchSpeedFactor * unit.MovementFactor() * dt;
|
double stepLength = unit.Speed() * Balance.MarchSpeedFactor * unit.MovementFactor() * dt;
|
||||||
Vec2 goal = unit.Position;
|
Vec2 goal = unit.Position;
|
||||||
double travel = 0.0;
|
double travel = 0.0;
|
||||||
|
|
|
||||||
129
Assets/Luneraria/Core/Simulation/LuneFog.cs
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Luneraria.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// S3 fog of war (Dota 2 vision and wards, extended rules). It only decides what a viewer's
|
||||||
|
/// team sees; the simulation never reads it, so the rules and every replay stay the same.
|
||||||
|
/// In combat an enemy unit is visible within reach of an own living unit, an own living
|
||||||
|
/// building or one of the team's wards (a ward watches the middle of its lane). In planning,
|
||||||
|
/// enemy armies show only on scouted lanes: a ward there, or the enemy's outer tower of that
|
||||||
|
/// lane has fallen. Neutral units (camp guardians, the grotto boss) are always visible.
|
||||||
|
/// </summary>
|
||||||
|
public static class LuneFog
|
||||||
|
{
|
||||||
|
public const double UnitSight = 9.0;
|
||||||
|
public const double BuildingSight = 10.0;
|
||||||
|
public const double WardSight = 12.0;
|
||||||
|
|
||||||
|
struct Source
|
||||||
|
{
|
||||||
|
public Vec2 At;
|
||||||
|
public double Radius;
|
||||||
|
public string Zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>The lane is scouted for the team in planning (ward, fallen enemy outer tower, or a ward in the own draft).</summary>
|
||||||
|
public static bool LaneScouted(LuneMatch match, int team, string lane, Draft ownDraft = null)
|
||||||
|
{
|
||||||
|
int index = LuneMap.LaneIndex(lane);
|
||||||
|
if (index < 0)
|
||||||
|
return false;
|
||||||
|
if (match.Boss.Wards[team * 3 + index] > 0)
|
||||||
|
return true;
|
||||||
|
if (ownDraft != null && ownDraft.WardLanes.Contains(lane))
|
||||||
|
return true;
|
||||||
|
foreach (BuildingDef definition in match.Map.Buildings)
|
||||||
|
{
|
||||||
|
if (definition.Team == 1 - team && definition.Lane == lane && definition.Tier == "outer")
|
||||||
|
return match.BuildingHp[definition.Id] <= 0.0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Planning (S3): the enemy's committed army on the lanes the team has scouted, as the
|
||||||
|
/// match will field it (troops and heroes, lane owner first). The planning preview shows
|
||||||
|
/// these; unscouted lanes show nothing of the enemy. Empty without the extended rules.
|
||||||
|
/// </summary>
|
||||||
|
public static List<LuneMatch.ArmyEntry> ScoutedEnemies(LuneMatch match, int team, Draft ownDraft = null)
|
||||||
|
{
|
||||||
|
var result = new List<LuneMatch.ArmyEntry>();
|
||||||
|
if (match == null || !match.Extended || team < 0 || team > 1)
|
||||||
|
return result;
|
||||||
|
int enemy = 1 - team;
|
||||||
|
foreach (string lane in LuneMap.Lanes)
|
||||||
|
{
|
||||||
|
if (!LaneScouted(match, team, lane, ownDraft))
|
||||||
|
continue;
|
||||||
|
for (int slot = enemy * 3; slot < enemy * 3 + 3; slot++)
|
||||||
|
{
|
||||||
|
foreach (LuneMatch.ArmyEntry entry in match.ArmyEntries(slot))
|
||||||
|
{
|
||||||
|
if (entry.Lane == lane)
|
||||||
|
result.Add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Middle of a lane, where a ward watches.</summary>
|
||||||
|
public static Vec2 WardPoint(LuneMatch match, string lane)
|
||||||
|
{
|
||||||
|
return match.Map.LanePoint(0, lane, match.Map.LanePaths[lane].Length * 0.5, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ids of the enemy units the team cannot see in the shown combat (the live combat, or
|
||||||
|
/// the planning preview when planning). Empty without the extended rules or for team -1.
|
||||||
|
/// </summary>
|
||||||
|
public static HashSet<int> Hidden(LuneMatch match, LuneCombat shown, int team, bool planning, Draft ownDraft = null)
|
||||||
|
{
|
||||||
|
var hidden = new HashSet<int>();
|
||||||
|
if (match == null || shown == null || !match.Extended || team < 0 || team > 1)
|
||||||
|
return hidden;
|
||||||
|
if (planning)
|
||||||
|
{
|
||||||
|
foreach (LuneUnit unit in shown.Units)
|
||||||
|
{
|
||||||
|
if (unit.Team == 1 - team && unit.IsMobile() && (unit.Zone != "lane" || !LaneScouted(match, team, unit.Lane, ownDraft)))
|
||||||
|
hidden.Add(unit.Id);
|
||||||
|
}
|
||||||
|
return hidden;
|
||||||
|
}
|
||||||
|
var sources = new List<Source>();
|
||||||
|
foreach (LuneUnit unit in shown.Units)
|
||||||
|
{
|
||||||
|
if (unit.Team != team || !unit.Alive)
|
||||||
|
continue;
|
||||||
|
if (unit.IsMobile())
|
||||||
|
sources.Add(new Source { At = unit.Position, Radius = UnitSight, Zone = unit.Zone });
|
||||||
|
else if (unit.IsBuilding())
|
||||||
|
sources.Add(new Source { At = unit.Position, Radius = BuildingSight, Zone = "lane" });
|
||||||
|
}
|
||||||
|
foreach (string lane in LuneMap.Lanes)
|
||||||
|
{
|
||||||
|
if (match.Boss.Wards[team * 3 + LuneMap.LaneIndex(lane)] > 0)
|
||||||
|
sources.Add(new Source { At = WardPoint(match, lane), Radius = WardSight, Zone = "lane" });
|
||||||
|
}
|
||||||
|
foreach (LuneUnit unit in shown.Units)
|
||||||
|
{
|
||||||
|
if (unit.Team != 1 - team || !unit.IsMobile())
|
||||||
|
continue;
|
||||||
|
bool seen = false;
|
||||||
|
foreach (Source source in sources)
|
||||||
|
{
|
||||||
|
if (source.Zone == unit.Zone && unit.Position.DistanceTo(source.At) <= source.Radius)
|
||||||
|
{
|
||||||
|
seen = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!seen)
|
||||||
|
hidden.Add(unit.Id);
|
||||||
|
}
|
||||||
|
return hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/Luneraria/Core/Simulation/LuneFog.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c7893fc71c204c29bacd289a276d0be5
|
||||||
|
|
@ -52,6 +52,8 @@ namespace Luneraria.Core
|
||||||
Boss.Blessing = new int[2];
|
Boss.Blessing = new int[2];
|
||||||
Boss.GlyphReady = new[] { 1, 1 };
|
Boss.GlyphReady = new[] { 1, 1 };
|
||||||
Boss.CoreLevel = new int[2];
|
Boss.CoreLevel = new int[2];
|
||||||
|
Boss.CampBuff = new int[6];
|
||||||
|
Boss.Wards = new int[6];
|
||||||
RoundNumber = 1;
|
RoundNumber = 1;
|
||||||
Phase = Phase.Planning;
|
Phase = Phase.Planning;
|
||||||
Winner = Ongoing;
|
Winner = Ongoing;
|
||||||
|
|
@ -336,6 +338,22 @@ namespace Luneraria.Core
|
||||||
draft.GlyphLane = lane;
|
draft.GlyphLane = lane;
|
||||||
return Result(true, lane.Length == 0 ? "Glyphe zurückgenommen." : "Glyphe für " + LuneMap.LaneNames[lane] + " bereitgehalten.");
|
return Result(true, lane.Length == 0 ? "Glyphe zurückgenommen." : "Glyphe für " + LuneMap.LaneNames[lane] + " bereitgehalten.");
|
||||||
}
|
}
|
||||||
|
case "ward":
|
||||||
|
{
|
||||||
|
if (!Extended)
|
||||||
|
return Result(false, "Späher gibt es nur mit erweiterten Regeln.");
|
||||||
|
string lane = command.Lane ?? "";
|
||||||
|
int index = LuneMap.LaneIndex(lane);
|
||||||
|
if (index < 0)
|
||||||
|
return Result(false, "Unbekannte Lane.");
|
||||||
|
if (draft.WardLanes.Contains(lane))
|
||||||
|
return Result(false, "Auf dieser Lane steht schon dein Späher.");
|
||||||
|
if (draft.Gold < Balance.WardCost)
|
||||||
|
return Result(false, string.Format("Es fehlen {0} Gold.", Balance.WardCost - draft.Gold));
|
||||||
|
draft.Gold -= Balance.WardCost;
|
||||||
|
draft.WardLanes.Add(lane);
|
||||||
|
return Result(true, "Späher auf " + LuneMap.LaneNames[lane] + " gesetzt (" + Balance.WardRounds + " Runden).");
|
||||||
|
}
|
||||||
case "core_upgrade":
|
case "core_upgrade":
|
||||||
{
|
{
|
||||||
if (!Extended)
|
if (!Extended)
|
||||||
|
|
@ -512,6 +530,8 @@ namespace Luneraria.Core
|
||||||
Combat.GlyphLane[team] = _glyphLane[team];
|
Combat.GlyphLane[team] = _glyphLane[team];
|
||||||
}
|
}
|
||||||
SpawnWaves();
|
SpawnWaves();
|
||||||
|
if (Extended)
|
||||||
|
SpawnCamps();
|
||||||
SpawnChampions();
|
SpawnChampions();
|
||||||
SpawnDeployedBoss();
|
SpawnDeployedBoss();
|
||||||
SpawnArmies();
|
SpawnArmies();
|
||||||
|
|
@ -576,6 +596,85 @@ namespace Luneraria.Core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------- S3 extended rules
|
||||||
|
public static readonly string[] CampNames = { "Glutwächter", "Mondwächter", "Goldwächter" };
|
||||||
|
public static readonly string[] CampBuffNames = { "Glutsegen", "Mondschild", "Beute" };
|
||||||
|
|
||||||
|
/// <summary>S3: a camp round (League of Legends buff camps) has a guardian in the middle of every lane.</summary>
|
||||||
|
public bool CampRound(int round) { return Extended && round > 0 && round % GdMath.Max(1, Balance.CampEvery) == 0; }
|
||||||
|
|
||||||
|
public int CampBuffLeft(int team, string lane) { return Boss.CampBuff[team * 3 + LuneMap.LaneIndex(lane)]; }
|
||||||
|
|
||||||
|
/// <summary>A neutral guardian scaled like the waves of the round; the model is the Bruchhirsch.</summary>
|
||||||
|
public UnitDef CampDefinition(string lane)
|
||||||
|
{
|
||||||
|
UnitDef definition = DataCatalog.GetEnemy("e07");
|
||||||
|
definition.DisplayName = CampNames[LuneMap.LaneIndex(lane)];
|
||||||
|
definition.MaxHp = Balance.CampHp * LuneWaves.Strength(Balance, RoundNumber, Balance.WaveHpGrowth);
|
||||||
|
definition.Damage = Balance.CampDamage * LuneWaves.Strength(Balance, RoundNumber, Balance.WaveDamageGrowth);
|
||||||
|
definition.AttackRange = Balance.CampRange;
|
||||||
|
definition.Speed = 0.0;
|
||||||
|
definition.Bounty = 0;
|
||||||
|
definition.IsBoss = false;
|
||||||
|
definition.ViewScale = 1.35;
|
||||||
|
definition.Ability = "";
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpawnCamps()
|
||||||
|
{
|
||||||
|
if (!CampRound(RoundNumber))
|
||||||
|
return;
|
||||||
|
foreach (string lane in LuneMap.Lanes)
|
||||||
|
{
|
||||||
|
double middle = Map.LanePaths[lane].Length * 0.5;
|
||||||
|
LuneUnit camp = Combat.Spawn("camp", LuneCombat.Neutral, lane, CampDefinition(lane), middle, 0.0);
|
||||||
|
camp.Position = Map.LanePoint(0, lane, middle, 0.0);
|
||||||
|
camp.PreviousPosition = camp.Position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Camp buffs on the army: Glutsegen (top) raises damage; Mondschild (mid) is applied as a shield at spawn.</summary>
|
||||||
|
UnitDef Buffed(UnitDef definition, int team)
|
||||||
|
{
|
||||||
|
if (Boss.CampBuff[team * 3] > 0)
|
||||||
|
definition.Damage *= 1.0 + Balance.CampDamageBuff;
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CampShield(LuneUnit unit)
|
||||||
|
{
|
||||||
|
if (Extended && unit.Team < 2 && Boss.CampBuff[unit.Team * 3 + 1] > 0)
|
||||||
|
unit.GrantShield(unit.MaxHp * Balance.CampShieldBuff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Settlement of the camps: running buffs lose a combat, then every claimed camp gives its
|
||||||
|
/// lane's buff to the team that took it (Beute pays at once).
|
||||||
|
/// </summary>
|
||||||
|
void SettleCamps(int[] gains)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Boss.CampBuff.Length; i++)
|
||||||
|
Boss.CampBuff[i] = GdMath.Max(0, Boss.CampBuff[i] - 1);
|
||||||
|
for (int i = 0; i < Boss.Wards.Length; i++)
|
||||||
|
Boss.Wards[i] = GdMath.Max(0, Boss.Wards[i] - 1);
|
||||||
|
foreach (CombatEvent ev in Combat.Events)
|
||||||
|
{
|
||||||
|
if (ev.Kind != "camp" || ev.ClaimTeam < 0)
|
||||||
|
continue;
|
||||||
|
int lane = LuneMap.LaneIndex(ev.Lane);
|
||||||
|
if (lane == 2)
|
||||||
|
{
|
||||||
|
for (int slot = ev.ClaimTeam * 3; slot < ev.ClaimTeam * 3 + 3; slot++)
|
||||||
|
gains[slot] += Balance.CampLootGold;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Boss.CampBuff[ev.ClaimTeam * 3 + lane] = Balance.CampBuffRounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------- S2 extended rules
|
// ---------------------------------------------------------------- S2 extended rules
|
||||||
readonly string[] _glyphLane = { "", "" };
|
readonly string[] _glyphLane = { "", "" };
|
||||||
|
|
||||||
|
|
@ -592,6 +691,12 @@ namespace Luneraria.Core
|
||||||
for (int slot = team * 3; slot < team * 3 + 3; slot++)
|
for (int slot = team * 3; slot < team * 3 + 3; slot++)
|
||||||
{
|
{
|
||||||
Player player = Players[slot];
|
Player player = Players[slot];
|
||||||
|
// S3 wards: a new ward watches its lane for WardRounds combats.
|
||||||
|
foreach (string lane in player.Draft.WardLanes)
|
||||||
|
{
|
||||||
|
int index = team * 3 + LuneMap.LaneIndex(lane);
|
||||||
|
Boss.Wards[index] = GdMath.Max(Boss.Wards[index], Balance.WardRounds);
|
||||||
|
}
|
||||||
if (_glyphLane[team].Length == 0 && player.Draft.GlyphLane.Length > 0 && RoundNumber >= Boss.GlyphReady[team])
|
if (_glyphLane[team].Length == 0 && player.Draft.GlyphLane.Length > 0 && RoundNumber >= Boss.GlyphReady[team])
|
||||||
_glyphLane[team] = player.Draft.GlyphLane;
|
_glyphLane[team] = player.Draft.GlyphLane;
|
||||||
for (int i = 0; i < player.Draft.CoreInvest; i++)
|
for (int i = 0; i < player.Draft.CoreInvest; i++)
|
||||||
|
|
@ -817,9 +922,10 @@ namespace Luneraria.Core
|
||||||
ArmyEntry entry = ordered[index];
|
ArmyEntry entry = ordered[index];
|
||||||
int row = index / 4;
|
int row = index / 4;
|
||||||
double lateral = ((double)(index % 4) - 1.5) * 1.2;
|
double lateral = ((double)(index % 4) - 1.5) * 1.2;
|
||||||
LuneUnit spawned = Combat.Spawn(entry.Kind, team, lane, Extended ? Blessed(entry.Definition, team, entry.Kind) : entry.Definition,
|
LuneUnit spawned = Combat.Spawn(entry.Kind, team, lane, Extended ? Buffed(Blessed(entry.Definition, team, entry.Kind), team) : entry.Definition,
|
||||||
GdMath.Max(0.4, 7.2 - (double)row * 1.5), lateral, entry.Slot, entry.Uid);
|
GdMath.Max(0.4, 7.2 - (double)row * 1.5), lateral, entry.Slot, entry.Uid);
|
||||||
Exhaust(spawned);
|
Exhaust(spawned);
|
||||||
|
CampShield(spawned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -837,8 +943,9 @@ namespace Luneraria.Core
|
||||||
{
|
{
|
||||||
ArmyEntry entry = ordered[index];
|
ArmyEntry entry = ordered[index];
|
||||||
Vec2 at = entryPoint - inward * (double)(index / 3) * 1.2 + across * ((double)(index % 3) - 1.0) * 1.1;
|
Vec2 at = entryPoint - inward * (double)(index / 3) * 1.2 + across * ((double)(index % 3) - 1.0) * 1.1;
|
||||||
LuneUnit spawned = Combat.SpawnAt(entry.Kind, team, Grotto, Extended ? Blessed(entry.Definition, team, entry.Kind) : entry.Definition, at, entry.Slot, entry.Uid);
|
LuneUnit spawned = Combat.SpawnAt(entry.Kind, team, Grotto, Extended ? Buffed(Blessed(entry.Definition, team, entry.Kind), team) : entry.Definition, at, entry.Slot, entry.Uid);
|
||||||
Exhaust(spawned);
|
Exhaust(spawned);
|
||||||
|
CampShield(spawned);
|
||||||
expedition = true;
|
expedition = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -938,6 +1045,8 @@ namespace Luneraria.Core
|
||||||
Players[unit.OwnerSlot].Hero.Exhausted = !unit.Alive;
|
Players[unit.OwnerSlot].Hero.Exhausted = !unit.Alive;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Extended)
|
||||||
|
SettleCamps(gains);
|
||||||
int income = Balance.RoundIncome(RoundNumber);
|
int income = Balance.RoundIncome(RoundNumber);
|
||||||
foreach (Player player in Players)
|
foreach (Player player in Players)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Luneraria.Core
|
||||||
{
|
{
|
||||||
/// <summary>Attack type (row) against armour type (column): Klinge, Durchschlag, Impuls.</summary>
|
/// <summary>Attack type (row) against armour type (column): Klinge, Durchschlag, Impuls.</summary>
|
||||||
public static readonly double[,] DamageMatrix = { { 1.30, 0.75, 1.00 }, { 1.00, 1.30, 0.75 }, { 0.75, 1.00, 1.30 } };
|
public static readonly double[,] DamageMatrix = { { 1.30, 0.75, 1.00 }, { 1.00, 1.30, 0.75 }, { 0.75, 1.00, 1.30 } };
|
||||||
public static readonly string[] MobileKinds = { "troop", "hero", "monster", "champion", "boss" };
|
public static readonly string[] MobileKinds = { "troop", "hero", "monster", "champion", "boss", "camp" };
|
||||||
|
|
||||||
/// <summary>Sequential per combat, assigned in spawn order (deterministic).</summary>
|
/// <summary>Sequential per combat, assigned in spawn order (deterministic).</summary>
|
||||||
public int Id;
|
public int Id;
|
||||||
|
|
@ -85,6 +85,9 @@ namespace Luneraria.Core
|
||||||
|
|
||||||
public bool IsBuilding() { return Kind == "tower" || Kind == "core"; }
|
public bool IsBuilding() { return Kind == "tower" || Kind == "core"; }
|
||||||
|
|
||||||
|
/// <summary>Buildings and S3 camp guardians stay where they are and only fight in reach.</summary>
|
||||||
|
public bool IsStationary() { return IsBuilding() || Kind == "camp"; }
|
||||||
|
|
||||||
public bool IsMobile() { return Array.IndexOf(MobileKinds, Kind) >= 0; }
|
public bool IsMobile() { return Array.IndexOf(MobileKinds, Kind) >= 0; }
|
||||||
|
|
||||||
public double AttackRange() { return Def.AttackRange; }
|
public double AttackRange() { return Def.AttackRange; }
|
||||||
|
|
|
||||||
|
|
@ -79,10 +79,13 @@ namespace Luneraria.Core
|
||||||
public string GlyphLane = "";
|
public string GlyphLane = "";
|
||||||
/// <summary>S2: Ancient levels this player buys in this planning.</summary>
|
/// <summary>S2: Ancient levels this player buys in this planning.</summary>
|
||||||
public int CoreInvest;
|
public int CoreInvest;
|
||||||
|
/// <summary>S3: lanes the player places a ward on in this planning.</summary>
|
||||||
|
public List<string> WardLanes = new List<string>();
|
||||||
|
|
||||||
public Draft Clone()
|
public Draft Clone()
|
||||||
{
|
{
|
||||||
var copy = new Draft { Gold = Gold, NextSeq = NextSeq, BossLane = BossLane, GlyphLane = GlyphLane, CoreInvest = CoreInvest, Hero = Hero != null ? Hero.Clone() : null };
|
var copy = new Draft { Gold = Gold, NextSeq = NextSeq, BossLane = BossLane, GlyphLane = GlyphLane, CoreInvest = CoreInvest, Hero = Hero != null ? Hero.Clone() : null,
|
||||||
|
WardLanes = new List<string>(WardLanes) };
|
||||||
foreach (RosterEntry entry in Roster)
|
foreach (RosterEntry entry in Roster)
|
||||||
copy.Roster.Add(entry.Clone());
|
copy.Roster.Add(entry.Clone());
|
||||||
foreach (Booking booking in NewBookings)
|
foreach (Booking booking in NewBookings)
|
||||||
|
|
@ -138,6 +141,10 @@ namespace Luneraria.Core
|
||||||
public int[] GlyphReady = { 1, 1 };
|
public int[] GlyphReady = { 1, 1 };
|
||||||
/// <summary>S2 (extended rules): Ancient level per team, 0..3 (Legion TD 2 king upgrades).</summary>
|
/// <summary>S2 (extended rules): Ancient level per team, 0..3 (Legion TD 2 king upgrades).</summary>
|
||||||
public int[] CoreLevel = new int[2];
|
public int[] CoreLevel = new int[2];
|
||||||
|
/// <summary>S3 (extended rules): combats left of the camp buffs, index team × 3 + lane (top Glutsegen, mid Mondschild).</summary>
|
||||||
|
public int[] CampBuff = new int[6];
|
||||||
|
/// <summary>S3 (extended rules): rounds left of each team's ward per lane (team × 3 + lane).</summary>
|
||||||
|
public int[] Wards = new int[6];
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class BossLogEntry
|
public sealed class BossLogEntry
|
||||||
|
|
@ -266,5 +273,7 @@ namespace Luneraria.Core
|
||||||
public static Command Glyph(string lane) { return new Command { Type = "glyph", Lane = lane }; }
|
public static Command Glyph(string lane) { return new Command { Type = "glyph", Lane = lane }; }
|
||||||
/// <summary>S2: buy the next Ancient level for the team.</summary>
|
/// <summary>S2: buy the next Ancient level for the team.</summary>
|
||||||
public static Command CoreUpgrade() { return new Command { Type = "core_upgrade" }; }
|
public static Command CoreUpgrade() { return new Command { Type = "core_upgrade" }; }
|
||||||
|
/// <summary>S3: place a ward on a lane (fog of war).</summary>
|
||||||
|
public static Command Ward(string lane) { return new Command { Type = "ward", Lane = lane }; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,10 @@ namespace Luneraria.Net
|
||||||
Int(text, boss.GlyphReady != null && boss.GlyphReady.Length > team ? boss.GlyphReady[team] : 1);
|
Int(text, boss.GlyphReady != null && boss.GlyphReady.Length > team ? boss.GlyphReady[team] : 1);
|
||||||
Int(text, boss.CoreLevel != null && boss.CoreLevel.Length > team ? boss.CoreLevel[team] : 0);
|
Int(text, boss.CoreLevel != null && boss.CoreLevel.Length > team ? boss.CoreLevel[team] : 0);
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
Int(text, boss.CampBuff != null && boss.CampBuff.Length > i ? boss.CampBuff[i] : 0);
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
Int(text, boss.Wards != null && boss.Wards.Length > i ? boss.Wards[i] : 0);
|
||||||
var cores = state.DestroyedCores ?? new List<int>();
|
var cores = state.DestroyedCores ?? new List<int>();
|
||||||
Int(text, cores.Count);
|
Int(text, cores.Count);
|
||||||
foreach (int core in cores)
|
foreach (int core in cores)
|
||||||
|
|
@ -285,6 +289,7 @@ namespace Luneraria.Net
|
||||||
Str(text, draft.BossLane ?? "");
|
Str(text, draft.BossLane ?? "");
|
||||||
Str(text, draft.GlyphLane ?? "");
|
Str(text, draft.GlyphLane ?? "");
|
||||||
Int(text, draft.CoreInvest);
|
Int(text, draft.CoreInvest);
|
||||||
|
Str(text, string.Join("\x1d", draft.WardLanes));
|
||||||
WriteRosterList(text, draft.Roster);
|
WriteRosterList(text, draft.Roster);
|
||||||
Int(text, draft.Hero != null ? 1 : 0);
|
Int(text, draft.Hero != null ? 1 : 0);
|
||||||
if (draft.Hero != null)
|
if (draft.Hero != null)
|
||||||
|
|
@ -669,6 +674,10 @@ namespace Luneraria.Net
|
||||||
state.Boss.GlyphReady[team] = Integer(1);
|
state.Boss.GlyphReady[team] = Integer(1);
|
||||||
state.Boss.CoreLevel[team] = Integer();
|
state.Boss.CoreLevel[team] = Integer();
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
state.Boss.CampBuff[i] = Integer();
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
state.Boss.Wards[i] = Integer();
|
||||||
int coreCount = Integer();
|
int coreCount = Integer();
|
||||||
for (int i = 0; i < coreCount; i++)
|
for (int i = 0; i < coreCount; i++)
|
||||||
state.DestroyedCores.Add(Integer());
|
state.DestroyedCores.Add(Integer());
|
||||||
|
|
@ -718,6 +727,7 @@ namespace Luneraria.Net
|
||||||
if (Flag())
|
if (Flag())
|
||||||
{
|
{
|
||||||
var draft = new Draft { Gold = Integer(), NextSeq = Integer(), BossLane = Text() ?? "", GlyphLane = Text() ?? "", CoreInvest = Integer() };
|
var draft = new Draft { Gold = Integer(), NextSeq = Integer(), BossLane = Text() ?? "", GlyphLane = Text() ?? "", CoreInvest = Integer() };
|
||||||
|
AddSplit(draft.WardLanes, Text());
|
||||||
draft.Roster = ReadRosterList();
|
draft.Roster = ReadRosterList();
|
||||||
if (Flag())
|
if (Flag())
|
||||||
draft.Hero = ReadHero();
|
draft.Hero = ReadHero();
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ namespace Luneraria.Core.Tests
|
||||||
|
|
||||||
public static IList<CheckSuite> All()
|
public static IList<CheckSuite> All()
|
||||||
{
|
{
|
||||||
return new List<CheckSuite> { new ContentSuite(), new CoreRulesSuite(), new M2RulesSuite(), new GoldenSuite(), new DeterminismSuite(), new NetSuite(), new NetRoundsSuite(), new H1HeroSuite(), new S1RulesSuite(), new S2RulesSuite() };
|
return new List<CheckSuite> { new ContentSuite(), new CoreRulesSuite(), new M2RulesSuite(), new GoldenSuite(), new DeterminismSuite(), new NetSuite(), new NetRoundsSuite(), new H1HeroSuite(), new S1RulesSuite(), new S2RulesSuite(), new S3RulesSuite() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
183
Assets/Luneraria/Tests/Core/S3RulesSuite.cs
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Luneraria.Core.Tests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// S3: bots that recruit their heroes early and a rotation over all profiles, neutral camps
|
||||||
|
/// (League of Legends buff camps), wards and the fog of war (Dota 2) under the extended
|
||||||
|
/// rules; none of it under the reference rules.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class S3RulesSuite : CheckSuite
|
||||||
|
{
|
||||||
|
public override string Name { get { return "s3"; } }
|
||||||
|
|
||||||
|
protected override void RunChecks()
|
||||||
|
{
|
||||||
|
TestReference();
|
||||||
|
TestBots();
|
||||||
|
TestCamps();
|
||||||
|
TestWards();
|
||||||
|
TestFog();
|
||||||
|
}
|
||||||
|
|
||||||
|
static LuneMatch NewMatch(bool extended, int seed = 61)
|
||||||
|
{
|
||||||
|
var state = new LuneMatch();
|
||||||
|
state.Setup(new MatchOptions { Seed = seed, HumanSlot = -1, Extended = extended,
|
||||||
|
Bunds = new List<string> { "glutpakt", "wurzelbund", "glutpakt", "wurzelbund", "glutpakt", "wurzelbund" } });
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestReference()
|
||||||
|
{
|
||||||
|
LuneMatch state = NewMatch(false);
|
||||||
|
state.RoundNumber = 3;
|
||||||
|
state.Players[0].Draft.Gold += 500;
|
||||||
|
Check(!state.Submit(0, Command.Ward("mid")).Ok, "reference: no wards");
|
||||||
|
state.BeginCombat();
|
||||||
|
Check(state.Combat.Units.All(u => u.Kind != "camp"), "reference: no camps in round 3");
|
||||||
|
Check(LuneFog.Hidden(state, state.Combat, 0, false).Count == 0, "reference: no fog");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestBots()
|
||||||
|
{
|
||||||
|
var profiles = new HashSet<string>();
|
||||||
|
LuneMatch probe = NewMatch(true, 1);
|
||||||
|
for (int slot = 0; slot < 6; slot++)
|
||||||
|
profiles.Add(LuneBot.ProfileFor(probe, slot));
|
||||||
|
Check(profiles.Count == 6, "extended rotation gives six different profiles (" + string.Join(",", profiles) + ")");
|
||||||
|
int heroes = 0;
|
||||||
|
int seats = 0;
|
||||||
|
for (int seed = 1; seed <= 6; seed++)
|
||||||
|
{
|
||||||
|
LuneMatch match = new LuneMatch();
|
||||||
|
match.Setup(new MatchOptions { Seed = seed, HumanSlot = -1, Extended = true });
|
||||||
|
while (match.Phase != Phase.Over && match.RoundNumber <= 6)
|
||||||
|
{
|
||||||
|
for (int slot = 0; slot < 6; slot++)
|
||||||
|
LuneBot.Plan(match, slot);
|
||||||
|
match.BeginCombat();
|
||||||
|
match.FinishCombat();
|
||||||
|
}
|
||||||
|
heroes += match.Players.Count(p => p.Hero != null);
|
||||||
|
seats += 6;
|
||||||
|
}
|
||||||
|
Check(heroes * 2 >= seats, "extended bots have most heroes after round 6 (" + heroes + " of " + seats + ")");
|
||||||
|
LuneMatch reference = new LuneMatch();
|
||||||
|
reference.Setup(new MatchOptions { Seed = 1, HumanSlot = -1 });
|
||||||
|
for (int round = 0; round < 6; round++)
|
||||||
|
{
|
||||||
|
for (int slot = 0; slot < 6; slot++)
|
||||||
|
LuneBot.Plan(reference, slot);
|
||||||
|
reference.BeginCombat();
|
||||||
|
reference.FinishCombat();
|
||||||
|
}
|
||||||
|
Check(reference.Players.Count(p => p.Hero != null) == 0, "reference bots keep their late heroes (parity)");
|
||||||
|
LuneMatch bounty = NewMatch(true);
|
||||||
|
Check(bounty.ChampionBountyFor(100) == 50 && NewMatch(false).ChampionBountyFor(100) == 100, "extended: defenders get half a champion's bounty");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestCamps()
|
||||||
|
{
|
||||||
|
LuneMatch state = NewMatch(true);
|
||||||
|
Check(!state.CampRound(1) && !state.CampRound(2) && state.CampRound(3) && state.CampRound(6), "camps every third round");
|
||||||
|
state.BeginCombat();
|
||||||
|
Check(state.Combat.Units.All(u => u.Kind != "camp"), "no camp in round 1");
|
||||||
|
state.FinishCombat();
|
||||||
|
state.RoundNumber = 3;
|
||||||
|
state.Players[0].Draft = state.Snapshot(state.Players[0]);
|
||||||
|
state.BeginCombat();
|
||||||
|
List<LuneUnit> camps = state.Combat.Units.Where(u => u.Kind == "camp").ToList();
|
||||||
|
Check(camps.Count == 3 && camps.All(c => c.Team == LuneCombat.Neutral && c.Zone == "lane"), "three neutral guardians, one per lane");
|
||||||
|
LuneUnit top = camps.First(c => c.Lane == "top");
|
||||||
|
Vec2 start = top.Position;
|
||||||
|
for (int i = 0; i < 40; i++)
|
||||||
|
state.Combat.Step();
|
||||||
|
Check(top.Position.DistanceTo(start) < 0.000001, "a guardian never moves");
|
||||||
|
// Blau's units stand next to the top guardian when it falls.
|
||||||
|
foreach (LuneUnit unit in state.Combat.Units.Where(u => u.Team == 0 && u.IsMobile()).Take(4))
|
||||||
|
unit.Position = top.Position + new Vec2(1.0, 0.0);
|
||||||
|
top.Hp = 0.0;
|
||||||
|
LuneUnit bot = camps.First(c => c.Lane == "bot");
|
||||||
|
foreach (LuneUnit unit in state.Combat.Units.Where(u => u.Team == 1 && u.IsMobile()).Take(4))
|
||||||
|
unit.Position = bot.Position + new Vec2(1.0, 0.0);
|
||||||
|
bot.Hp = 0.0;
|
||||||
|
state.Combat.Step();
|
||||||
|
CombatEvent topEvent = state.Combat.Events.First(e => e.Kind == "camp" && e.Lane == "top");
|
||||||
|
Check(topEvent.ClaimTeam == 0, "the team with more units near the guardian takes the camp");
|
||||||
|
int[] before = state.Players.Select(p => p.Gold).ToArray();
|
||||||
|
state.FinishCombat();
|
||||||
|
Check(state.Boss.CampBuff[0] == 2 && state.Boss.CampBuff[3] == 0, "Glutsegen for Blau for two combats");
|
||||||
|
int redGain = state.Players[4].Gold - before[4] - state.LastSettlement.Gains[4] + 50;
|
||||||
|
Check(state.LastSettlement.Gains[3] >= 50 && state.LastSettlement.Gains[4] >= 50 && state.LastSettlement.Gains[5] >= 50, "Beute: Rot's players get 50 gold each");
|
||||||
|
state.Players[0].Draft.Gold += 500;
|
||||||
|
state.Submit(0, Command.Buy("g01", "top"));
|
||||||
|
state.BeginCombat();
|
||||||
|
LuneUnit troop = state.Combat.Units.First(u => u.Kind == "troop" && u.OwnerSlot == 0 && u.Def.Id == "g01");
|
||||||
|
Check(GdMath.IsEqualApprox(troop.Def.Damage, DataCatalog.GetUnit("g01").Damage * 1.10), "Glutsegen: +10 % damage");
|
||||||
|
state.FinishCombat();
|
||||||
|
state.Boss.CampBuff[4] = 1;
|
||||||
|
state.Players[3].Draft.Gold += 500;
|
||||||
|
state.Submit(3, Command.Buy("w01", "top"));
|
||||||
|
state.BeginCombat();
|
||||||
|
LuneUnit red = state.Combat.Units.First(u => u.Kind == "troop" && u.Team == 1);
|
||||||
|
Check(GdMath.IsEqualApprox(red.Shield, red.MaxHp * 0.10) || red.Shield > red.MaxHp * 0.10, "Mondschild: shield of 10 % at the start");
|
||||||
|
Check(redGain >= 0, "settlement consistent");
|
||||||
|
// Combats end without waiting for a lone guardian.
|
||||||
|
LuneMatch lonely = NewMatch(true);
|
||||||
|
lonely.RoundNumber = 3;
|
||||||
|
lonely.BeginCombat();
|
||||||
|
foreach (LuneUnit unit in lonely.Combat.Units.Where(u => u.Kind != "camp" && u.IsMobile()))
|
||||||
|
unit.Hp = 0.0;
|
||||||
|
lonely.Combat.Step();
|
||||||
|
lonely.Combat.Step();
|
||||||
|
Check(lonely.Combat.Finished && lonely.Combat.EndReason == "cleared", "a guardian alone does not hold the combat open");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestWards()
|
||||||
|
{
|
||||||
|
LuneMatch state = NewMatch(true);
|
||||||
|
int gold = state.GoldOf(0);
|
||||||
|
Check(!state.Submit(0, Command.Ward("river")).Ok, "unknown lane rejected");
|
||||||
|
Check(state.Submit(0, Command.Ward("mid")).Ok && state.GoldOf(0) == gold - 40, "a ward costs 40");
|
||||||
|
Check(!state.Submit(0, Command.Ward("mid")).Ok, "one ward per lane and planning");
|
||||||
|
Check(LuneFog.LaneScouted(state, 0, "mid", state.Players[0].Draft) && !LuneFog.LaneScouted(state, 0, "mid"), "the own draft ward scouts at once, the team sees it after the commit");
|
||||||
|
state.BeginCombat();
|
||||||
|
Check(state.Boss.Wards[1] == 3 && state.Boss.Wards[4] == 0, "the team ward watches mid for three rounds");
|
||||||
|
state.FinishCombat();
|
||||||
|
Check(state.Boss.Wards[1] == 2 && LuneFog.LaneScouted(state, 0, "mid") && !LuneFog.LaneScouted(state, 1, "mid"), "it counts down and scouts only for Blau");
|
||||||
|
state.BuildingHp["rot_top_outer"] = 0.0;
|
||||||
|
Check(LuneFog.LaneScouted(state, 0, "top"), "a fallen enemy outer tower scouts the lane");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestFog()
|
||||||
|
{
|
||||||
|
LuneMatch state = NewMatch(true);
|
||||||
|
state.RoundNumber = 3;
|
||||||
|
state.BeginCombat();
|
||||||
|
HashSet<int> hidden = LuneFog.Hidden(state, state.Combat, 0, false);
|
||||||
|
Check(state.Combat.Units.Where(u => u.Team == 1 && u.IsMobile()).All(u => hidden.Contains(u.Id)), "at combat start Blau sees no Rot unit (they stand at their base)");
|
||||||
|
Check(state.Combat.Units.Where(u => u.Team != 1).All(u => !hidden.Contains(u.Id)), "own and neutral units are always visible");
|
||||||
|
LuneUnit enemy = state.Combat.Units.First(u => u.Team == 1 && u.IsMobile());
|
||||||
|
LuneUnit own = state.Combat.Units.First(u => u.Team == 0 && u.IsMobile() && u.Zone == enemy.Zone);
|
||||||
|
enemy.Position = own.Position + new Vec2(5.0, 0.0);
|
||||||
|
Check(!LuneFog.Hidden(state, state.Combat, 0, false).Contains(enemy.Id), "an enemy within 9 m of an own unit is visible");
|
||||||
|
enemy.Position = LuneFog.WardPoint(state, enemy.Lane == "grotto" ? "mid" : enemy.Lane);
|
||||||
|
bool before = LuneFog.Hidden(state, state.Combat, 0, false).Contains(enemy.Id);
|
||||||
|
state.Boss.Wards[LuneMap.LaneIndex(enemy.Lane)] = 2;
|
||||||
|
Check(before && !LuneFog.Hidden(state, state.Combat, 0, false).Contains(enemy.Id), "a ward reveals the middle of its lane");
|
||||||
|
state.FinishCombat();
|
||||||
|
LuneMatch plan = NewMatch(true);
|
||||||
|
plan.Players[3].Draft.Gold += 200;
|
||||||
|
plan.Submit(3, Command.Buy("w01", "top"));
|
||||||
|
plan.Submit(3, Command.Buy("w01", "mid"));
|
||||||
|
plan.BeginCombat();
|
||||||
|
plan.FinishCombat();
|
||||||
|
plan.Boss.Wards[0] = 1;
|
||||||
|
List<LuneMatch.ArmyEntry> scouted = LuneFog.ScoutedEnemies(plan, 0);
|
||||||
|
Check(scouted.Any(e => e.Lane == "top" && e.Slot == 3) && scouted.All(e => e.Lane == "top"), "planning: the warded lane shows Rot's committed army, the others nothing");
|
||||||
|
Check(LuneFog.ScoutedEnemies(plan, 1).Count == 0 && LuneFog.ScoutedEnemies(NewMatch(false), 0).Count == 0, "no scouting without a ward or under the reference rules");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/Luneraria/Tests/Core/S3RulesSuite.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9632c5c9699a4bc99db6e8b3479cf103
|
||||||
|
|
@ -54,5 +54,6 @@ namespace Luneraria.Core.Tests
|
||||||
[Test] public void H1Heroes() { RunSuite(new H1HeroSuite()); }
|
[Test] public void H1Heroes() { RunSuite(new H1HeroSuite()); }
|
||||||
[Test] public void S1Rules() { RunSuite(new S1RulesSuite()); }
|
[Test] public void S1Rules() { RunSuite(new S1RulesSuite()); }
|
||||||
[Test] public void S2Rules() { RunSuite(new S2RulesSuite()); }
|
[Test] public void S2Rules() { RunSuite(new S2RulesSuite()); }
|
||||||
|
[Test] public void S3Rules() { RunSuite(new S3RulesSuite()); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,8 @@ namespace Luneraria.UI.Tests
|
||||||
StringAssert.Contains("davon 15 Söldner", texts, "the gold display shows the champion income");
|
StringAssert.Contains("davon 15 Söldner", texts, "the gold display shows the champion income");
|
||||||
StringAssert.Contains("SEGEN 2/4", texts, "the team header shows the Mondsegen");
|
StringAssert.Contains("SEGEN 2/4", texts, "the team header shows the Mondsegen");
|
||||||
Assert.IsTrue(HudSession.Visible(s.Hud.Lanes["mid"].Barracks), "mid shows the barracks mark");
|
Assert.IsTrue(HudSession.Visible(s.Hud.Lanes["mid"].Barracks), "mid shows the barracks mark");
|
||||||
Assert.IsFalse(HudSession.Visible(s.Hud.Lanes["top"].Barracks), "top shows none");
|
bool topBroken = s.Match.BarracksBroken(0, "top") || s.Match.BarracksBroken(1, "top");
|
||||||
|
Assert.AreEqual(topBroken, HudSession.Visible(s.Hud.Lanes["top"].Barracks), "top shows the mark exactly when an inner top tower fell");
|
||||||
Assert.IsTrue(s.Me.Hero.Exhausted, "the fallen hero is exhausted");
|
Assert.IsTrue(s.Me.Hero.Exhausted, "the fallen hero is exhausted");
|
||||||
s.Hud.OpenHero();
|
s.Hud.OpenHero();
|
||||||
yield return HudSession.Frames(2);
|
yield return HudSession.Frames(2);
|
||||||
|
|
|
||||||
113
Assets/Luneraria/Tests/UI/PlayMode/S3RulesViewsTests.cs
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
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>
|
||||||
|
/// S3 in the real scene: camp guardians on the lanes in a camp round, the team panel's ward
|
||||||
|
/// and camp rows, a ward that brings the enemy army of its lane into the planning preview,
|
||||||
|
/// and the fog of war that hides enemy figures nobody of the own team sees. S3Bilder
|
||||||
|
/// (explicit) captures them at 1920×1080; LUNE_EVIDENCE names the folder below
|
||||||
|
/// docs/port/screenshots (default s3/spiel).
|
||||||
|
/// </summary>
|
||||||
|
public sealed class S3RulesViewsTests
|
||||||
|
{
|
||||||
|
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 IEnumerator WaitReady(HudSession s)
|
||||||
|
{
|
||||||
|
float waited = 0f;
|
||||||
|
while (s.Hud.ReadyBlocked() && waited < 5f)
|
||||||
|
{
|
||||||
|
waited += Time.unscaledDeltaTime;
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LuneUnitView[] Views(HudSession s)
|
||||||
|
{
|
||||||
|
return UnityEngine.Object.FindObjectsByType<LuneUnitView>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnityTest, Timeout(600000)]
|
||||||
|
public IEnumerator S3Hud()
|
||||||
|
{
|
||||||
|
var s = new HudSession();
|
||||||
|
yield return s.Open(1920, 1080, seed: 4, startRound: 3, extraGold: 1000, extended: true);
|
||||||
|
Assert.IsTrue(s.Match.CampRound(3), "round 3 is a camp round");
|
||||||
|
StringAssert.Contains("diese Runde", s.Hud.Team.CampState.text, "the team panel announces the guardians");
|
||||||
|
Assert.IsTrue(HudSession.Visible(s.Hud.Lanes["mid"].CampMark), "the lane shows the camp mark");
|
||||||
|
yield return s.Starter();
|
||||||
|
s.Leave();
|
||||||
|
s.Game.Key(KeyCode.Space);
|
||||||
|
yield return HudSession.Frames(3);
|
||||||
|
Assert.AreEqual(3, s.Match.Combat.Units.Count(u => u.Kind == "camp"), "three guardians in combat");
|
||||||
|
yield return HudSession.Frames(2);
|
||||||
|
Assert.IsTrue(Views(s).Any(v => v.Unit != null && v.Unit.Kind == "camp" && v.gameObject.activeSelf), "guardians have visible figures");
|
||||||
|
Assert.IsTrue(s.Game.View.Hidden.Count > 0, "the fog hides Rot's distant units at the start");
|
||||||
|
LuneUnitView hiddenView = Views(s).First(v => v.Unit != null && s.Game.View.Hidden.Contains(v.Unit.Id));
|
||||||
|
Assert.IsFalse(hiddenView.gameObject.activeSelf, "a hidden enemy has no visible figure");
|
||||||
|
Assert.AreEqual(1, hiddenView.Unit.Team, "only enemies are hidden");
|
||||||
|
yield return s.FinishCombat();
|
||||||
|
yield return WaitReady(s);
|
||||||
|
Assert.IsTrue(s.Match.Players.Skip(3).Any(p => p.Roster.Count > 0), "Rot has a committed army now");
|
||||||
|
int enemiesBefore = s.Game.View.Preview.Units.Count(u => u.Team == 1);
|
||||||
|
Assert.AreEqual(0, enemiesBefore, "without scouting the preview shows no enemy");
|
||||||
|
Send(s, Command.Ward("mid"));
|
||||||
|
yield return HudSession.Frames(2);
|
||||||
|
Assert.IsTrue(s.Hud.Team.WardButtons["mid"].On, "the mid ward button shows the ward");
|
||||||
|
Assert.IsTrue(s.Game.View.Preview.Units.Any(u => u.Team == 1 && u.Lane == "mid"), "the ward shows Rot's mid army in the preview");
|
||||||
|
Assert.IsFalse(s.Game.View.Preview.Units.Any(u => u.Team == 1 && u.Lane == "top"), "top stays unscouted");
|
||||||
|
s.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnityTest, Timeout(600000), Explicit("Bildwerkzeug: nur gezielt per -testFilter")]
|
||||||
|
public IEnumerator S3Bilder()
|
||||||
|
{
|
||||||
|
string evidence = Environment.GetEnvironmentVariable("LUNE_EVIDENCE");
|
||||||
|
string folder = "docs/port/screenshots/" + (string.IsNullOrEmpty(evidence) ? "s3/spiel" : evidence) + "/";
|
||||||
|
var s = new HudSession();
|
||||||
|
yield return s.Open(1920, 1080, seed: 4, startRound: 3, extraGold: 1000, extended: true);
|
||||||
|
yield return s.Starter();
|
||||||
|
s.Leave();
|
||||||
|
yield return new WaitForSecondsRealtime(.4f);
|
||||||
|
yield return s.Shot(folder + "01-planung-lager-angekuendigt.png");
|
||||||
|
s.Game.Key(KeyCode.Space);
|
||||||
|
yield return HudSession.Frames(2);
|
||||||
|
yield return s.Fight(7.0);
|
||||||
|
s.Driver.Paused = true;
|
||||||
|
LuneUnit camp = s.Match.Combat.Units.Where(u => u.Kind == "camp" && u.Lane == "mid").First();
|
||||||
|
s.Rig.LookAt(camp.Position, 14f, true);
|
||||||
|
yield return new WaitForSecondsRealtime(.5f);
|
||||||
|
yield return s.Shot(folder + "02-kampf-um-das-mondlager.png");
|
||||||
|
s.Rig.LookAt(camp.Position, 40f, true);
|
||||||
|
yield return new WaitForSecondsRealtime(.5f);
|
||||||
|
yield return s.Shot(folder + "03-nebel-im-kampf.png");
|
||||||
|
s.Driver.Paused = false;
|
||||||
|
yield return s.FinishCombat();
|
||||||
|
yield return WaitReady(s);
|
||||||
|
Send(s, Command.Ward("mid"));
|
||||||
|
LuneUnit enemy = s.Game.View.Preview.Units.FirstOrDefault(u => u.Team == 1 && u.Lane == "mid");
|
||||||
|
if (enemy != null)
|
||||||
|
s.Rig.LookAt(enemy.Position, 18f, true);
|
||||||
|
yield return new WaitForSecondsRealtime(.6f);
|
||||||
|
yield return s.Shot(folder + "04-spaeher-zeigt-gegnerische-aufstellung.png");
|
||||||
|
s.Hover(s.Hud.Team.WardButtons["mid"]);
|
||||||
|
yield return new WaitForSecondsRealtime(.3f);
|
||||||
|
yield return s.Shot(folder + "05-spaeher-tooltip.png");
|
||||||
|
s.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b8e0bd7c590a42fcb9c90dfa0e1458fa
|
||||||
|
|
@ -430,6 +430,15 @@ namespace Luneraria.UI
|
||||||
}
|
}
|
||||||
unit.PreviousPosition = unit.Position;
|
unit.PreviousPosition = unit.Position;
|
||||||
}
|
}
|
||||||
|
// S3 (extended rules): scouted lanes show the enemy's committed army in its formation.
|
||||||
|
var enemyRows = new Dictionary<string, int>();
|
||||||
|
foreach (LuneMatch.ArmyEntry entry in LuneFog.ScoutedEnemies(Match, player.Team, player.Draft))
|
||||||
|
{
|
||||||
|
int index = enemyRows.GetValueOrDefault(entry.Lane, 0);
|
||||||
|
enemyRows[entry.Lane] = index + 1;
|
||||||
|
LuneUnit unit = preview.Spawn(entry.Kind, 1 - player.Team, entry.Lane, entry.Definition, Math.Max(.4, 7.2 - (index / 4) * 1.5), (index % 4 - 1.5) * 1.2, entry.Slot, entry.Uid);
|
||||||
|
unit.PreviousPosition = unit.Position;
|
||||||
|
}
|
||||||
View.Preview = preview;
|
View.Preview = preview;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -450,6 +459,10 @@ namespace Luneraria.UI
|
||||||
Bind();
|
Bind();
|
||||||
}
|
}
|
||||||
TrackStage();
|
TrackStage();
|
||||||
|
// S3 fog of war: only a human seat in an extended match sees through its team's eyes.
|
||||||
|
View.FogSlot = Human && Match.Extended ? Seat : -1;
|
||||||
|
if (Hud != null && Hud.Model != null)
|
||||||
|
Hud.Model.Hidden = View.Hidden;
|
||||||
UpdateDeployment();
|
UpdateDeployment();
|
||||||
HandleKeys();
|
HandleKeys();
|
||||||
HandleClicks();
|
HandleClicks();
|
||||||
|
|
|
||||||
|
|
@ -119,9 +119,13 @@ namespace Luneraria.UI
|
||||||
public event Action<Command> CommandRequested;
|
public event Action<Command> CommandRequested;
|
||||||
public readonly Dictionary<string, LuneButton> GlyphButtons = new Dictionary<string, LuneButton>();
|
public readonly Dictionary<string, LuneButton> GlyphButtons = new Dictionary<string, LuneButton>();
|
||||||
public LuneButton CoreButton;
|
public LuneButton CoreButton;
|
||||||
|
/// <summary>S3 wards per lane (fog of war).</summary>
|
||||||
|
public readonly Dictionary<string, LuneButton> WardButtons = new Dictionary<string, LuneButton>();
|
||||||
VisualElement _actions;
|
VisualElement _actions;
|
||||||
Label _glyphState;
|
Label _glyphState;
|
||||||
Label _coreState;
|
Label _coreState;
|
||||||
|
/// <summary>S3: running camp buffs of the own team and the next camp round.</summary>
|
||||||
|
public Label CampState;
|
||||||
string _actionSignature = "";
|
string _actionSignature = "";
|
||||||
readonly LuneGlyphElement _emblem;
|
readonly LuneGlyphElement _emblem;
|
||||||
string _signature = "";
|
string _signature = "";
|
||||||
|
|
@ -186,6 +190,32 @@ namespace Luneraria.UI
|
||||||
Text = "Jeder im Team kann Stufen kaufen (höchstens 3). Jede Stufe repariert den Ancient um 1.000 und lässt ihn auf Angreifer in 7,5 m schießen: 45 / 75 / 110 Schaden pro Sekunde.",
|
Text = "Jeder im Team kann Stufen kaufen (höchstens 3). Jede Stufe repariert den Ancient um 1.000 und lässt ihn auf Angreifer in 7,5 m schießen: 45 / 75 / 110 Schaden pro Sekunde.",
|
||||||
Note = "Preis: 150 × nächste Stufe.",
|
Note = "Preis: 150 × nächste Stufe.",
|
||||||
});
|
});
|
||||||
|
VisualElement wardRow = LuneUi.Box(false, 4f, _actions);
|
||||||
|
LuneUi.Glyph("star", LuneUiTheme.BronzeLight, 14f, wardRow);
|
||||||
|
LuneUi.Label("SPÄHER", "HudCaps", wardRow).style.minWidth = 64f;
|
||||||
|
foreach (string lane in LuneMap.Lanes)
|
||||||
|
{
|
||||||
|
var button = new LuneButton("", LuneButtons.HudToggle, wardRow);
|
||||||
|
string captured = lane;
|
||||||
|
button.Clicked += () => CommandRequested?.Invoke(Command.Ward(captured));
|
||||||
|
WardButtons[lane] = button;
|
||||||
|
}
|
||||||
|
LuneTooltip.Attach(wardRow, () => new LuneTip
|
||||||
|
{
|
||||||
|
Title = "Späher (wie die Wards in Dota 2)", Glyph = "star", GlyphColor = LuneUiTheme.BronzeLight,
|
||||||
|
Text = "Nebel des Krieges: Gegner siehst du nur nahe deiner Einheiten (9 m) und Gebäude (10 m). Ein Späher kostet 40 Gold, wacht 3 Runden über die Mitte seiner Lane (12 m) und zeigt in der Planung die gegnerische Aufstellung dort. Ist der äußere Turm des Gegners gefallen, ist die Lane auch ohne Späher aufgeklärt.",
|
||||||
|
Note = "Die Zahl auf dem Knopf: verbleibende Runden des Team-Spähers.",
|
||||||
|
});
|
||||||
|
VisualElement campRow = LuneUi.Box(false, 4f, _actions);
|
||||||
|
LuneUi.Glyph("emblem_2", LuneUiTheme.Team[2], 14f, campRow);
|
||||||
|
LuneUi.Label("LAGER", "HudCaps", campRow).style.minWidth = 64f;
|
||||||
|
CampState = LuneUi.Clip(LuneUi.Label("", "HudText", campRow));
|
||||||
|
CampState.style.flexGrow = 1f;
|
||||||
|
LuneTooltip.Attach(campRow, () => new LuneTip
|
||||||
|
{
|
||||||
|
Title = "Neutrallager (wie die Buff-Camps in League of Legends)", Glyph = "emblem_2", GlyphColor = LuneUiTheme.Team[2],
|
||||||
|
Text = "Jede dritte Runde steht in der Mitte jeder Lane ein neutraler Wächter, der beide Teams angreift. Fällt er, nimmt das Team mit mehr Einheiten in 8 m das Lager (bei Gleichstand: mehr Leben).\nTop · Glutsegen: +10 % Schaden, 2 Kämpfe.\nMid · Mondschild: Schild von 10 % Leben zu Kampfbeginn, 2 Kämpfe.\nBot · Beute: sofort 50 Gold für jeden im Team.",
|
||||||
|
});
|
||||||
LuneUi.Show(_actions, false);
|
LuneUi.Show(_actions, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,7 +230,8 @@ namespace Luneraria.UI
|
||||||
int level = state.Boss.CoreLevel[team];
|
int level = state.Boss.CoreLevel[team];
|
||||||
int pending = model.Planning ? draft.CoreInvest : 0;
|
int pending = model.Planning ? draft.CoreInvest : 0;
|
||||||
string held = model.Planning ? draft.GlyphLane : "";
|
string held = model.Planning ? draft.GlyphLane : "";
|
||||||
string signature = on + "|" + model.Planning + "|" + model.Locked + "|" + ready + "|" + state.RoundNumber + "|" + level + "|" + pending + "|" + held + "|" + model.OwnGold;
|
int[] buffs = state.Boss.CampBuff;
|
||||||
|
string signature = string.Join(",", buffs) + "|" + string.Join(",", state.Boss.Wards) + "|" + string.Join(",", draft.WardLanes) + "|" + on + "|" + model.Planning + "|" + model.Locked + "|" + ready + "|" + state.RoundNumber + "|" + level + "|" + pending + "|" + held + "|" + model.OwnGold;
|
||||||
if (signature == _actionSignature)
|
if (signature == _actionSignature)
|
||||||
return;
|
return;
|
||||||
_actionSignature = signature;
|
_actionSignature = signature;
|
||||||
|
|
@ -221,6 +252,27 @@ namespace Luneraria.UI
|
||||||
int cost = max ? 0 : state.Balance.CoreUpgradeCost(shown);
|
int cost = max ? 0 : state.Balance.CoreUpgradeCost(shown);
|
||||||
CoreButton.Text = max ? "MAX" : "+" + cost + " G";
|
CoreButton.Text = max ? "MAX" : "+" + cost + " G";
|
||||||
CoreButton.Disabled = !canAct || max || model.OwnGold < cost;
|
CoreButton.Disabled = !canAct || max || model.OwnGold < cost;
|
||||||
|
foreach (KeyValuePair<string, LuneButton> pair in WardButtons)
|
||||||
|
{
|
||||||
|
int left = state.Boss.Wards[team * 3 + LuneMap.LaneIndex(pair.Key)];
|
||||||
|
bool placed = model.Planning && draft.WardLanes.Contains(pair.Key);
|
||||||
|
string name = pair.Key == "bot" ? "BOT" : LuneUi.Upper(LuneMap.LaneNames[pair.Key]);
|
||||||
|
pair.Value.Text = placed ? name + " +" + state.Balance.WardRounds : left > 0 ? name + " " + left : name;
|
||||||
|
pair.Value.On = placed || left > 0;
|
||||||
|
pair.Value.Disabled = !canAct || placed || model.OwnGold < state.Balance.WardCost;
|
||||||
|
}
|
||||||
|
var parts = new List<string>();
|
||||||
|
for (int lane = 0; lane < 2; lane++)
|
||||||
|
{
|
||||||
|
int left = buffs[team * 3 + lane];
|
||||||
|
if (left > 0)
|
||||||
|
parts.Add(LuneMatch.CampBuffNames[lane] + " " + left);
|
||||||
|
}
|
||||||
|
int next = state.RoundNumber;
|
||||||
|
while (!state.CampRound(next) && next < state.RoundNumber + 10)
|
||||||
|
next++;
|
||||||
|
string upcoming = next == state.RoundNumber ? "Wächter diese Runde" : "Wächter in Runde " + next;
|
||||||
|
CampState.text = parts.Count > 0 ? string.Join(" · ", parts) + " · " + upcoming : upcoming;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>S1: Mondsegen stacks of the own team (-1 under the reference rules).</summary>
|
/// <summary>S1: Mondsegen stacks of the own team (-1 under the reference rules).</summary>
|
||||||
|
|
|
||||||
|
|
@ -755,6 +755,7 @@ namespace Luneraria.UI
|
||||||
if (fighting && _mapTick >= MapRate)
|
if (fighting && _mapTick >= MapRate)
|
||||||
{
|
{
|
||||||
_mapTick = 0f;
|
_mapTick = 0f;
|
||||||
|
Minimap.Hidden = Model.Hidden;
|
||||||
Minimap.Refresh(Match.Announcements());
|
Minimap.Refresh(Match.Announcements());
|
||||||
}
|
}
|
||||||
if (_feedTick >= FeedRate)
|
if (_feedTick >= FeedRate)
|
||||||
|
|
@ -811,6 +812,7 @@ namespace Luneraria.UI
|
||||||
{
|
{
|
||||||
Minimap.ViewerTeam = Model.Team;
|
Minimap.ViewerTeam = Model.Team;
|
||||||
Minimap.HumanSlot = HumanSlot;
|
Minimap.HumanSlot = HumanSlot;
|
||||||
|
Minimap.Hidden = Model.Hidden;
|
||||||
Minimap.Refresh(Match.Announcements());
|
Minimap.Refresh(Match.Announcements());
|
||||||
}
|
}
|
||||||
if (_modal.Open)
|
if (_modal.Open)
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@ namespace Luneraria.UI
|
||||||
readonly LuneGlyphElement _enemyShape;
|
readonly LuneGlyphElement _enemyShape;
|
||||||
/// <summary>S1 barracks: crossed swords in the own team colour (own waves reinforced) or red (enemy waves).</summary>
|
/// <summary>S1 barracks: crossed swords in the own team colour (own waves reinforced) or red (enemy waves).</summary>
|
||||||
public readonly LuneGlyphElement Barracks;
|
public readonly LuneGlyphElement Barracks;
|
||||||
|
/// <summary>S3: neutral hexagon while a camp guardian stands on the lane this round.</summary>
|
||||||
|
public readonly LuneGlyphElement CampMark;
|
||||||
float _lowerHold;
|
float _lowerHold;
|
||||||
float _pulse;
|
float _pulse;
|
||||||
string _signature = "";
|
string _signature = "";
|
||||||
|
|
@ -61,6 +63,8 @@ namespace Luneraria.UI
|
||||||
LuneUi.Spacer(head);
|
LuneUi.Spacer(head);
|
||||||
Barracks = LuneUi.Glyph("melee", LuneUiTheme.Muted, 14f, head);
|
Barracks = LuneUi.Glyph("melee", LuneUiTheme.Muted, 14f, head);
|
||||||
LuneUi.Show(Barracks, false);
|
LuneUi.Show(Barracks, false);
|
||||||
|
CampMark = LuneUi.Glyph("emblem_2", LuneUiTheme.Team[2], 14f, head);
|
||||||
|
LuneUi.Show(CampMark, false);
|
||||||
_badge = new LuneStatusBadge();
|
_badge = new LuneStatusBadge();
|
||||||
head.Add(_badge);
|
head.Add(_badge);
|
||||||
VisualElement chain = LuneUi.Box(false, 3f, column);
|
VisualElement chain = LuneUi.Box(false, 3f, column);
|
||||||
|
|
@ -126,6 +130,7 @@ namespace Luneraria.UI
|
||||||
Color tint = LuneUiTheme.Threat[Level];
|
Color tint = LuneUiTheme.Threat[Level];
|
||||||
_badge.SetState(LuneLaneThreat.Names[Level], tint, Level >= 2 ? LuneLaneThreat.Glyphs[Level] : "", Level == LuneLaneThreat.Critical);
|
_badge.SetState(LuneLaneThreat.Names[Level], tint, Level >= 2 ? LuneLaneThreat.Glyphs[Level] : "", Level == LuneLaneThreat.Critical);
|
||||||
LuneUi.Show(Barracks, entry.OwnBarracks || entry.EnemyBarracks);
|
LuneUi.Show(Barracks, entry.OwnBarracks || entry.EnemyBarracks);
|
||||||
|
LuneUi.Show(CampMark, entry.Camp.Length > 0);
|
||||||
Barracks.Color = entry.EnemyBarracks ? LuneUiTheme.Danger : LuneUiTheme.TeamColor(ownTeam);
|
Barracks.Color = entry.EnemyBarracks ? LuneUiTheme.Danger : LuneUiTheme.TeamColor(ownTeam);
|
||||||
_ownShape.Glyph = "emblem_" + ownTeam;
|
_ownShape.Glyph = "emblem_" + ownTeam;
|
||||||
_ownShape.Color = LuneUiTheme.TeamColor(ownTeam);
|
_ownShape.Color = LuneUiTheme.TeamColor(ownTeam);
|
||||||
|
|
@ -201,6 +206,9 @@ namespace Luneraria.UI
|
||||||
tip.Stat("melee", "Kaserne", "gegnerischer innerer Turm gefallen: eure Wellen +25 % und ein Monster mehr");
|
tip.Stat("melee", "Kaserne", "gegnerischer innerer Turm gefallen: eure Wellen +25 % und ein Monster mehr");
|
||||||
if (Data.EnemyBarracks)
|
if (Data.EnemyBarracks)
|
||||||
tip.Stat("warning", "Kaserne", "euer innerer Turm ist gefallen: gegnerische Wellen +25 % und ein Monster mehr");
|
tip.Stat("warning", "Kaserne", "euer innerer Turm ist gefallen: gegnerische Wellen +25 % und ein Monster mehr");
|
||||||
|
// S3 camps (League of Legends): a guardian in the middle of the lane this round.
|
||||||
|
if (Data.Camp.Length > 0)
|
||||||
|
tip.Stat("emblem_2", "Lager", Data.Camp);
|
||||||
var notes = new List<string>();
|
var notes = new List<string>();
|
||||||
foreach (Announcement danger in Data.Dangers)
|
foreach (Announcement danger in Data.Dangers)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@ namespace Luneraria.UI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class LuneMinimap : VisualElement
|
public sealed class LuneMinimap : VisualElement
|
||||||
{
|
{
|
||||||
|
/// <summary>S3 fog of war: enemy units hidden from the viewer (set by the HUD).</summary>
|
||||||
|
public HashSet<int> Hidden;
|
||||||
|
|
||||||
public const float Cell = 6f;
|
public const float Cell = 6f;
|
||||||
/// <summary>Radius of the grotto arena (lune_terrain.gd ARENA_RADIUS).</summary>
|
/// <summary>Radius of the grotto arena (lune_terrain.gd ARENA_RADIUS).</summary>
|
||||||
public const float ArenaRadius = 7.8f;
|
public const float ArenaRadius = 7.8f;
|
||||||
|
|
@ -154,6 +157,9 @@ namespace Luneraria.UI
|
||||||
{
|
{
|
||||||
if (!unit.Alive || !unit.IsMobile())
|
if (!unit.Alive || !unit.IsMobile())
|
||||||
continue;
|
continue;
|
||||||
|
// S3 fog of war: enemies nobody of the team sees are not drawn.
|
||||||
|
if (Hidden != null && Hidden.Contains(unit.Id))
|
||||||
|
continue;
|
||||||
Units++;
|
Units++;
|
||||||
if (unit.Kind == "hero" || unit.Kind == "champion" || unit.Kind == "boss")
|
if (unit.Kind == "hero" || unit.Kind == "champion" || unit.Kind == "boss")
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ namespace Luneraria.UI
|
||||||
public int Income { get { return State.Balance.RoundIncome(State.RoundNumber) + IncomeBonus; } }
|
public int Income { get { return State.Balance.RoundIncome(State.RoundNumber) + IncomeBonus; } }
|
||||||
/// <summary>S1: the own permanent champion income (Legion TD 2), 0 under the reference rules.</summary>
|
/// <summary>S1: the own permanent champion income (Legion TD 2), 0 under the reference rules.</summary>
|
||||||
public int IncomeBonus { get { return State.Extended ? Me.IncomeBonus : 0; } }
|
public int IncomeBonus { get { return State.Extended ? Me.IncomeBonus : 0; } }
|
||||||
|
/// <summary>S3 fog of war: ids of enemy units the viewer's team cannot see (filled by the game each frame).</summary>
|
||||||
|
public HashSet<int> Hidden = new HashSet<int>();
|
||||||
/// <summary>After Ready the plan is binding (the host refuses later commands).</summary>
|
/// <summary>After Ready the plan is binding (the host refuses later commands).</summary>
|
||||||
public bool Locked { get { return Planning && Me.Ready; } }
|
public bool Locked { get { return Planning && Me.Ready; } }
|
||||||
public List<RosterEntry> OwnRoster { get { return Planning ? Me.Draft.Roster : Me.Roster; } }
|
public List<RosterEntry> OwnRoster { get { return Planning ? Me.Draft.Roster : Me.Roster; } }
|
||||||
|
|
@ -306,6 +308,29 @@ namespace Luneraria.UI
|
||||||
/// <summary>S1 barracks: own waves reinforced here (enemy inner tower fell) / enemy waves reinforced.</summary>
|
/// <summary>S1 barracks: own waves reinforced here (enemy inner tower fell) / enemy waves reinforced.</summary>
|
||||||
public bool OwnBarracks;
|
public bool OwnBarracks;
|
||||||
public bool EnemyBarracks;
|
public bool EnemyBarracks;
|
||||||
|
/// <summary>S3: text of the camp on this lane this round, "" without one.</summary>
|
||||||
|
public string Camp = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>S3: the camp guardian of a lane in a camp round (alive in combat, expected in planning).</summary>
|
||||||
|
string CampText(string lane)
|
||||||
|
{
|
||||||
|
if (!State.CampRound(State.RoundNumber))
|
||||||
|
return "";
|
||||||
|
int index = LuneMap.LaneIndex(lane);
|
||||||
|
string reward = index == 0 ? "Glutsegen (+10 % Schaden, 2 Kämpfe)" : index == 1 ? "Mondschild (Schild 10 % Leben, 2 Kämpfe)" : "Beute (50 Gold je Spieler)";
|
||||||
|
if (Fighting)
|
||||||
|
{
|
||||||
|
bool alive = false;
|
||||||
|
foreach (LuneUnit unit in State.Combat.Units)
|
||||||
|
{
|
||||||
|
if (unit.Kind == "camp" && unit.Lane == lane && unit.Alive)
|
||||||
|
alive = true;
|
||||||
|
}
|
||||||
|
if (!alive)
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return LuneMatch.CampNames[index] + " in der Lanemitte · Sieg: " + reward;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LaneInfo Lane(string lane)
|
public LaneInfo Lane(string lane)
|
||||||
|
|
@ -318,8 +343,9 @@ namespace Luneraria.UI
|
||||||
{
|
{
|
||||||
Lane = lane, Title = LuneMap.LaneNames[lane].ToUpperInvariant(), OwnPlayer = PlayerName(ownSeat), EnemyPlayer = PlayerName(enemySeat), OwnIsMe = ownSeat == Slot,
|
Lane = lane, Title = LuneMap.LaneNames[lane].ToUpperInvariant(), OwnPlayer = PlayerName(ownSeat), EnemyPlayer = PlayerName(enemySeat), OwnIsMe = ownSeat == Slot,
|
||||||
Towers = new[] { Building(own + "_" + lane + "_inner"), Building(own + "_" + lane + "_outer"), Building(enemy + "_" + lane + "_outer"), Building(enemy + "_" + lane + "_inner") },
|
Towers = new[] { Building(own + "_" + lane + "_inner"), Building(own + "_" + lane + "_outer"), Building(enemy + "_" + lane + "_outer"), Building(enemy + "_" + lane + "_inner") },
|
||||||
Threat = LuneLaneThreat.Evaluate(State, Team, lane), OwnHero = HeroOf(ownSeat), EnemyHero = HeroOf(enemySeat),
|
Threat = LuneLaneThreat.Evaluate(State, Team, lane, Hidden), OwnHero = HeroOf(ownSeat), EnemyHero = HeroOf(enemySeat),
|
||||||
OwnBarracks = State.Extended && State.BarracksBroken(Team, lane), EnemyBarracks = State.Extended && State.BarracksBroken(Enemy, lane),
|
OwnBarracks = State.Extended && State.BarracksBroken(Team, lane), EnemyBarracks = State.Extended && State.BarracksBroken(Enemy, lane),
|
||||||
|
Camp = CampText(lane),
|
||||||
};
|
};
|
||||||
foreach (Announcement entry in State.Announcements())
|
foreach (Announcement entry in State.Announcements())
|
||||||
{
|
{
|
||||||
|
|
@ -328,7 +354,7 @@ namespace Luneraria.UI
|
||||||
}
|
}
|
||||||
if (Fighting)
|
if (Fighting)
|
||||||
{
|
{
|
||||||
LuneLaneThreat.Battle battle = LuneLaneThreat.Battlefield(State, Team, lane);
|
LuneLaneThreat.Battle battle = LuneLaneThreat.Battlefield(State, Team, lane, Hidden);
|
||||||
result.HasCounts = true;
|
result.HasCounts = true;
|
||||||
result.OwnCount = battle.OwnCount;
|
result.OwnCount = battle.OwnCount;
|
||||||
result.EnemyCount = battle.EnemyCount;
|
result.EnemyCount = battle.EnemyCount;
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ namespace Luneraria.UI
|
||||||
return LuneUiTheme.Round(value * 100.0) + " %";
|
return LuneUiTheme.Round(value * 100.0) + " %";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result Evaluate(LuneMatch state, int team, string lane)
|
public static Result Evaluate(LuneMatch state, int team, string lane, ICollection<int> hidden = null)
|
||||||
{
|
{
|
||||||
var result = new Result();
|
var result = new Result();
|
||||||
int level = Calm;
|
int level = Calm;
|
||||||
|
|
@ -122,7 +122,7 @@ namespace Luneraria.UI
|
||||||
}
|
}
|
||||||
if (state.Phase == Phase.Combat && state.Combat != null)
|
if (state.Phase == Phase.Combat && state.Combat != null)
|
||||||
{
|
{
|
||||||
Battle battle = Battlefield(state, team, lane);
|
Battle battle = Battlefield(state, team, lane, hidden);
|
||||||
double length = battle.Length;
|
double length = battle.Length;
|
||||||
if (battle.EnemyCount > 0)
|
if (battle.EnemyCount > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -161,7 +161,8 @@ namespace Luneraria.UI
|
||||||
/// Units of both sides on one lane: counts, HP sums and the deepest enemy position measured
|
/// Units of both sides on one lane: counts, HP sums and the deepest enemy position measured
|
||||||
/// from the own base along the lane (from positions only).
|
/// from the own base along the lane (from positions only).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Battle Battlefield(LuneMatch state, int team, string lane)
|
/// <summary>Units on the lane in combat; S3: enemies in the fog (hidden) are not counted.</summary>
|
||||||
|
public static Battle Battlefield(LuneMatch state, int team, string lane, ICollection<int> hidden = null)
|
||||||
{
|
{
|
||||||
LanePath path = state.Map.LanePaths[lane];
|
LanePath path = state.Map.LanePaths[lane];
|
||||||
var result = new Battle { Length = path.Length };
|
var result = new Battle { Length = path.Length };
|
||||||
|
|
@ -171,6 +172,8 @@ namespace Luneraria.UI
|
||||||
{
|
{
|
||||||
if (!unit.Alive || !unit.IsMobile() || unit.Zone != "lane" || unit.Lane != lane || unit.Team > 1)
|
if (!unit.Alive || !unit.IsMobile() || unit.Zone != "lane" || unit.Lane != lane || unit.Team > 1)
|
||||||
continue;
|
continue;
|
||||||
|
if (hidden != null && hidden.Contains(unit.Id))
|
||||||
|
continue;
|
||||||
double s = path.Project(unit.Position);
|
double s = path.Project(unit.Position);
|
||||||
double fromOwnBase = team == 0 ? s : path.Length - s;
|
double fromOwnBase = team == 0 ? s : path.Length - s;
|
||||||
if (unit.Team == team)
|
if (unit.Team == team)
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,11 @@ namespace Luneraria.View
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<LuneUnitView> Units { get { return _units.Values; } }
|
public IEnumerable<LuneUnitView> Units { get { return _units.Values; } }
|
||||||
|
/// <summary>S3 fog of war: the seat whose team's vision applies (-1 = everything visible).</summary>
|
||||||
|
public int FogSlot = -1;
|
||||||
|
/// <summary>Ids of the units hidden in the fog this frame.</summary>
|
||||||
|
public HashSet<int> Hidden { get; private set; } = new HashSet<int>();
|
||||||
|
static readonly HashSet<int> Empty = new HashSet<int>();
|
||||||
/// <summary>Main-thread cost of the last frame's view update (milliseconds).</summary>
|
/// <summary>Main-thread cost of the last frame's view update (milliseconds).</summary>
|
||||||
public double LastSyncMs { get; private set; }
|
public double LastSyncMs { get; private set; }
|
||||||
readonly System.Diagnostics.Stopwatch _clock = new System.Diagnostics.Stopwatch();
|
readonly System.Diagnostics.Stopwatch _clock = new System.Diagnostics.Stopwatch();
|
||||||
|
|
@ -108,6 +113,10 @@ namespace Luneraria.View
|
||||||
_combat = shown;
|
_combat = shown;
|
||||||
}
|
}
|
||||||
bool showUnits = _combat != null && (!planning || _combat == Preview);
|
bool showUnits = _combat != null && (!planning || _combat == Preview);
|
||||||
|
// S3 fog of war (extended rules): enemies the viewer's team cannot see are hidden.
|
||||||
|
Hidden = FogSlot >= 0 && FogSlot < match.Players.Count && showUnits
|
||||||
|
? LuneFog.Hidden(match, _combat, match.Players[FogSlot].Team, planning, planning ? match.Players[FogSlot].Draft : null)
|
||||||
|
: Empty;
|
||||||
float alpha = Driver.Runner.Current == LuneMatchRunner.Stage.Combat ? (float)Driver.Runner.Clock.Alpha : 1f;
|
float alpha = Driver.Runner.Current == LuneMatchRunner.Stage.Combat ? (float)Driver.Runner.Clock.Alpha : 1f;
|
||||||
if (showUnits)
|
if (showUnits)
|
||||||
{
|
{
|
||||||
|
|
@ -122,6 +131,9 @@ namespace Luneraria.View
|
||||||
view.Bind(unit, Library);
|
view.Bind(unit, Library);
|
||||||
_units[unit.Id] = view;
|
_units[unit.Id] = view;
|
||||||
}
|
}
|
||||||
|
bool visible = !Hidden.Contains(unit.Id);
|
||||||
|
if (view.gameObject.activeSelf != visible)
|
||||||
|
view.gameObject.SetActive(visible);
|
||||||
view.Sync(alpha, dt, ViewCamera != null ? ViewCamera.transform : null);
|
view.Sync(alpha, dt, ViewCamera != null ? ViewCamera.transform : null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,9 @@ Legende:
|
||||||
| Glyphe | umgesetzt in S2 |
|
| Glyphe | umgesetzt in S2 |
|
||||||
| Item-Rezepte | umgesetzt in S2 |
|
| Item-Rezepte | umgesetzt in S2 |
|
||||||
| Ancient stärken (Legion TD 2) | umgesetzt in S2 (neu, nicht in der ursprünglichen Liste) |
|
| Ancient stärken (Legion TD 2) | umgesetzt in S2 (neu, nicht in der ursprünglichen Liste) |
|
||||||
| Fog of War, Neutrallager, Schreine | offen (S3) |
|
| Fog of War mit Spähern | umgesetzt in S3 (Darstellung, Planungsaufklärung; ohne Gelände-Shader) |
|
||||||
|
| Neutrallager | umgesetzt in S3 (Lanemitte, Glutsegen, Mondschild, Beute) |
|
||||||
|
| Schreine | durch die Lager abgedeckt; eigene Schreine offen |
|
||||||
|
|
||||||
## Empfohlene Reihenfolge
|
## Empfohlene Reihenfolge
|
||||||
|
|
||||||
|
|
|
||||||
110
docs/luneraria/S3-STRATEGIE.md
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
# S3 · Frühere Bot-Helden, Neutrallager, Fog of War
|
||||||
|
|
||||||
|
Stand: 11. Oktober 2026 · Branch `luneraria/s3-strategie` (von `luneraria/s2-strategie`).
|
||||||
|
Auftrag: „1–3 umsetzen“:
|
||||||
|
1. Fog of War mit Spähern
|
||||||
|
2. Neutrallager und Schreine
|
||||||
|
3. Bots kaufen Helden früher
|
||||||
|
|
||||||
|
Alles wirkt nur mit erweiterten Regeln (`MatchOptions.Extended`). Die Referenzregeln, Golden-Replays und Fingerabdrücke bleiben unverändert.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## A · Bots (Commit `e756a90`)
|
||||||
|
|
||||||
|
| Befund | Behebung |
|
||||||
|
| --- | --- |
|
||||||
|
| Bots werben ihre Helden erst um Runde 11 bis 12 an: Sie geben jede Runde fast alles für Truppen aus und sammeln die 260 Gold nie an | Mit erweiterten Regeln sparen Bots ab ihrer Heldenrunde (sobald 3 Truppen stehen), bis der Held gekauft ist. Helden kommen jetzt in Runde 4 bis 6 |
|
||||||
|
| **Fehler aus S1:** Mit sieben Profilen ergibt `(Platz × 7 + Seed) % 7` für alle sechs Plätze dasselbe Profil. Die Sylvara-Quote von 50 % in S1 war deshalb ein Artefakt | Rotation mit Schritt 5: sechs verschiedene Profile je Partie. Die Referenz mit sechs Profilen nutzt unverändert Schritt 7 |
|
||||||
|
| Profile mit Angriffschampions verlieren in kurzen Partien: Das Kopfgeld des Champions (70 + 6 × Runde) ist ein Geschenk an den Verteidiger | Verteidiger bekommen mit erweiterten Regeln das halbe Kopfgeld (wie in Legion TD 2: weniger, als der Söldner kostet). Das Assassinen-Profil bucht keinen Champion |
|
||||||
|
|
||||||
|
Das Balance-Werkzeug spielt jeden Seed jetzt zweimal, beim zweiten Mal mit vertauschten Teamprofilen. Damit zählt eine starke Profilkombination für beide Seiten, und nur ein echter Seitenvorteil bliebe übrig.
|
||||||
|
|
||||||
|
## B · Neutrallager (League of Legends)
|
||||||
|
|
||||||
|
In jeder dritten Runde (3, 6, 9 …) steht in der Mitte jeder Lane ein neutraler Wächter (Modell: Bruchhirsch). Er bewegt sich nicht, greift beide Teams in 2,5 m an und wächst mit den Wellen.
|
||||||
|
|
||||||
|
- **Wer gewinnt:** Fällt der Wächter, nimmt das Team mit mehr lebenden Einheiten in 8 m das Lager. Bei gleicher Zahl entscheidet die Summe der Lebenspunkte. Nur exakt gespiegelte Lagen bleiben ohne Sieger. Es gibt kein Last-Hitting; Einheiten, die im selben Schritt fallen, zählen nicht.
|
||||||
|
- **Kampfende:** Ein allein übriger Wächter hält den Kampf nicht offen.
|
||||||
|
|
||||||
|
| Lane | Lager | Belohnung |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Top | Glutwächter | **Glutsegen:** +10 % Schaden für Truppen und Helden des Teams, 2 Kämpfe (wie Red Buff) |
|
||||||
|
| Mid | Mondwächter | **Mondschild:** Schild von 10 % Leben zu Kampfbeginn, 2 Kämpfe (wie Blue Buff/Baron) |
|
||||||
|
| Bot | Goldwächter | **Beute:** sofort 50 Gold für jeden im Team |
|
||||||
|
|
||||||
|
**HUD:**
|
||||||
|
- Teampanel-Zeile **LAGER** mit laufenden Buffs und „Wächter diese Runde / in Runde N“.
|
||||||
|
- Ein Sechseck an jeder Lane, die in dieser Runde einen Wächter hat; der Lane-Tooltip nennt die Belohnung.
|
||||||
|
|
||||||
|
**Messung** (40 Bot-Partien):
|
||||||
|
- 330 Wächter, alle gefallen, im Schnitt nach 17,5 s.
|
||||||
|
- Blau holt 157, Rot 173, kein Gleichstand (vor dem Lebenspunkte-Entscheid waren es 96 Gleichstände).
|
||||||
|
|
||||||
|
## C · Fog of War mit Spähern (Dota 2)
|
||||||
|
|
||||||
|
Der Nebel ist reine Darstellung und Information für den Menschen am eigenen Sitz. Die Simulation liest ihn nie (`LuneFog` im Kern, vom Spiel abgefragt).
|
||||||
|
|
||||||
|
**Im Kampf:**
|
||||||
|
- Gegnerische Figuren sind nur sichtbar in 9 m um eigene Einheiten, in 10 m um eigene Gebäude und in 12 m um die Lanemitte eines eigenen Spähers.
|
||||||
|
- Unsichtbare Gegner verschwinden aus dem 3D-Feld, von der Minimap, aus den Namensschildern und aus der Einheitenzählung der Lane-Anzeige.
|
||||||
|
- Neutrale Einheiten (Wächter, Grottenboss) bleiben immer sichtbar.
|
||||||
|
|
||||||
|
**In der Planung:**
|
||||||
|
- Bisher zeigte die Vorschau nur die eigene Armee.
|
||||||
|
- Jetzt zeigt sie auf **aufgeklärten** Lanes zusätzlich die festgelegte gegnerische Armee (Truppen und Held) in ihrer Aufstellung.
|
||||||
|
- Aufgeklärt ist eine Lane mit einem Späher des Teams, mit einem eigenen Späher dieser Planung oder wenn der äußere Turm des Gegners dort gefallen ist.
|
||||||
|
|
||||||
|
**Späher:**
|
||||||
|
- 40 Gold, wacht 3 Runden über seine Lane und gilt für das ganze Team (Befehl `ward`).
|
||||||
|
- Teampanel-Zeile **SPÄHER**: TOP, MID, BOT; die Zahl zeigt die Restrunden.
|
||||||
|
|
||||||
|
**Bots** nutzen den Nebel nicht. Sie lesen ohnehin nur öffentliche Informationen.
|
||||||
|
|
||||||
|
**Bekannte Grenzen:**
|
||||||
|
- Der Nebel ist im Gelände nicht als Abdunklung sichtbar, nur durch fehlende Gegner. Dafür braucht es einen eigenen Nebel-Shader.
|
||||||
|
- Im Netzwerkspiel erhalten Gäste alle Einheiten im Kampfrahmen. Der Nebel ist Darstellung, keine Netz-Geheimhaltung.
|
||||||
|
|
||||||
|
## Balance (gespiegelte Bot-Partien)
|
||||||
|
|
||||||
|
Rohdaten: `docs/port/logs/s3/balance-s3a-bots.txt` (nach Teil A) und `balance-s3.txt` (mit Lagern).
|
||||||
|
|
||||||
|
| | Referenz | S3 nur Bots | S3 mit Lagern |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| Partien | 120 | 120 | 120 |
|
||||||
|
| Blau / Rot | 60 / 60 | 59 / 61 | 57 / 63 |
|
||||||
|
| Ø Runden | 10,3 | 10,1 | 9,0 |
|
||||||
|
| Wer den ersten Turm nimmt, gewinnt | 100 | 104 | **53** |
|
||||||
|
| Sylvara (Plätze / Siege) | – | 102 / 42 | 102 / 48 |
|
||||||
|
| Rezept-Items bei Bots | – | 0 | 4 |
|
||||||
|
| Mondsegen-Stapel | – | 60 | 67 |
|
||||||
|
|
||||||
|
Bewertung:
|
||||||
|
- Mit den Lagern sagt der erste Turm kaum noch etwas über den Sieger aus (53 von 120). Umkämpfte Buffs führen zu Wenden wie die Objectives in LoL.
|
||||||
|
- Die Partien werden etwas kürzer, weil die Buffs Druck aufbauen. Das sollten wir mit echten Spielern beobachten.
|
||||||
|
- Beide Seiten bleiben ausgeglichen.
|
||||||
|
|
||||||
|
## Tests und Nachweise
|
||||||
|
|
||||||
|
| Prüfung | Ergebnis |
|
||||||
|
| --- | --- |
|
||||||
|
| Kern (.NET 8) | 597/597, darunter **s3 31** (Referenz ohne Späher, Lager und Nebel; sechs verschiedene Profile; frühe Bot-Helden, Referenz-Bots weiterhin spät; halbes Champion-Kopfgeld; Lager: Runden, drei Wächter, kein Schritt, Teamwahl, Glutsegen, Mondschild, Beute, Kampfende; Späher: Preis, eine pro Lane, Teamwirkung, Countdown, Aufklärung durch gefallenen Turm; Nebel: Start, Sicht 9 m, Späherpunkt, Planungsvorschau nur auf aufgeklärten Lanes) |
|
||||||
|
| Golden und Fingerabdrücke | 0 Abweichungen; `DCE95C96556F3A1A` bei 30/60/120 fps und unbegrenzt unverändert |
|
||||||
|
| Unity EditMode | 33/33 |
|
||||||
|
| Unity PlayMode | 18/18 (neu `S3RulesViewsTests.S3Hud`: Lager-Ankündigung, Sechseck, Wächter-Figuren, versteckte Gegnerfiguren, Späher bringt die Mid-Armee in die Vorschau, Top bleibt verborgen); Verify A–I 718/0; der S1-Test prüft das Kasernen-Symbol jetzt am Spielzustand (die stärkeren Bots brechen Top früher) |
|
||||||
|
| Player-Selbsttest | macOS 30/30 |
|
||||||
|
| Leistung | sechs Sylvaras, Seed 9 ab Welle 2: Karte 144,4–150,0 fps, Mid nah 167,4–172,2 fps, HUD 0,04–0,06 ms. Im Rahmen von S2; die Nebelberechnung kostet nicht messbar mehr |
|
||||||
|
|
||||||
|
**Bilder** in `docs/port/screenshots/s3/spiel/`:
|
||||||
|
1. Planung mit angekündigten Lagern
|
||||||
|
2. Kampf um das Mondlager
|
||||||
|
3. Nebel im Kampf (Übersicht)
|
||||||
|
4. Späher zeigt die gegnerische Aufstellung
|
||||||
|
5. Späher-Tooltip
|
||||||
|
|
||||||
|
## Offene Punkte
|
||||||
|
|
||||||
|
- **Nebel-Abdunklung im Gelände:** braucht einen eigenen Shader; die Minimap könnte Sichtkreise zeigen.
|
||||||
|
- **Nebel als Netz-Geheimhaltung:** Gäste erhalten derzeit alle Einheiten.
|
||||||
|
- **Bots setzen keine Späher:** Sie brauchen keine Sicht.
|
||||||
|
- **Kürzere Partien mit Lagern** (9,0 Runden): mit echten Spielern beobachten, eventuell Lager erst ab Runde 6.
|
||||||
|
|
@ -300,6 +300,18 @@ Die Glutpakt-Arbeit entstand als Kette aufeinander aufbauender Zweige (`lunerari
|
||||||
| Bild | `screenshots/s2/spiel/` |
|
| Bild | `screenshots/s2/spiel/` |
|
||||||
| Commits | `luneraria/s2-strategie` |
|
| Commits | `luneraria/s2-strategie` |
|
||||||
|
|
||||||
|
## S3 · Bots, Neutrallager, Fog of War
|
||||||
|
|
||||||
|
| Punkt | Ergebnis |
|
||||||
|
| --- | --- |
|
||||||
|
| Tests | Kern .NET 597/597 (neu `s3` 31), EditMode 33/33, PlayMode 18/18 (neu `S3Hud`), Verify A–I 718/0, Player-Selbsttest 30/30 |
|
||||||
|
| Parität | Referenzregeln unverändert: Golden 0 Abweichungen, Fingerabdruck `DCE95C96556F3A1A` gleich |
|
||||||
|
| Inhalt | Bots sparen für frühe Helden; Rotationsfehler der erweiterten Regeln behoben; halbes Champion-Kopfgeld; Neutrallager mit Glutsegen, Mondschild und Beute; Fog of War mit Spähern und Aufklärung in der Planungsvorschau |
|
||||||
|
| Balance | 120 gespiegelte Bot-Partien: Blau/Rot 57/63, Ø 9,0 Runden, erster Turm gewinnt 53/120 (Referenz 100/120), Sylvara 48/102 (`logs/s3/`) |
|
||||||
|
| Leistung | Karte 144,4–150,0 fps, Mid nah 167,4–172,2 fps, HUD 0,04–0,06 ms (`logs/s3/`) |
|
||||||
|
| Bild | `screenshots/s3/spiel/` |
|
||||||
|
| Commits | `luneraria/s3-strategie` (S3A `e756a90`) |
|
||||||
|
|
||||||
## Ausblick
|
## Ausblick
|
||||||
|
|
||||||
Der Pilot entscheidet über eine Serie weiterer Meshy-Figuren (Kosten je Figur, Lizenz, Stilgleichheit). Offen bleiben außerdem Künstler-Sculpts für Anatomie/Gesicht/Haar, LOD und Material-Atlanten sowie die Build-Module für Windows und Linux.
|
Der Pilot entscheidet über eine Serie weiterer Meshy-Figuren (Kosten je Figur, Lizenz, Stilgleichheit). Offen bleiben außerdem Künstler-Sculpts für Anatomie/Gesicht/Haar, LOD und Material-Atlanten sowie die Build-Module für Windows und Linux.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Port-Status · Champions of Luneraria in Unity
|
# Port-Status · Champions of Luneraria in Unity
|
||||||
|
|
||||||
Stand: 11. Oktober 2026 (S2, Glyphe, Rezepte, Ancient).
|
Stand: 11. Oktober 2026 (S3, Bots, Neutrallager, Fog of War).
|
||||||
|
|
||||||
Referenz ist der Godot-Stand `luneraria/g3` (`1b540f2`) in `../saumwacht-godot`; er wird nicht mehr verändert. Engine: Unity 6.3 LTS (6000.3.20f1), Renderer URP. HDRP ist ausgeschlossen, bis ein Vergleich mit einer echten Szene etwas anderes nahelegt.
|
Referenz ist der Godot-Stand `luneraria/g3` (`1b540f2`) in `../saumwacht-godot`; er wird nicht mehr verändert. Engine: Unity 6.3 LTS (6000.3.20f1), Renderer URP. HDRP ist ausgeschlossen, bis ein Vergleich mit einer echten Szene etwas anderes nahelegt.
|
||||||
|
|
||||||
|
|
@ -17,6 +17,7 @@ Zielplattformen sind Fedora 44 und Windows 11; macOS ist die Entwicklungsplattfo
|
||||||
| H1 · Sylvara | **fertig** (`luneraria/h1-sylvara`): erste spielbare Heldin nach dem Port mit Ultimate-Auslöser in der Planung und Skin-System (Blutmond); Referenzpartien unverändert | [../luneraria/H1-SYLVARA.md](../luneraria/H1-SYLVARA.md) |
|
| H1 · Sylvara | **fertig** (`luneraria/h1-sylvara`): erste spielbare Heldin nach dem Port mit Ultimate-Auslöser in der Planung und Skin-System (Blutmond); Referenzpartien unverändert | [../luneraria/H1-SYLVARA.md](../luneraria/H1-SYLVARA.md) |
|
||||||
| S1 · Strategie-Regeln | **fertig** (`luneraria/s1-strategie`): Söldner-Einkommen (Legion TD 2), Kasernen und Rückkauf (Dota 2), Mondsegen (League of Legends) hinter dem Regelschalter „Erweitert“ (Standard im Spiel); Referenzregeln für Tests unverändert | [../luneraria/S1-STRATEGIE.md](../luneraria/S1-STRATEGIE.md) |
|
| S1 · Strategie-Regeln | **fertig** (`luneraria/s1-strategie`): Söldner-Einkommen (Legion TD 2), Kasernen und Rückkauf (Dota 2), Mondsegen (League of Legends) hinter dem Regelschalter „Erweitert“ (Standard im Spiel); Referenzregeln für Tests unverändert | [../luneraria/S1-STRATEGIE.md](../luneraria/S1-STRATEGIE.md) |
|
||||||
| S2 · Glyphe, Rezepte, Ancient | **fertig** (`luneraria/s2-strategie`): Glyphe (Dota 2), Item-Rezepte (Dota 2/LoL), Ancient-Stufen (Legion TD 2), Grottenjagd der Bots; hinter dem Regelschalter „Erweitert“ | [../luneraria/S2-STRATEGIE.md](../luneraria/S2-STRATEGIE.md) |
|
| S2 · Glyphe, Rezepte, Ancient | **fertig** (`luneraria/s2-strategie`): Glyphe (Dota 2), Item-Rezepte (Dota 2/LoL), Ancient-Stufen (Legion TD 2), Grottenjagd der Bots; hinter dem Regelschalter „Erweitert“ | [../luneraria/S2-STRATEGIE.md](../luneraria/S2-STRATEGIE.md) |
|
||||||
|
| S3 · Bots, Neutrallager, Fog of War | **fertig** (`luneraria/s3-strategie`): frühe Bot-Helden und Rotationsfehler behoben, Neutrallager mit LoL-Buffs, Fog of War mit Spähern (Dota 2) und Aufklärung in der Planung; hinter dem Regelschalter „Erweitert“ | [../luneraria/S3-STRATEGIE.md](../luneraria/S3-STRATEGIE.md) |
|
||||||
|
|
||||||
QA je Meilenstein: [PORT-QA.md](PORT-QA.md).
|
QA je Meilenstein: [PORT-QA.md](PORT-QA.md).
|
||||||
|
|
||||||
|
|
|
||||||
3
docs/port/logs/s3/balance-s3.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
rules; matches; blue wins; red wins; draws; open; mean rounds; min; max; first tower wins; champion income/seat; barracks waves; exhausted heroes; buybacks; blessings; sylvara seats; sylvara wins; glyphs fired; Ancient levels; recipe items
|
||||||
|
referenz; 120; 60; 60; 0; 0; 10.3; 9; 12; 100/120; 0.0; 0; 0; 0; 0; 0; 0; 0; 0; 0
|
||||||
|
erweitert; 120; 57; 63; 0; 0; 9.0; 8; 10; 53/120; 13.3; 273; 3472; 525; 67; 102; 48; 195; 318; 4
|
||||||
18
docs/port/logs/s3/core-tests-dotnet.json
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"suites": [
|
||||||
|
{"suite": "content", "checks": 77, "failures": 0, "seconds": 0.02, "failed": [], "notes": ["map geometry: largest deviation lanes 0.00E+000 m, buildings 0.00E+000 m"]},
|
||||||
|
{"suite": "core", "checks": 91, "failures": 0, "seconds": 1.71, "failed": [], "notes": ["full match seed 2 -> Rot after 9 rounds"]},
|
||||||
|
{"suite": "m2", "checks": 73, "failures": 0, "seconds": 0.39, "failed": [], "notes": []},
|
||||||
|
{"suite": "golden", "checks": 157, "failures": 0, "seconds": 1.55, "failed": [], "notes": ["golden values compared: 51221", "largest deviation angle: 0.00E+000 over 1140 values (tolerance 1E-004)", "largest deviation effect: 0.00E+000 over 264 values (tolerance 1E-006)", "largest deviation hp: 0.00E+000 over 5679 values (tolerance 1E-002)", "largest deviation other: 0.00E+000 over 34 values (tolerance 1E-006)", "largest deviation position: 0.00E+000 over 3420 values (tolerance 1E-003)", "largest deviation time: 0.00E+000 over 780 values (tolerance 1E-006)", "domain ancients: 246 values, 0 differences, largest numeric deviation 0.00E+000", "domain announcements: 44 values, 0 differences, largest numeric deviation 0.00E+000", "domain boss: 1559 values, 0 differences, largest numeric deviation 0.00E+000", "domain combat: 676 values, 0 differences, largest numeric deviation 0.00E+000", "domain commands: 410 values, 0 differences, largest numeric deviation 0.00E+000", "domain events: 6937 values, 0 differences, largest numeric deviation 0.00E+000", "domain facing: 1140 values, 0 differences, largest numeric deviation 0.00E+000", "domain gold: 3584 values, 0 differences, largest numeric deviation 0.00E+000", "domain heroes: 1512 values, 0 differences, largest numeric deviation 0.00E+000", "domain hp: 3420 values, 0 differences, largest numeric deviation 0.00E+000", "domain other: 119 values, 0 differences, largest numeric deviation 0.00E+000", "domain positions: 3420 values, 0 differences, largest numeric deviation 0.00E+000", "domain purchases: 9311 values, 0 differences, largest numeric deviation 0.00E+000", "domain rounds: 119 values, 0 differences, largest numeric deviation 0.00E+000", "domain targets: 1140 values, 0 differences, largest numeric deviation 0.00E+000", "domain towers: 1994 values, 0 differences, largest numeric deviation 0.00E+000", "domain units: 14164 values, 0 differences, largest numeric deviation 0.00E+000", "domain waves: 731 values, 0 differences, largest numeric deviation 0.00E+000", "domain winner: 695 values, 0 differences, largest numeric deviation 0.00E+000"]},
|
||||||
|
{"suite": "determinism", "checks": 6, "failures": 0, "seconds": 1.52, "failed": [], "notes": []},
|
||||||
|
{"suite": "net", "checks": 43, "failures": 0, "seconds": 0.01, "failed": [], "notes": []},
|
||||||
|
{"suite": "net_rounds", "checks": 12, "failures": 0, "seconds": 0.08, "failed": [], "notes": []},
|
||||||
|
{"suite": "h1", "checks": 42, "failures": 0, "seconds": 1.27, "failed": [], "notes": ["sylvara-bot match seed 12: 15/1"]},
|
||||||
|
{"suite": "s1", "checks": 31, "failures": 0, "seconds": 0.37, "failed": [], "notes": ["extended seed 17: 9/1, income bonus 24,24,0,24,15,0, blessing 0/0"]},
|
||||||
|
{"suite": "s2", "checks": 34, "failures": 0, "seconds": 1.98, "failed": [], "notes": ["12 extended matches: expeditions 12, Mondsegen 6, recipe heroes 0, glyphs 16, Ancient levels 27; seed 1 9/0"]},
|
||||||
|
{"suite": "s3", "checks": 31, "failures": 0, "seconds": 0.69, "failed": [], "notes": []}
|
||||||
|
],
|
||||||
|
"runtime": ".NET 8.0.27",
|
||||||
|
"label": ".NET 8.0.27, Release",
|
||||||
|
"os": "Darwin 27.0.0 Darwin Kernel Version 27.0.0: Tue Aug 11 21:02:59 PDT 2026; root:xnu-13432.1.9~1/RELEASE_ARM64_T8142 Arm64"
|
||||||
|
}
|
||||||
363
docs/port/logs/s3/editmode-results.xml
Normal file
|
|
@ -0,0 +1,363 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<test-run id="2" testcasecount="33" result="Passed" total="33" passed="33" failed="0" inconclusive="0" skipped="0" asserts="0" engine-version="3.5.0.0" clr-version="4.0.30319.42000" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:15:27Z" duration="97.8832669">
|
||||||
|
<test-suite type="TestSuite" id="1000" name="luneraria-unity" fullname="luneraria-unity" runstate="Runnable" testcasecount="33" result="Passed" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:15:27Z" duration="97.883267" total="33" passed="33" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="platform" value="EditMode" />
|
||||||
|
</properties>
|
||||||
|
<test-suite type="Assembly" id="1016" name="Luneraria.Core.Tests.dll" fullname="/private/tmp/lune-konzept/Library/ScriptAssemblies/Luneraria.Core.Tests.dll" runstate="Runnable" testcasecount="13" result="Passed" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:15:03Z" duration="74.762638" total="13" passed="13" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_PID" value="26501" />
|
||||||
|
<property name="_APPDOMAIN" value="Unity Child Domain" />
|
||||||
|
<property name="platform" value="EditMode" />
|
||||||
|
<property name="EditorOnly" value="True" />
|
||||||
|
</properties>
|
||||||
|
<test-suite type="TestSuite" id="1017" name="Luneraria" fullname="Luneraria" runstate="Runnable" testcasecount="13" result="Passed" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:15:03Z" duration="74.762375" total="13" passed="13" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1018" name="Core" fullname="Luneraria.Core" runstate="Runnable" testcasecount="13" result="Passed" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:15:03Z" duration="74.762141" total="13" passed="13" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1019" name="Tests" fullname="Luneraria.Core.Tests" runstate="Runnable" testcasecount="13" result="Passed" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:15:03Z" duration="74.761897" total="13" passed="13" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestFixture" id="1001" name="CoreIntegrationTests" fullname="Luneraria.Core.Tests.CoreIntegrationTests" classname="Luneraria.Core.Tests.CoreIntegrationTests" runstate="Runnable" testcasecount="2" result="Passed" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:13:49Z" duration="0.055119" total="2" passed="2" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1003" name="CoreFloatArithmeticMatchesGodot" fullname="Luneraria.Core.Tests.CoreIntegrationTests.CoreFloatArithmeticMatchesGodot" methodname="CoreFloatArithmeticMatchesGodot" classname="Luneraria.Core.Tests.CoreIntegrationTests" runstate="Runnable" seed="1266851593" result="Passed" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:13:49Z" duration="0.050419" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[float probe: length 4000/4000, length_squared 4000/4000, distance_to 4000/4000, distance_squared_to 4000/4000, dot 4000/4000, normalized 4000/4000, lerp 4000/4000, limit_length 4000/4000, multiply 4000/4000, divide 4000/4000, sub_normalized 4000/4000, atan2 4000/4000
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1002" name="CoreHasNoEngineReferences" fullname="Luneraria.Core.Tests.CoreIntegrationTests.CoreHasNoEngineReferences" methodname="CoreHasNoEngineReferences" classname="Luneraria.Core.Tests.CoreIntegrationTests" runstate="Runnable" seed="1114925743" result="Passed" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:13:49Z" duration="0.000283" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1004" name="CoreSuiteTests" fullname="Luneraria.Core.Tests.CoreSuiteTests" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" testcasecount="11" result="Passed" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:15:03Z" duration="74.706211" total="11" passed="11" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1005" name="Content" fullname="Luneraria.Core.Tests.CoreSuiteTests.Content" methodname="Content" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" seed="203734501" result="Passed" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:13:49Z" duration="0.010938" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[content: map geometry: largest deviation lanes 0.00E+000 m, buildings 0.00E+000 m
|
||||||
|
LUNE_U1_PASS content: 77 checks
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1006" name="CoreRules" fullname="Luneraria.Core.Tests.CoreSuiteTests.CoreRules" methodname="CoreRules" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" seed="483360937" result="Passed" start-time="2026-10-11 14:13:49Z" end-time="2026-10-11 14:13:54Z" duration="5.311849" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[core: full match seed 2 -> Rot after 9 rounds
|
||||||
|
LUNE_U1_PASS core: 91 checks
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1009" name="Determinism" fullname="Luneraria.Core.Tests.CoreSuiteTests.Determinism" methodname="Determinism" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" seed="1811144674" result="Passed" start-time="2026-10-11 14:13:54Z" end-time="2026-10-11 14:14:08Z" duration="13.663685" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_U1_PASS determinism: 6 checks
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1008" name="GoldenReplays" fullname="Luneraria.Core.Tests.CoreSuiteTests.GoldenReplays" methodname="GoldenReplays" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" seed="1174353329" result="Passed" start-time="2026-10-11 14:14:08Z" end-time="2026-10-11 14:14:21Z" duration="13.580795" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[golden: golden values compared: 51221
|
||||||
|
golden: largest deviation angle: 0.00E+000 over 1140 values (tolerance 1E-004)
|
||||||
|
golden: largest deviation effect: 0.00E+000 over 264 values (tolerance 1E-006)
|
||||||
|
golden: largest deviation hp: 0.00E+000 over 5679 values (tolerance 1E-002)
|
||||||
|
golden: largest deviation other: 0.00E+000 over 34 values (tolerance 1E-006)
|
||||||
|
golden: largest deviation position: 0.00E+000 over 3420 values (tolerance 1E-003)
|
||||||
|
golden: largest deviation time: 0.00E+000 over 780 values (tolerance 1E-006)
|
||||||
|
golden: domain ancients: 246 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain announcements: 44 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain boss: 1559 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain combat: 676 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain commands: 410 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain events: 6937 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain facing: 1140 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain gold: 3584 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain heroes: 1512 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain hp: 3420 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain other: 119 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain positions: 3420 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain purchases: 9311 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain rounds: 119 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain targets: 1140 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain towers: 1994 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain units: 14164 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain waves: 731 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
golden: domain winner: 695 values, 0 differences, largest numeric deviation 0.00E+000
|
||||||
|
LUNE_U1_PASS golden: 157 checks
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1012" name="H1Heroes" fullname="Luneraria.Core.Tests.CoreSuiteTests.H1Heroes" methodname="H1Heroes" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" seed="32820993" result="Passed" start-time="2026-10-11 14:14:21Z" end-time="2026-10-11 14:14:33Z" duration="11.512555" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[h1: sylvara-bot match seed 12: 15/1
|
||||||
|
LUNE_U1_PASS h1: 42 checks
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1007" name="M2Rules" fullname="Luneraria.Core.Tests.CoreSuiteTests.M2Rules" methodname="M2Rules" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" seed="910585894" result="Passed" start-time="2026-10-11 14:14:33Z" end-time="2026-10-11 14:14:36Z" duration="3.479485" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_U1_PASS m2: 73 checks
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1010" name="NetProtocol" fullname="Luneraria.Core.Tests.CoreSuiteTests.NetProtocol" methodname="NetProtocol" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" seed="680268678" result="Passed" start-time="2026-10-11 14:14:36Z" end-time="2026-10-11 14:14:36Z" duration="0.084483" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_U1_PASS net: 43 checks
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1011" name="NetRounds" fullname="Luneraria.Core.Tests.CoreSuiteTests.NetRounds" methodname="NetRounds" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" seed="569729171" result="Passed" start-time="2026-10-11 14:14:36Z" end-time="2026-10-11 14:14:37Z" duration="0.576906" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_U1_PASS net_rounds: 12 checks
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1013" name="S1Rules" fullname="Luneraria.Core.Tests.CoreSuiteTests.S1Rules" methodname="S1Rules" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" seed="313551112" result="Passed" start-time="2026-10-11 14:14:37Z" end-time="2026-10-11 14:14:40Z" duration="3.218133" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[s1: extended seed 17: 9/1, income bonus 24,24,0,24,15,0, blessing 0/0
|
||||||
|
LUNE_U1_PASS s1: 31 checks
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1014" name="S2Rules" fullname="Luneraria.Core.Tests.CoreSuiteTests.S2Rules" methodname="S2Rules" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" seed="274688512" result="Passed" start-time="2026-10-11 14:14:40Z" end-time="2026-10-11 14:14:58Z" duration="17.872695" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[s2: 12 extended matches: expeditions 12, Mondsegen 6, recipe heroes 0, glyphs 16, Ancient levels 27; seed 1 9/0
|
||||||
|
LUNE_U1_PASS s2: 34 checks
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1015" name="S3Rules" fullname="Luneraria.Core.Tests.CoreSuiteTests.S3Rules" methodname="S3Rules" classname="Luneraria.Core.Tests.CoreSuiteTests" runstate="Runnable" seed="773434970" result="Passed" start-time="2026-10-11 14:14:58Z" end-time="2026-10-11 14:15:03Z" duration="5.391845" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_U1_PASS s3: 31 checks
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="Assembly" id="1025" name="Luneraria.Net.Tests.dll" fullname="/private/tmp/lune-konzept/Library/ScriptAssemblies/Luneraria.Net.Tests.dll" runstate="Runnable" testcasecount="4" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:03Z" duration="0.031484" total="4" passed="4" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_PID" value="26501" />
|
||||||
|
<property name="_APPDOMAIN" value="Unity Child Domain" />
|
||||||
|
<property name="platform" value="EditMode" />
|
||||||
|
<property name="EditorOnly" value="True" />
|
||||||
|
</properties>
|
||||||
|
<test-suite type="TestSuite" id="1026" name="Luneraria" fullname="Luneraria" runstate="Runnable" testcasecount="4" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:03Z" duration="0.009665" total="4" passed="4" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1027" name="Net" fullname="Luneraria.Net" runstate="Runnable" testcasecount="4" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:03Z" duration="0.009322" total="4" passed="4" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1028" name="Tests" fullname="Luneraria.Net.Tests" runstate="Runnable" testcasecount="4" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:03Z" duration="0.009121" total="4" passed="4" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestFixture" id="1020" name="LuneWireTests" fullname="Luneraria.Net.Tests.LuneWireTests" classname="Luneraria.Net.Tests.LuneWireTests" runstate="Runnable" testcasecount="4" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:03Z" duration="0.008990" total="4" passed="4" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1021" name="CommandRoundTrips" fullname="Luneraria.Net.Tests.LuneWireTests.CommandRoundTrips" methodname="CommandRoundTrips" classname="Luneraria.Net.Tests.LuneWireTests" runstate="Runnable" seed="99476542" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:03Z" duration="0.002462" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1024" name="LobbyAndOptionsRoundTrip" fullname="Luneraria.Net.Tests.LuneWireTests.LobbyAndOptionsRoundTrip" methodname="LobbyAndOptionsRoundTrip" classname="Luneraria.Net.Tests.LuneWireTests" runstate="Runnable" seed="1985196889" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:03Z" duration="0.000898" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1022" name="StateRoundTrips" fullname="Luneraria.Net.Tests.LuneWireTests.StateRoundTrips" methodname="StateRoundTrips" classname="Luneraria.Net.Tests.LuneWireTests" runstate="Runnable" seed="1815062695" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:03Z" duration="0.003082" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1023" name="UnitsAndFrameRoundTrip" fullname="Luneraria.Net.Tests.LuneWireTests.UnitsAndFrameRoundTrip" methodname="UnitsAndFrameRoundTrip" classname="Luneraria.Net.Tests.LuneWireTests" runstate="Runnable" seed="1297221926" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:03Z" duration="0.001603" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="Assembly" id="1042" name="Luneraria.UI.Tests.EditMode.dll" fullname="/private/tmp/lune-konzept/Library/ScriptAssemblies/Luneraria.UI.Tests.EditMode.dll" runstate="Runnable" testcasecount="12" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:04Z" duration="0.199482" total="12" passed="12" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_PID" value="26501" />
|
||||||
|
<property name="_APPDOMAIN" value="Unity Child Domain" />
|
||||||
|
<property name="platform" value="EditMode" />
|
||||||
|
<property name="EditorOnly" value="True" />
|
||||||
|
</properties>
|
||||||
|
<test-suite type="TestSuite" id="1043" name="Luneraria" fullname="Luneraria" runstate="Runnable" testcasecount="12" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:04Z" duration="0.199154" total="12" passed="12" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1044" name="UI" fullname="Luneraria.UI" runstate="Runnable" testcasecount="12" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:04Z" duration="0.199004" total="12" passed="12" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1045" name="Tests" fullname="Luneraria.UI.Tests" runstate="Runnable" testcasecount="12" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:04Z" duration="0.198895" total="12" passed="12" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestFixture" id="1029" name="HudModelTests" fullname="Luneraria.UI.Tests.HudModelTests" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" testcasecount="12" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:04Z" duration="0.198726" total="12" passed="12" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1034" name="AnnouncedDangersRaiseTheThreat" fullname="Luneraria.UI.Tests.HudModelTests.AnnouncedDangersRaiseTheThreat" methodname="AnnouncedDangersRaiseTheThreat" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="550727083" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:03Z" duration="0.004440" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1035" name="BattlefieldCountsTheLaneUnits" fullname="Luneraria.UI.Tests.HudModelTests.BattlefieldCountsTheLaneUnits" methodname="BattlefieldCountsTheLaneUnits" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="1638115156" result="Passed" start-time="2026-10-11 14:15:03Z" end-time="2026-10-11 14:15:04Z" duration="0.030239" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1032" name="BossLaneChoiceIsPrivateToTheChooser" fullname="Luneraria.UI.Tests.HudModelTests.BossLaneChoiceIsPrivateToTheChooser" methodname="BossLaneChoiceIsPrivateToTheChooser" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="1347827952" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:04Z" duration="0.002548" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1036" name="BossStatesFromPublicState" fullname="Luneraria.UI.Tests.HudModelTests.BossStatesFromPublicState" methodname="BossStatesFromPublicState" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="1211369956" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:04Z" duration="0.000652" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1041" name="BotMatchStillStartsByItself" fullname="Luneraria.UI.Tests.HudModelTests.BotMatchStillStartsByItself" methodname="BotMatchStillStartsByItself" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="990731656" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:04Z" duration="0.001073" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1030" name="EverySeatSeesTheSamePublicPicture" fullname="Luneraria.UI.Tests.HudModelTests.EverySeatSeesTheSamePublicPicture" methodname="EverySeatSeesTheSamePublicPicture" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="1372146762" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:04Z" duration="0.041571" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1040" name="HumanSeatPlanningWaitsForReady" fullname="Luneraria.UI.Tests.HudModelTests.HumanSeatPlanningWaitsForReady" methodname="HumanSeatPlanningWaitsForReady" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="55307828" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:04Z" duration="0.056214" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1033" name="LaneThreatFollowsTowerHealth" fullname="Luneraria.UI.Tests.HudModelTests.LaneThreatFollowsTowerHealth" methodname="LaneThreatFollowsTowerHealth" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="764936055" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:04Z" duration="0.000865" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1037" name="NextWaveIsTheRulesWave" fullname="Luneraria.UI.Tests.HudModelTests.NextWaveIsTheRulesWave" methodname="NextWaveIsTheRulesWave" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="1646673060" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:04Z" duration="0.001626" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1039" name="NumbersAreFormattedAsInGodot" fullname="Luneraria.UI.Tests.HudModelTests.NumbersAreFormattedAsInGodot" methodname="NumbersAreFormattedAsInGodot" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="68443850" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:04Z" duration="0.001223" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1031" name="OtherSeatsPlansStayPrivateUntilCombat" fullname="Luneraria.UI.Tests.HudModelTests.OtherSeatsPlansStayPrivateUntilCombat" methodname="OtherSeatsPlansStayPrivateUntilCombat" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="234387928" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:04Z" duration="0.056299" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1038" name="ReadyLocksThePlan" fullname="Luneraria.UI.Tests.HudModelTests.ReadyLocksThePlan" methodname="ReadyLocksThePlan" classname="Luneraria.UI.Tests.HudModelTests" runstate="Runnable" seed="882533245" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:04Z" duration="0.000763" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="Assembly" id="1051" name="Luneraria.View.Tests.EditMode.dll" fullname="/private/tmp/lune-konzept/Library/ScriptAssemblies/Luneraria.View.Tests.EditMode.dll" runstate="Runnable" testcasecount="4" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:27Z" duration="22.887103" total="4" passed="4" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_PID" value="26501" />
|
||||||
|
<property name="_APPDOMAIN" value="Unity Child Domain" />
|
||||||
|
<property name="platform" value="EditMode" />
|
||||||
|
<property name="EditorOnly" value="True" />
|
||||||
|
</properties>
|
||||||
|
<test-suite type="TestSuite" id="1052" name="Luneraria" fullname="Luneraria" runstate="Runnable" testcasecount="4" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:27Z" duration="22.886792" total="4" passed="4" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1053" name="View" fullname="Luneraria.View" runstate="Runnable" testcasecount="4" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:27Z" duration="22.886683" total="4" passed="4" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1054" name="Tests" fullname="Luneraria.View.Tests" runstate="Runnable" testcasecount="4" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:27Z" duration="22.886553" total="4" passed="4" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestFixture" id="1046" name="FrameRateIndependenceTests" fullname="Luneraria.View.Tests.FrameRateIndependenceTests" classname="Luneraria.View.Tests.FrameRateIndependenceTests" runstate="Runnable" testcasecount="4" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:27Z" duration="22.886406" total="4" passed="4" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1050" name="ClockRunsWholeStepsOnly" fullname="Luneraria.View.Tests.FrameRateIndependenceTests.ClockRunsWholeStepsOnly" methodname="ClockRunsWholeStepsOnly" classname="Luneraria.View.Tests.FrameRateIndependenceTests" runstate="Runnable" seed="1200841470" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:04Z" duration="0.000539" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1047" name="FullBotMatchSeed2IsTheSameAtEveryFrameRate" fullname="Luneraria.View.Tests.FrameRateIndependenceTests.FullBotMatchSeed2IsTheSameAtEveryFrameRate" methodname="FullBotMatchSeed2IsTheSameAtEveryFrameRate" classname="Luneraria.View.Tests.FrameRateIndependenceTests" runstate="Runnable" seed="1960786840" result="Passed" start-time="2026-10-11 14:15:04Z" end-time="2026-10-11 14:15:13Z" duration="8.938205" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_FPS seed 2 30 fps: 19315 frames, 12690 steps, hash DCE95C96556F3A1A (core DCE95C96556F3A1A)
|
||||||
|
LUNE_FPS seed 2 60 fps: 38597 frames, 12690 steps, hash DCE95C96556F3A1A (core DCE95C96556F3A1A)
|
||||||
|
LUNE_FPS seed 2 120 fps: 77169 frames, 12690 steps, hash DCE95C96556F3A1A (core DCE95C96556F3A1A)
|
||||||
|
LUNE_FPS seed 2 unlimited (0.4-3.9 ms jitter): 569627 frames, 12690 steps, hash DCE95C96556F3A1A (core DCE95C96556F3A1A)
|
||||||
|
LUNE_FPS seed 2 stutter (stalls up to 0.4 s): 26845 frames, 12690 steps, hash DCE95C96556F3A1A (core DCE95C96556F3A1A)
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1048" name="HighWaveMatchFromRound21IsTheSameAtEveryFrameRate" fullname="Luneraria.View.Tests.FrameRateIndependenceTests.HighWaveMatchFromRound21IsTheSameAtEveryFrameRate" methodname="HighWaveMatchFromRound21IsTheSameAtEveryFrameRate" classname="Luneraria.View.Tests.FrameRateIndependenceTests" runstate="Runnable" seed="442359531" result="Passed" start-time="2026-10-11 14:15:13Z" end-time="2026-10-11 14:15:18Z" duration="5.053102" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_FPS seed 9 30 fps: 6342 frames, 4195 steps, hash 7B8E43AEFC0D60C5 (core 7B8E43AEFC0D60C5)
|
||||||
|
LUNE_FPS seed 9 60 fps: 12678 frames, 4195 steps, hash 7B8E43AEFC0D60C5 (core 7B8E43AEFC0D60C5)
|
||||||
|
LUNE_FPS seed 9 120 fps: 25352 frames, 4195 steps, hash 7B8E43AEFC0D60C5 (core 7B8E43AEFC0D60C5)
|
||||||
|
LUNE_FPS seed 9 unlimited (0.4-3.9 ms jitter): 99090 frames, 4195 steps, hash 7B8E43AEFC0D60C5 (core 7B8E43AEFC0D60C5)
|
||||||
|
LUNE_FPS seed 9 stutter (stalls up to 0.4 s): 8796 frames, 4195 steps, hash 7B8E43AEFC0D60C5 (core 7B8E43AEFC0D60C5)
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1049" name="MatchSpeedDoesNotChangeTheMatch" fullname="Luneraria.View.Tests.FrameRateIndependenceTests.MatchSpeedDoesNotChangeTheMatch" methodname="MatchSpeedDoesNotChangeTheMatch" classname="Luneraria.View.Tests.FrameRateIndependenceTests" runstate="Runnable" seed="306198604" result="Passed" start-time="2026-10-11 14:15:18Z" end-time="2026-10-11 14:15:27Z" duration="8.893639" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_FPS seed 2 30 fps: 2418 frames, 12690 steps, hash DCE95C96556F3A1A (core DCE95C96556F3A1A)
|
||||||
|
LUNE_FPS seed 2 60 fps: 4831 frames, 12690 steps, hash DCE95C96556F3A1A (core DCE95C96556F3A1A)
|
||||||
|
LUNE_FPS seed 2 120 fps: 9658 frames, 12690 steps, hash DCE95C96556F3A1A (core DCE95C96556F3A1A)
|
||||||
|
LUNE_FPS seed 2 unlimited (0.4-3.9 ms jitter): 37713 frames, 12690 steps, hash DCE95C96556F3A1A (core DCE95C96556F3A1A)
|
||||||
|
LUNE_FPS seed 2 stutter (stalls up to 0.4 s): 3428 frames, 12690 steps, hash DCE95C96556F3A1A (core DCE95C96556F3A1A)
|
||||||
|
Saving results to: /Users/martin/Library/Application Support/DefaultCompany/luneraria-unity/TestResults.xml
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-run>
|
||||||
15
docs/port/logs/s3/player-benchmark-sylvara-run1.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"build": "OSXPlayer player, 6000.3.20f1, release",
|
||||||
|
"device": "Mac17,2; Apple M5; Apple M5",
|
||||||
|
"graphics_api": "Metal",
|
||||||
|
"resolution": "1920x1080",
|
||||||
|
"vsync": 0,
|
||||||
|
"match": "seed 9 from round 2, army held_sylvara x6, speed 1x, measured after 10 s of combat",
|
||||||
|
// moving units at the start of the first window: w04 11, w06 11, g04 10, g02 9, g06 9, w02 7, sylvara 5, g08 4, g10 4, w08 4, w10 3
|
||||||
|
"windows": [
|
||||||
|
{"view": "overview (zoom 64)", "frames": 3001, "fps": 150.0, "frame_ms_avg": 6.67, "frame_ms_median": 2.80, "frame_ms_p95": 21.60, "frame_ms_p99": 26.90, "frame_ms_max": 36.51, "frames_over_16_7_ms": 332, "of_them_with_simulation_step": 40, "gc_collections": 20, "simulation_ms_per_frame": 0.061, "views_ms_per_frame": 0.199, "ui_ms_per_frame": 0.054, "units_alive_max": 77},
|
||||||
|
// timings overview (zoom 64): main thread avg 2.31 / median 2.20 / p95 3.12 ms, render thread avg 1.68 / median 1.67 / p95 1.95 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 4.34 / median 0.22 / p95 19.26 ms
|
||||||
|
{"view": "mid lane close (zoom 22)", "frames": 1722, "fps": 172.2, "frame_ms_avg": 5.81, "frame_ms_median": 2.81, "frame_ms_p95": 20.11, "frame_ms_p99": 27.02, "frame_ms_max": 34.70, "frames_over_16_7_ms": 150, "of_them_with_simulation_step": 16, "gc_collections": 8, "simulation_ms_per_frame": 0.033, "views_ms_per_frame": 0.167, "ui_ms_per_frame": 0.040, "units_alive_max": 37}
|
||||||
|
// timings mid lane close (zoom 22): main thread avg 1.72 / median 1.64 / p95 2.41 ms, render thread avg 1.30 / median 1.28 / p95 1.51 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 4.11 / median 1.26 / p95 18.32 ms
|
||||||
|
]
|
||||||
|
}
|
||||||
15
docs/port/logs/s3/player-benchmark-sylvara-run2.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"build": "OSXPlayer player, 6000.3.20f1, release",
|
||||||
|
"device": "Mac17,2; Apple M5; Apple M5",
|
||||||
|
"graphics_api": "Metal",
|
||||||
|
"resolution": "1920x1080",
|
||||||
|
"vsync": 0,
|
||||||
|
"match": "seed 9 from round 2, army held_sylvara x6, speed 1x, measured after 10 s of combat",
|
||||||
|
// moving units at the start of the first window: w04 11, w06 11, g04 10, g02 9, g06 9, w02 7, sylvara 5, g08 4, g10 4, w08 4, w10 3
|
||||||
|
"windows": [
|
||||||
|
{"view": "overview (zoom 64)", "frames": 2888, "fps": 144.4, "frame_ms_avg": 6.93, "frame_ms_median": 3.40, "frame_ms_p95": 21.10, "frame_ms_p99": 26.31, "frame_ms_max": 33.70, "frames_over_16_7_ms": 312, "of_them_with_simulation_step": 23, "gc_collections": 20, "simulation_ms_per_frame": 0.066, "views_ms_per_frame": 0.225, "ui_ms_per_frame": 0.063, "units_alive_max": 77},
|
||||||
|
// timings overview (zoom 64): main thread avg 2.66 / median 2.44 / p95 4.40 ms, render thread avg 1.80 / median 1.77 / p95 2.25 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 4.26 / median 0.19 / p95 18.41 ms
|
||||||
|
{"view": "mid lane close (zoom 22)", "frames": 1674, "fps": 167.4, "frame_ms_avg": 5.97, "frame_ms_median": 2.70, "frame_ms_p95": 20.20, "frame_ms_p99": 28.59, "frame_ms_max": 35.32, "frames_over_16_7_ms": 152, "of_them_with_simulation_step": 15, "gc_collections": 8, "simulation_ms_per_frame": 0.032, "views_ms_per_frame": 0.168, "ui_ms_per_frame": 0.044, "units_alive_max": 37}
|
||||||
|
// timings mid lane close (zoom 22): main thread avg 1.78 / median 1.70 / p95 2.46 ms, render thread avg 1.34 / median 1.33 / p95 1.56 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 4.20 / median 0.73 / p95 18.17 ms
|
||||||
|
]
|
||||||
|
}
|
||||||
15
docs/port/logs/s3/player-benchmark-sylvara-run3.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"build": "OSXPlayer player, 6000.3.20f1, release",
|
||||||
|
"device": "Mac17,2; Apple M5; Apple M5",
|
||||||
|
"graphics_api": "Metal",
|
||||||
|
"resolution": "1920x1080",
|
||||||
|
"vsync": 0,
|
||||||
|
"match": "seed 9 from round 2, army held_sylvara x6, speed 1x, measured after 10 s of combat",
|
||||||
|
// moving units at the start of the first window: w04 11, w06 11, g04 10, g02 9, g06 9, w02 7, sylvara 5, g08 4, g10 4, w08 4, w10 3
|
||||||
|
"windows": [
|
||||||
|
{"view": "overview (zoom 64)", "frames": 2978, "fps": 148.8, "frame_ms_avg": 6.72, "frame_ms_median": 2.89, "frame_ms_p95": 21.91, "frame_ms_p99": 27.89, "frame_ms_max": 40.29, "frames_over_16_7_ms": 346, "of_them_with_simulation_step": 35, "gc_collections": 20, "simulation_ms_per_frame": 0.061, "views_ms_per_frame": 0.198, "ui_ms_per_frame": 0.055, "units_alive_max": 77},
|
||||||
|
// timings overview (zoom 64): main thread avg 2.30 / median 2.20 / p95 3.11 ms, render thread avg 1.69 / median 1.68 / p95 1.98 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 4.41 / median 0.26 / p95 19.47 ms
|
||||||
|
{"view": "mid lane close (zoom 22)", "frames": 1717, "fps": 171.4, "frame_ms_avg": 5.83, "frame_ms_median": 2.69, "frame_ms_p95": 19.91, "frame_ms_p99": 28.30, "frame_ms_max": 32.91, "frames_over_16_7_ms": 133, "of_them_with_simulation_step": 8, "gc_collections": 8, "simulation_ms_per_frame": 0.036, "views_ms_per_frame": 0.166, "ui_ms_per_frame": 0.037, "units_alive_max": 37}
|
||||||
|
// timings mid lane close (zoom 22): main thread avg 1.74 / median 1.66 / p95 2.46 ms, render thread avg 1.31 / median 1.30 / p95 1.53 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 4.07 / median 0.80 / p95 17.99 ms
|
||||||
|
]
|
||||||
|
}
|
||||||
11
docs/port/logs/s3/player-smoke.json
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"build": "OSXPlayer player, 6000.3.20f1, release",
|
||||||
|
"device": "Mac17,2; Apple M5; Apple M5",
|
||||||
|
"graphics_api": "Metal",
|
||||||
|
"resolution": "1920x1080",
|
||||||
|
"seconds": 11.6,
|
||||||
|
"passed": ["Startbildschirm sichtbar", "Partie wartet: Spielcontroller und Treiber aus", "vor dem Start kein HUD", "„Allein spielen“ bedienbar", "Offline: Startbildschirm verborgen", "Offline: Spielcontroller und Treiber laufen", "Offline: HUD sichtbar", "Offline: neue Partie, Sitz 1 (Mid)", "Offline: Planung", "Offline: lokale Sitzung", "„Startaufstellung“ bedienbar", "Startaufstellung gekauft (3 Einheiten)", "„Bereit“ bedienbar", "Bereit: Kampf beginnt", "Kampf: Figuren im Feld", "„Menü“ bedienbar", "Verlassen-Dialog mit „Zum Menü“", "Zurück: Startbildschirm sichtbar", "Zurück: HUD verborgen", "Zurück: Spielcontroller und Treiber aus", "Zurück: Sitzung beendet", "Zurück: keine Figuren im Feld", "Zurück: Kamera ruht", "Zurück: „Allein spielen“ bedienbar", "Zweite Partie: Startbildschirm verborgen, HUD sichtbar", "Zweite Partie: neue Partie in der Planung", "SSAO folgt der Einstellung", "Option „Umgebungsverdeckung“ sichtbar", "Option schaltet SSAO um", "Option stellt SSAO zurück"],
|
||||||
|
"failed": [],
|
||||||
|
"photos": ["00-startbildschirm.jpg", "01-planung.jpg", "02-kampf.jpg", "03-verlassen.jpg", "04-zurueck-im-startbildschirm.jpg", "05-zweite-partie.jpg", "06-optionen.jpg"],
|
||||||
|
"result": "PASS"
|
||||||
|
}
|
||||||
429
docs/port/logs/s3/playmode-results.xml
Normal file
|
|
@ -0,0 +1,429 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<test-run id="2" testcasecount="29" result="Passed" total="29" passed="18" failed="0" inconclusive="0" skipped="11" asserts="0" engine-version="3.5.0.0" clr-version="4.0.30319.42000" start-time="2026-10-11 14:24:50Z" end-time="2026-10-11 14:30:01Z" duration="310.8820833">
|
||||||
|
<test-suite type="TestSuite" id="1055" name="luneraria-unity" fullname="luneraria-unity" runstate="Runnable" testcasecount="29" result="Passed" start-time="2026-10-11 14:24:50Z" end-time="2026-10-11 14:30:01Z" duration="310.882083" total="29" passed="18" failed="0" inconclusive="0" skipped="11" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="platform" value="PlayMode" />
|
||||||
|
</properties>
|
||||||
|
<test-suite type="Assembly" id="1040" name="Luneraria.UI.Tests.PlayMode.dll" fullname="/private/tmp/lune-konzept/Library/ScriptAssemblies/Luneraria.UI.Tests.PlayMode.dll" runstate="Runnable" testcasecount="27" result="Passed" start-time="2026-10-11 14:24:50Z" end-time="2026-10-11 14:25:18Z" duration="28.046530" total="27" passed="16" failed="0" inconclusive="0" skipped="11" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_PID" value="28020" />
|
||||||
|
<property name="_APPDOMAIN" value="Unity Child Domain" />
|
||||||
|
<property name="platform" value="PlayMode" />
|
||||||
|
<property name="EditorOnly" value="False" />
|
||||||
|
</properties>
|
||||||
|
<test-suite type="TestSuite" id="1041" name="Luneraria" fullname="Luneraria" runstate="Runnable" testcasecount="27" result="Passed" start-time="2026-10-11 14:24:50Z" end-time="2026-10-11 14:25:18Z" duration="28.046154" total="27" passed="16" failed="0" inconclusive="0" skipped="11" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1042" name="UI" fullname="Luneraria.UI" runstate="Runnable" testcasecount="27" result="Passed" start-time="2026-10-11 14:24:50Z" end-time="2026-10-11 14:25:18Z" duration="28.045942" total="27" passed="16" failed="0" inconclusive="0" skipped="11" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1043" name="Tests" fullname="Luneraria.UI.Tests" runstate="Runnable" testcasecount="27" result="Passed" start-time="2026-10-11 14:24:50Z" end-time="2026-10-11 14:25:18Z" duration="28.045551" total="27" passed="16" failed="0" inconclusive="0" skipped="11" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestFixture" id="1001" name="ArmyViewsTests" fullname="Luneraria.UI.Tests.ArmyViewsTests" classname="Luneraria.UI.Tests.ArmyViewsTests" runstate="Explicit" testcasecount="1" result="Skipped" label="Explicit" site="SetUp" start-time="2026-10-11 14:24:50Z" end-time="2026-10-11 14:24:50Z" duration="0.002721" total="1" passed="0" failed="0" inconclusive="0" skipped="1" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_SKIPREASON" value="Bildwerkzeug: nur gezielt per -testFilter" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
<test-case id="1002" name="Glutpakt" fullname="Luneraria.UI.Tests.ArmyViewsTests.Glutpakt" methodname="Glutpakt" classname="Luneraria.UI.Tests.ArmyViewsTests" runstate="Runnable" seed="1427448480" result="Skipped" label="Explicit" site="Parent" start-time="0001-01-01 00:00:00Z" end-time="0001-01-01 00:00:00Z" duration="0.000000" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="900000" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1003" name="FigureViewsTests" fullname="Luneraria.UI.Tests.FigureViewsTests" classname="Luneraria.UI.Tests.FigureViewsTests" runstate="Explicit" testcasecount="1" result="Skipped" label="Explicit" site="SetUp" start-time="2026-10-11 14:24:50Z" end-time="2026-10-11 14:24:50Z" duration="0.000066" total="1" passed="0" failed="0" inconclusive="0" skipped="1" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_SKIPREASON" value="Bildwerkzeug: nur gezielt per -testFilter" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
<test-case id="1004" name="Kohlenbeisser" fullname="Luneraria.UI.Tests.FigureViewsTests.Kohlenbeisser" methodname="Kohlenbeisser" classname="Luneraria.UI.Tests.FigureViewsTests" runstate="Runnable" seed="160092792" result="Skipped" label="Explicit" site="Parent" start-time="0001-01-01 00:00:00Z" end-time="0001-01-01 00:00:00Z" duration="0.000000" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="900000" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1005" name="H1HeroViewsTests" fullname="Luneraria.UI.Tests.H1HeroViewsTests" classname="Luneraria.UI.Tests.H1HeroViewsTests" runstate="Runnable" testcasecount="2" result="Passed" start-time="2026-10-11 14:24:50Z" end-time="2026-10-11 14:24:52Z" duration="1.957683" total="2" passed="1" failed="0" inconclusive="0" skipped="1" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1007" name="SylvaraBilder" fullname="Luneraria.UI.Tests.H1HeroViewsTests.SylvaraBilder" methodname="SylvaraBilder" classname="Luneraria.UI.Tests.H1HeroViewsTests" runstate="Explicit" seed="1739563441" result="Skipped" label="Explicit" start-time="2026-10-11 14:24:50Z" end-time="2026-10-11 14:24:50Z" duration="0.000158" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="900000" />
|
||||||
|
<property name="_SKIPREASON" value="Bildwerkzeug: nur gezielt per -testFilter" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1006" name="SylvaraHud" fullname="Luneraria.UI.Tests.H1HeroViewsTests.SylvaraHud" methodname="SylvaraHud" classname="Luneraria.UI.Tests.H1HeroViewsTests" runstate="Runnable" seed="360346876" result="Passed" start-time="2026-10-11 14:24:50Z" end-time="2026-10-11 14:24:52Z" duration="1.955277" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="600000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1008" name="HudCaptureTests" fullname="Luneraria.UI.Tests.HudCaptureTests" classname="Luneraria.UI.Tests.HudCaptureTests" runstate="Runnable" testcasecount="1" result="Passed" start-time="2026-10-11 14:24:52Z" end-time="2026-10-11 14:24:52Z" duration="0.373937" total="1" passed="1" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1009" name="PlanningHudOverTheScene" fullname="Luneraria.UI.Tests.HudCaptureTests.PlanningHudOverTheScene" methodname="PlanningHudOverTheScene" classname="Luneraria.UI.Tests.HudCaptureTests" runstate="Runnable" seed="490156247" result="Passed" start-time="2026-10-11 14:24:52Z" end-time="2026-10-11 14:24:52Z" duration="0.370797" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="600000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_HUD syncs 1 sync ms 0.148 portraits 14 scale 1 size (1706.67, 960.00)
|
||||||
|
LUNE_HUD region top (x:425.78, y:12.44, width:855.11, height:83.56)
|
||||||
|
LUNE_HUD region system (x:1559.11, y:12.44, width:136.00, height:35.56)
|
||||||
|
LUNE_HUD region left (x:12.44, y:12.44, width:312.00, height:466.67)
|
||||||
|
LUNE_HUD region right (x:1372.44, y:56.00, width:322.67, height:248.00)
|
||||||
|
LUNE_HUD region bottom (x:12.44, y:761.78, width:1432.00, height:186.67)
|
||||||
|
LUNE_HUD region ready (x:1455.11, y:616.00, width:240.00, height:84.44)
|
||||||
|
LUNE_HUD region minimap (x:1455.11, y:708.44, width:240.00, height:240.00)
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1010" name="HudPlaytest" fullname="Luneraria.UI.Tests.HudPlaytest" classname="Luneraria.UI.Tests.HudPlaytest" runstate="Explicit" testcasecount="1" result="Skipped" label="Explicit" site="SetUp" start-time="2026-10-11 14:24:52Z" end-time="2026-10-11 14:24:52Z" duration="0.000083" total="1" passed="0" failed="0" inconclusive="0" skipped="1" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_SKIPREASON" value="Spieltest: wartet auf Befehlsdateien" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Spieltest: wartet auf Befehlsdateien]]></message>
|
||||||
|
</reason>
|
||||||
|
<test-case id="1011" name="Play" fullname="Luneraria.UI.Tests.HudPlaytest.Play" methodname="Play" classname="Luneraria.UI.Tests.HudPlaytest" runstate="Runnable" seed="2060716252" result="Skipped" label="Explicit" site="Parent" start-time="0001-01-01 00:00:00Z" end-time="0001-01-01 00:00:00Z" duration="0.000000" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="2147483647" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Spieltest: wartet auf Befehlsdateien]]></message>
|
||||||
|
</reason>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1012" name="HudVerifyTests" fullname="Luneraria.UI.Tests.HudVerifyTests" classname="Luneraria.UI.Tests.HudVerifyTests" runstate="Runnable" testcasecount="9" result="Passed" start-time="2026-10-11 14:24:52Z" end-time="2026-10-11 14:25:04Z" duration="11.286899" total="9" passed="9" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1013" name="A_Layout" fullname="Luneraria.UI.Tests.HudVerifyTests.A_Layout" methodname="A_Layout" classname="Luneraria.UI.Tests.HudVerifyTests" runstate="Runnable" seed="567707000" result="Passed" start-time="2026-10-11 14:24:52Z" end-time="2026-10-11 14:24:56Z" duration="4.026027" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="1800000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_VERIFY A: 585 checks, 0 failed
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1014" name="B_Status" fullname="Luneraria.UI.Tests.HudVerifyTests.B_Status" methodname="B_Status" classname="Luneraria.UI.Tests.HudVerifyTests" runstate="Runnable" seed="282292383" result="Passed" start-time="2026-10-11 14:24:56Z" end-time="2026-10-11 14:24:57Z" duration="0.354726" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="900000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_VERIFY B: 21 checks, 0 failed
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1015" name="C_HeroItemsUnits" fullname="Luneraria.UI.Tests.HudVerifyTests.C_HeroItemsUnits" methodname="C_HeroItemsUnits" classname="Luneraria.UI.Tests.HudVerifyTests" runstate="Runnable" seed="795459748" result="Passed" start-time="2026-10-11 14:24:57Z" end-time="2026-10-11 14:24:57Z" duration="0.662536" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="900000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_VERIFY C: 23 checks, 0 failed
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1016" name="D_ChampionsAndBoss" fullname="Luneraria.UI.Tests.HudVerifyTests.D_ChampionsAndBoss" methodname="D_ChampionsAndBoss" classname="Luneraria.UI.Tests.HudVerifyTests" runstate="Runnable" seed="1465240178" result="Passed" start-time="2026-10-11 14:24:57Z" end-time="2026-10-11 14:24:58Z" duration="0.486798" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="900000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_VERIFY D: 16 checks, 0 failed
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1017" name="E_ReadyBotsPrivacy" fullname="Luneraria.UI.Tests.HudVerifyTests.E_ReadyBotsPrivacy" methodname="E_ReadyBotsPrivacy" classname="Luneraria.UI.Tests.HudVerifyTests" runstate="Runnable" seed="1441287330" result="Passed" start-time="2026-10-11 14:24:58Z" end-time="2026-10-11 14:24:59Z" duration="1.371425" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="900000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_VERIFY E: 17 checks, 0 failed
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1018" name="F_Input" fullname="Luneraria.UI.Tests.HudVerifyTests.F_Input" methodname="F_Input" classname="Luneraria.UI.Tests.HudVerifyTests" runstate="Runnable" seed="867797772" result="Passed" start-time="2026-10-11 14:24:59Z" end-time="2026-10-11 14:25:03Z" duration="3.404406" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="900000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_VERIFY F: 18 checks, 0 failed
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1019" name="G_EventsAndMotion" fullname="Luneraria.UI.Tests.HudVerifyTests.G_EventsAndMotion" methodname="G_EventsAndMotion" classname="Luneraria.UI.Tests.HudVerifyTests" runstate="Runnable" seed="819185325" result="Passed" start-time="2026-10-11 14:25:03Z" end-time="2026-10-11 14:25:03Z" duration="0.483542" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="900000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_VERIFY G: 14 checks, 0 failed
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1020" name="H_RatesAndPortraits" fullname="Luneraria.UI.Tests.HudVerifyTests.H_RatesAndPortraits" methodname="H_RatesAndPortraits" classname="Luneraria.UI.Tests.HudVerifyTests" runstate="Runnable" seed="1485870284" result="Passed" start-time="2026-10-11 14:25:03Z" end-time="2026-10-11 14:25:03Z" duration="0.202121" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="900000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_VERIFY rates planning 18/2s combat 10/2s sync 0.220 ms portraits 15
|
||||||
|
LUNE_VERIFY H: 5 checks, 0 failed
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1021" name="I_Field" fullname="Luneraria.UI.Tests.HudVerifyTests.I_Field" methodname="I_Field" classname="Luneraria.UI.Tests.HudVerifyTests" runstate="Runnable" seed="367785142" result="Passed" start-time="2026-10-11 14:25:03Z" end-time="2026-10-11 14:25:04Z" duration="0.292393" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="900000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_VERIFY I: 19 checks, 0 failed
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1022" name="HudViewsTests" fullname="Luneraria.UI.Tests.HudViewsTests" classname="Luneraria.UI.Tests.HudViewsTests" runstate="Explicit" testcasecount="4" result="Skipped" label="Explicit" site="SetUp" start-time="2026-10-11 14:25:04Z" end-time="2026-10-11 14:25:04Z" duration="0.000232" total="4" passed="0" failed="0" inconclusive="0" skipped="4" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_SKIPREASON" value="Bildwerkzeug: nur gezielt per -testFilter" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
<test-case id="1025" name="Motifs_1280x720" fullname="Luneraria.UI.Tests.HudViewsTests.Motifs_1280x720" methodname="Motifs_1280x720" classname="Luneraria.UI.Tests.HudViewsTests" runstate="Runnable" seed="1780525871" result="Skipped" label="Explicit" site="Parent" start-time="0001-01-01 00:00:00Z" end-time="0001-01-01 00:00:00Z" duration="0.000000" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="1800000" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1023" name="Motifs_1920x1080" fullname="Luneraria.UI.Tests.HudViewsTests.Motifs_1920x1080" methodname="Motifs_1920x1080" classname="Luneraria.UI.Tests.HudViewsTests" runstate="Runnable" seed="691621395" result="Skipped" label="Explicit" site="Parent" start-time="0001-01-01 00:00:00Z" end-time="0001-01-01 00:00:00Z" duration="0.000000" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="1800000" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1026" name="Motifs_2560x1080" fullname="Luneraria.UI.Tests.HudViewsTests.Motifs_2560x1080" methodname="Motifs_2560x1080" classname="Luneraria.UI.Tests.HudViewsTests" runstate="Runnable" seed="128243598" result="Skipped" label="Explicit" site="Parent" start-time="0001-01-01 00:00:00Z" end-time="0001-01-01 00:00:00Z" duration="0.000000" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="1800000" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1024" name="Motifs_2560x1440" fullname="Luneraria.UI.Tests.HudViewsTests.Motifs_2560x1440" methodname="Motifs_2560x1440" classname="Luneraria.UI.Tests.HudViewsTests" runstate="Runnable" seed="988039574" result="Skipped" label="Explicit" site="Parent" start-time="0001-01-01 00:00:00Z" end-time="0001-01-01 00:00:00Z" duration="0.000000" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="1800000" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1027" name="S1RulesViewsTests" fullname="Luneraria.UI.Tests.S1RulesViewsTests" classname="Luneraria.UI.Tests.S1RulesViewsTests" runstate="Runnable" testcasecount="2" result="Passed" start-time="2026-10-11 14:25:04Z" end-time="2026-10-11 14:25:05Z" duration="1.767120" total="2" passed="1" failed="0" inconclusive="0" skipped="1" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1029" name="S1Bilder" fullname="Luneraria.UI.Tests.S1RulesViewsTests.S1Bilder" methodname="S1Bilder" classname="Luneraria.UI.Tests.S1RulesViewsTests" runstate="Explicit" seed="1049294022" result="Skipped" label="Explicit" start-time="2026-10-11 14:25:04Z" end-time="2026-10-11 14:25:04Z" duration="0.000001" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="600000" />
|
||||||
|
<property name="_SKIPREASON" value="Bildwerkzeug: nur gezielt per -testFilter" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1028" name="S1Hud" fullname="Luneraria.UI.Tests.S1RulesViewsTests.S1Hud" methodname="S1Hud" classname="Luneraria.UI.Tests.S1RulesViewsTests" runstate="Runnable" seed="747488534" result="Passed" start-time="2026-10-11 14:25:04Z" end-time="2026-10-11 14:25:05Z" duration="1.764963" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="600000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1030" name="S2RulesViewsTests" fullname="Luneraria.UI.Tests.S2RulesViewsTests" classname="Luneraria.UI.Tests.S2RulesViewsTests" runstate="Runnable" testcasecount="2" result="Passed" start-time="2026-10-11 14:25:05Z" end-time="2026-10-11 14:25:06Z" duration="0.329720" total="2" passed="1" failed="0" inconclusive="0" skipped="1" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1032" name="S2Bilder" fullname="Luneraria.UI.Tests.S2RulesViewsTests.S2Bilder" methodname="S2Bilder" classname="Luneraria.UI.Tests.S2RulesViewsTests" runstate="Explicit" seed="2071742234" result="Skipped" label="Explicit" start-time="2026-10-11 14:25:05Z" end-time="2026-10-11 14:25:05Z" duration="0.000001" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="600000" />
|
||||||
|
<property name="_SKIPREASON" value="Bildwerkzeug: nur gezielt per -testFilter" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1031" name="S2Hud" fullname="Luneraria.UI.Tests.S2RulesViewsTests.S2Hud" methodname="S2Hud" classname="Luneraria.UI.Tests.S2RulesViewsTests" runstate="Runnable" seed="2003724229" result="Passed" start-time="2026-10-11 14:25:05Z" end-time="2026-10-11 14:25:06Z" duration="0.317122" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="600000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1033" name="S3RulesViewsTests" fullname="Luneraria.UI.Tests.S3RulesViewsTests" classname="Luneraria.UI.Tests.S3RulesViewsTests" runstate="Runnable" testcasecount="2" result="Passed" start-time="2026-10-11 14:25:06Z" end-time="2026-10-11 14:25:07Z" duration="1.548371" total="2" passed="1" failed="0" inconclusive="0" skipped="1" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1035" name="S3Bilder" fullname="Luneraria.UI.Tests.S3RulesViewsTests.S3Bilder" methodname="S3Bilder" classname="Luneraria.UI.Tests.S3RulesViewsTests" runstate="Explicit" seed="2136829365" result="Skipped" label="Explicit" start-time="2026-10-11 14:25:06Z" end-time="2026-10-11 14:25:06Z" duration="0.000002" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="600000" />
|
||||||
|
<property name="_SKIPREASON" value="Bildwerkzeug: nur gezielt per -testFilter" />
|
||||||
|
</properties>
|
||||||
|
<reason>
|
||||||
|
<message><![CDATA[Bildwerkzeug: nur gezielt per -testFilter]]></message>
|
||||||
|
</reason>
|
||||||
|
</test-case>
|
||||||
|
<test-case id="1034" name="S3Hud" fullname="Luneraria.UI.Tests.S3RulesViewsTests.S3Hud" methodname="S3Hud" classname="Luneraria.UI.Tests.S3RulesViewsTests" runstate="Runnable" seed="249937121" result="Passed" start-time="2026-10-11 14:25:06Z" end-time="2026-10-11 14:25:07Z" duration="1.545394" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="600000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1036" name="StartScreenTests" fullname="Luneraria.UI.Tests.StartScreenTests" classname="Luneraria.UI.Tests.StartScreenTests" runstate="Runnable" testcasecount="1" result="Passed" start-time="2026-10-11 14:25:07Z" end-time="2026-10-11 14:25:18Z" duration="10.700333" total="1" passed="1" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1037" name="StartScreenLeadsIntoTheMatchAndBack" fullname="Luneraria.UI.Tests.StartScreenTests.StartScreenLeadsIntoTheMatchAndBack" methodname="StartScreenLeadsIntoTheMatchAndBack" classname="Luneraria.UI.Tests.StartScreenTests" runstate="Runnable" seed="725406323" result="Passed" start-time="2026-10-11 14:25:07Z" end-time="2026-10-11 14:25:18Z" duration="10.698666" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="300000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_SMOKE ok Startbildschirm sichtbar
|
||||||
|
LUNE_SMOKE ok Partie wartet: Spielcontroller und Treiber aus
|
||||||
|
LUNE_SMOKE ok vor dem Start kein HUD
|
||||||
|
LUNE_SMOKE ok „Allein spielen“ bedienbar
|
||||||
|
LUNE_SMOKE ok Offline: Startbildschirm verborgen
|
||||||
|
LUNE_SMOKE ok Offline: Spielcontroller und Treiber laufen
|
||||||
|
LUNE_SMOKE ok Offline: HUD sichtbar
|
||||||
|
LUNE_SMOKE ok Offline: neue Partie, Sitz 1 (Mid)
|
||||||
|
LUNE_SMOKE ok Offline: Planung
|
||||||
|
LUNE_SMOKE ok Offline: lokale Sitzung
|
||||||
|
LUNE_SMOKE ok „Startaufstellung“ bedienbar
|
||||||
|
LUNE_SMOKE ok Startaufstellung gekauft (3 Einheiten)
|
||||||
|
LUNE_SMOKE ok „Bereit“ bedienbar
|
||||||
|
LUNE_SMOKE ok Bereit: Kampf beginnt
|
||||||
|
LUNE_SMOKE ok Kampf: Figuren im Feld
|
||||||
|
LUNE_SMOKE ok „Menü“ bedienbar
|
||||||
|
LUNE_SMOKE ok Verlassen-Dialog mit „Zum Menü“
|
||||||
|
LUNE_SMOKE ok Zurück: Startbildschirm sichtbar
|
||||||
|
LUNE_SMOKE ok Zurück: HUD verborgen
|
||||||
|
LUNE_SMOKE ok Zurück: Spielcontroller und Treiber aus
|
||||||
|
LUNE_SMOKE ok Zurück: Sitzung beendet
|
||||||
|
LUNE_SMOKE ok Zurück: keine Figuren im Feld
|
||||||
|
LUNE_SMOKE ok Zurück: Kamera ruht
|
||||||
|
LUNE_SMOKE ok Zurück: „Allein spielen“ bedienbar
|
||||||
|
LUNE_SMOKE ok Zweite Partie: Startbildschirm verborgen, HUD sichtbar
|
||||||
|
LUNE_SMOKE ok Zweite Partie: neue Partie in der Planung
|
||||||
|
LUNE_SMOKE_PASS 26 ok, 0 Fehler
|
||||||
|
LUNE_START_SCREEN 26 checks passed
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1038" name="UiToolkitProbeTests" fullname="Luneraria.UI.Tests.UiToolkitProbeTests" classname="Luneraria.UI.Tests.UiToolkitProbeTests" runstate="Runnable" testcasecount="1" result="Passed" start-time="2026-10-11 14:25:18Z" end-time="2026-10-11 14:25:18Z" duration="0.076930" total="1" passed="1" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1039" name="PanelRendersIntoTexture" fullname="Luneraria.UI.Tests.UiToolkitProbeTests.PanelRendersIntoTexture" methodname="PanelRendersIntoTexture" classname="Luneraria.UI.Tests.UiToolkitProbeTests" runstate="Runnable" seed="1642177974" result="Passed" start-time="2026-10-11 14:25:18Z" end-time="2026-10-11 14:25:18Z" duration="0.076317" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_SPIKE corner RGBA(0.565, 0.635, 0.506, 1.000) panel RGBA(0.196, 0.227, 0.204, 1.000) layout (x:12.44, y:12.44, width:760.00, height:530.67)
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="Assembly" id="1048" name="Luneraria.View.Tests.PlayMode.dll" fullname="/private/tmp/lune-konzept/Library/ScriptAssemblies/Luneraria.View.Tests.PlayMode.dll" runstate="Runnable" testcasecount="2" result="Passed" start-time="2026-10-11 14:25:18Z" end-time="2026-10-11 14:30:01Z" duration="282.832351" total="2" passed="2" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_PID" value="28020" />
|
||||||
|
<property name="_APPDOMAIN" value="Unity Child Domain" />
|
||||||
|
<property name="platform" value="PlayMode" />
|
||||||
|
<property name="EditorOnly" value="False" />
|
||||||
|
</properties>
|
||||||
|
<test-suite type="TestSuite" id="1049" name="Luneraria" fullname="Luneraria" runstate="Runnable" testcasecount="2" result="Passed" start-time="2026-10-11 14:25:18Z" end-time="2026-10-11 14:30:01Z" duration="282.831500" total="2" passed="2" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1050" name="View" fullname="Luneraria.View" runstate="Runnable" testcasecount="2" result="Passed" start-time="2026-10-11 14:25:18Z" end-time="2026-10-11 14:30:01Z" duration="282.831143" total="2" passed="2" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestSuite" id="1051" name="Tests" fullname="Luneraria.View.Tests" runstate="Runnable" testcasecount="2" result="Passed" start-time="2026-10-11 14:25:18Z" end-time="2026-10-11 14:30:01Z" duration="282.830820" total="2" passed="2" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-suite type="TestFixture" id="1044" name="SceneFrameRateTests" fullname="Luneraria.View.Tests.SceneFrameRateTests" classname="Luneraria.View.Tests.SceneFrameRateTests" runstate="Runnable" testcasecount="1" result="Passed" start-time="2026-10-11 14:25:18Z" end-time="2026-10-11 14:27:09Z" duration="110.398582" total="1" passed="1" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1045" name="SceneMatchIsTheSameAtRealFrameRates" fullname="Luneraria.View.Tests.SceneFrameRateTests.SceneMatchIsTheSameAtRealFrameRates" methodname="SceneMatchIsTheSameAtRealFrameRates" classname="Luneraria.View.Tests.SceneFrameRateTests" runstate="Runnable" seed="981845431" result="Passed" start-time="2026-10-11 14:25:18Z" end-time="2026-10-11 14:27:09Z" duration="110.397118" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_SCENE_FPS 30 fps: 815 frames in 27.1 s = 30.0 fps, up to 21 steps per frame, hash DCE95C96556F3A1A, same=True
|
||||||
|
LUNE_SCENE_FPS 60 fps: 1626 frames in 27.1 s = 60.0 fps, up to 10 steps per frame, hash DCE95C96556F3A1A, same=True
|
||||||
|
LUNE_SCENE_FPS 120 fps: 3223 frames in 26.9 s = 119.8 fps, up to 6 steps per frame, hash DCE95C96556F3A1A, same=True
|
||||||
|
LUNE_SCENE_FPS unlimited: 86375 frames in 26.8 s = 3221.2 fps, up to 25 steps per frame, hash DCE95C96556F3A1A, same=True
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
<test-suite type="TestFixture" id="1046" name="VerticalFunctionTests" fullname="Luneraria.View.Tests.VerticalFunctionTests" classname="Luneraria.View.Tests.VerticalFunctionTests" runstate="Runnable" testcasecount="1" result="Passed" start-time="2026-10-11 14:27:09Z" end-time="2026-10-11 14:30:01Z" duration="172.431887" total="1" passed="1" failed="0" inconclusive="0" skipped="0" asserts="0">
|
||||||
|
<properties />
|
||||||
|
<test-case id="1047" name="BotMatchesRunVisiblyAndMatchTheCore" fullname="Luneraria.View.Tests.VerticalFunctionTests.BotMatchesRunVisiblyAndMatchTheCore" methodname="BotMatchesRunVisiblyAndMatchTheCore" classname="Luneraria.View.Tests.VerticalFunctionTests" runstate="Runnable" seed="1058411317" result="Passed" start-time="2026-10-11 14:27:09Z" end-time="2026-10-11 14:30:01Z" duration="172.427264" asserts="0">
|
||||||
|
<properties>
|
||||||
|
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||||
|
<property name="Timeout" value="3600000" />
|
||||||
|
<property name="retryIteration" value="0" />
|
||||||
|
<property name="repeatIteration" value="0" />
|
||||||
|
</properties>
|
||||||
|
<output><![CDATA[LUNE_U2D shot 01-runde1-aufmarsch round 1 Combat
|
||||||
|
LUNE_U2D shot 02-runde1-mid-kampf round 1 Combat
|
||||||
|
LUNE_U2D shot 03-turm-faellt round 7 Combat
|
||||||
|
LUNE_U2D shot 04-turm-ruine round 7 Combat
|
||||||
|
LUNE_U2D shot 05-grotte-bosskampf round 8 Combat
|
||||||
|
LUNE_U2D shot 06-held-kaempft round 9 Combat
|
||||||
|
LUNE_U2D shot 07-boss-auf-der-lane round 9 Combat
|
||||||
|
LUNE_U2D shot 08-ancient-faellt round 9 Over
|
||||||
|
LUNE_U2D shot 09-ancient-ruine round 9 Over
|
||||||
|
LUNE_U2D shot 10-ende-uebersicht round 9 Over
|
||||||
|
LUNE_U2D shot 11-welle21-uebersicht round 21 Combat
|
||||||
|
LUNE_U2D shot 12-welle21-kampf round 21 Combat
|
||||||
|
LUNE_U2D shot 13-ancient-rot-faellt round 22 Over
|
||||||
|
LUNE_U2D shot 14-welle-ende round 22 Over
|
||||||
|
Saving results to: /Users/martin/Library/Application Support/DefaultCompany/luneraria-unity/TestResults.xml
|
||||||
|
]]></output>
|
||||||
|
</test-case>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-suite>
|
||||||
|
</test-run>
|
||||||
11
docs/port/logs/s3/scene-frame-rates.json
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"match": "seed 2, bots, speed 24x",
|
||||||
|
"core_hash": "DCE95C96556F3A1A",
|
||||||
|
"core_steps": 12690,
|
||||||
|
"runs": [
|
||||||
|
{"target": "30 fps", "frames": 815, "seconds": 27.144, "measured_fps": 30.025, "max_steps_per_frame": 21, "steps": 12690, "hash": "DCE95C96556F3A1A", "winner": 1, "same_as_core": true},
|
||||||
|
{"target": "60 fps", "frames": 1626, "seconds": 27.086, "measured_fps": 60.031, "max_steps_per_frame": 10, "steps": 12690, "hash": "DCE95C96556F3A1A", "winner": 1, "same_as_core": true},
|
||||||
|
{"target": "120 fps", "frames": 3223, "seconds": 26.897, "measured_fps": 119.829, "max_steps_per_frame": 6, "steps": 12690, "hash": "DCE95C96556F3A1A", "winner": 1, "same_as_core": true},
|
||||||
|
{"target": "unlimited", "frames": 86375, "seconds": 26.814, "measured_fps": 3221.234, "max_steps_per_frame": 25, "steps": 12690, "hash": "DCE95C96556F3A1A", "winner": 1, "same_as_core": true}
|
||||||
|
]
|
||||||
|
}
|
||||||
16
docs/port/logs/s3/vertical-function-test.json
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"runs": [
|
||||||
|
{"label": "match-seed2", "seed": 2, "start_round": 1, "extra_gold": 0, "speed": 6, "winner": 1, "end_note": "Ancient von Blau zerstört.", "steps": 12690, "hash": "DCE95C96556F3A1A", "core_hash": "DCE95C96556F3A1A", "same_as_core": true,
|
||||||
|
"units_alive_max": 84, "heroes_alive_max": 4, "boss_log": ["round 8: won team 1 ", "round 9: deployed team 1 bot"],
|
||||||
|
"rounds": [{"round": 1, "combat_seconds": 44.9, "lost": [], "boss": "none", "end": "cleared"}, {"round": 2, "combat_seconds": 57.1, "lost": [], "boss": "none", "end": "cleared"}, {"round": 3, "combat_seconds": 54.1, "lost": [], "boss": "none", "end": "cleared"}, {"round": 4, "combat_seconds": 62.9, "lost": [], "boss": "none", "end": "cleared"}, {"round": 5, "combat_seconds": 60.7, "lost": [], "boss": "none", "end": "cleared"}, {"round": 6, "combat_seconds": 62.1, "lost": [], "boss": "none", "end": "cleared"}, {"round": 7, "combat_seconds": 66.5, "lost": ["blau_bot_outer"], "boss": "none", "end": "cleared"}, {"round": 8, "combat_seconds": 89.65, "lost": ["rot_top_outer", "rot_top_inner"], "boss": "won", "end": "cleared"}, {"round": 9, "combat_seconds": 136.55, "lost": ["blau_bot_inner", "blau_base_2", "blau_base_1", "blau_ancient"], "boss": "deployed", "end": "core"}],
|
||||||
|
"events": ["round 7: blau_bot_outer destroyed", "round 8: rot_top_outer destroyed", "round 8: rot_top_inner destroyed", "round 8: grotto boss won", "round 9: blau_bot_inner destroyed", "round 9: blau_base_2 destroyed", "round 9: blau_base_1 destroyed", "round 9: blau_ancient destroyed", "round 9: grotto boss deployed"],
|
||||||
|
"shots": ["01-runde1-aufmarsch", "02-runde1-mid-kampf", "03-turm-faellt", "04-turm-ruine", "05-grotte-bosskampf", "06-held-kaempft", "07-boss-auf-der-lane", "08-ancient-faellt", "09-ancient-ruine", "10-ende-uebersicht"],
|
||||||
|
"performance": null},
|
||||||
|
{"label": "match-seed9-round21", "seed": 9, "start_round": 21, "extra_gold": 4000, "speed": 6, "winner": 0, "end_note": "Ancient von Rot zerstört.", "steps": 4195, "hash": "7B8E43AEFC0D60C5", "core_hash": "7B8E43AEFC0D60C5", "same_as_core": true,
|
||||||
|
"units_alive_max": 125, "heroes_alive_max": 6, "boss_log": [],
|
||||||
|
"rounds": [{"round": 21, "combat_seconds": 121.8, "lost": ["rot_mid_outer", "rot_top_outer", "rot_mid_inner"], "boss": "none", "end": "cleared"}, {"round": 22, "combat_seconds": 87.95, "lost": ["rot_top_inner", "rot_base_1", "blau_bot_outer", "rot_base_2", "rot_ancient"], "boss": "none", "end": "core"}],
|
||||||
|
"events": ["round 21: rot_mid_outer destroyed", "round 21: rot_top_outer destroyed", "round 21: rot_mid_inner destroyed", "round 22: rot_top_inner destroyed", "round 22: rot_base_1 destroyed", "round 22: blau_bot_outer destroyed", "round 22: rot_base_2 destroyed", "round 22: rot_ancient destroyed"],
|
||||||
|
"shots": ["11-welle21-uebersicht", "12-welle21-kampf", "13-ancient-rot-faellt", "14-welle-ende"],
|
||||||
|
"performance": {"window": "20 s real time at 1x speed, unlimited frame rate, round 21", "frames": 48365, "fps": 2418.249, "frame_ms_avg": 0.414, "frame_ms_p95": 0.422, "simulation_ms_per_frame": 0.004, "views_ms_per_frame": 0.143, "units_alive_max": 116}}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
docs/port/screenshots/s3/ablauf/01-runde1-aufmarsch.jpg
Normal file
|
After Width: | Height: | Size: 584 KiB |
BIN
docs/port/screenshots/s3/ablauf/02-runde1-mid-kampf.jpg
Normal file
|
After Width: | Height: | Size: 599 KiB |
BIN
docs/port/screenshots/s3/ablauf/03-turm-faellt.jpg
Normal file
|
After Width: | Height: | Size: 536 KiB |
BIN
docs/port/screenshots/s3/ablauf/04-turm-ruine.jpg
Normal file
|
After Width: | Height: | Size: 528 KiB |
BIN
docs/port/screenshots/s3/ablauf/05-grotte-bosskampf.jpg
Normal file
|
After Width: | Height: | Size: 598 KiB |
BIN
docs/port/screenshots/s3/ablauf/06-held-kaempft.jpg
Normal file
|
After Width: | Height: | Size: 615 KiB |
BIN
docs/port/screenshots/s3/ablauf/07-boss-auf-der-lane.jpg
Normal file
|
After Width: | Height: | Size: 567 KiB |
BIN
docs/port/screenshots/s3/ablauf/08-ancient-faellt.jpg
Normal file
|
After Width: | Height: | Size: 612 KiB |
BIN
docs/port/screenshots/s3/ablauf/09-ancient-ruine.jpg
Normal file
|
After Width: | Height: | Size: 612 KiB |
BIN
docs/port/screenshots/s3/ablauf/10-ende-uebersicht.jpg
Normal file
|
After Width: | Height: | Size: 426 KiB |
BIN
docs/port/screenshots/s3/ablauf/11-welle21-uebersicht.jpg
Normal file
|
After Width: | Height: | Size: 581 KiB |
BIN
docs/port/screenshots/s3/ablauf/12-welle21-kampf.jpg
Normal file
|
After Width: | Height: | Size: 638 KiB |
BIN
docs/port/screenshots/s3/ablauf/13-ancient-rot-faellt.jpg
Normal file
|
After Width: | Height: | Size: 591 KiB |
BIN
docs/port/screenshots/s3/ablauf/14-welle-ende.jpg
Normal file
|
After Width: | Height: | Size: 570 KiB |
BIN
docs/port/screenshots/s3/spiel/01-planung-lager-angekuendigt.jpg
Normal file
|
After Width: | Height: | Size: 725 KiB |
BIN
docs/port/screenshots/s3/spiel/02-kampf-um-das-mondlager.jpg
Normal file
|
After Width: | Height: | Size: 699 KiB |
BIN
docs/port/screenshots/s3/spiel/03-nebel-im-kampf.jpg
Normal file
|
After Width: | Height: | Size: 664 KiB |
|
After Width: | Height: | Size: 716 KiB |
BIN
docs/port/screenshots/s3/spiel/05-spaeher-tooltip.jpg
Normal file
|
After Width: | Height: | Size: 739 KiB |