Vollständiger, engineunabhängiger Regelkern (Luneraria.Core, ohne UnityEngine): Partie mit sechs Plätzen und zwei Teams, private Planung mit atomarer Übernahme, Gold, Käufe, Aufwertungen, Formation, drei Lanes mit zwei Laneturmen und zwei Basistürmen je Team, Ancients, unbegrenzte Wellen, Helden mit Stufen, Items und Talenten, Angriffschampions, Bossgrotte mit Anspruch, Entsendung, Kopfgeld und dreirundiger Sperre, Bots und Siegbedingung (nur Ancient-Fall). Serverautoritative Befehlsschnittstelle. - Deterministisch: fester Takt, geordnete Maps, fortlaufende IDs, kein Zufall, keine Uhr, keine Threads - Tabellen einmal aus Godot erzeugt (tools/port/gen_content.py) - Golden-Referenzen aus Godot (tools/godot-golden): 19 Szenarien, 120 Snapshots, 51.221 Werte, Abweichung 0 (Toleranzen dokumentiert) - Tests: content 75, core 91, m2 73, golden 157, determinism 6 = 402/402 - Leistung (M5): Simulationsschritt 0,259 ms statt 1,587 ms in GDScript - Referenzfehler R1 im Bot-Gedächtnis bewusst übernommen und dokumentiert - Geplante Helden (Lucy, Ghaliga, Siegfried, Feena) im Datenmodell, inaktiv - Doku unter docs/port (U1-RULES, PORT-STATUS, PORT-QA, U2 bis U5) Unity-Editor-Lauf offen: Die Unity-Lizenz ist noch nicht aktiviert; gebaut und getestet mit dem .NET 8 SDK auf Unitys Sprachstand (C# 9, .NET Standard 2.1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
70 lines
2.9 KiB
C#
70 lines
2.9 KiB
C#
namespace Luneraria.Core
|
|
{
|
|
/// <summary>
|
|
/// Every tunable number of Champions of Luneraria (reference: lune_balance.gd with
|
|
/// data/luneraria/balance_default.tres). Tests may use variants; bots never get extras.
|
|
/// </summary>
|
|
public sealed class LuneBalance
|
|
{
|
|
// Simulation
|
|
/// <summary>Fixed combat step in seconds (20 steps per second of combat time).</summary>
|
|
public double SimStep = 0.05;
|
|
/// <summary>Ends only the current combat phase, never the match.</summary>
|
|
public double CombatTimeLimit = 180.0;
|
|
public double MarchSpeedFactor = 1.6;
|
|
public double AggroRadius = 7.0;
|
|
/// <summary>Targets further away than this are dropped and re-acquired.</summary>
|
|
public double LeashRadius = 10.0;
|
|
public double LaneHalfWidth = 2.6;
|
|
|
|
// Economy
|
|
public int StartGold = 220;
|
|
public int BaseIncome = 70;
|
|
public int IncomePerRound = 4;
|
|
public int IncomeGrowthCap = 80;
|
|
public int SupplyCap = 12;
|
|
public double SellRefund = 0.75;
|
|
/// <summary>Share of lane kill gold for the lane player; the rest splits evenly in the team.</summary>
|
|
public double LaneShare = 0.5;
|
|
|
|
// Waves
|
|
public int WaveBaseCount = 3;
|
|
/// <summary>One more monster per lane every N rounds, up to WaveMaxCount.</summary>
|
|
public int WaveCountEvery = 3;
|
|
public int WaveMaxCount = 7;
|
|
public double WaveHpGrowth = 0.11;
|
|
public double WaveDamageGrowth = 0.07;
|
|
public double WaveGrowthQuadratic = 0.0015;
|
|
public double MonsterBountyScale = 2.0;
|
|
public double BountyGrowth = 0.04;
|
|
/// <summary>Monster types in rotation order; later indices unlock later.</summary>
|
|
public string[] MonsterPool = { "e01", "e02", "e04", "e03", "e06", "e05" };
|
|
|
|
// Buildings
|
|
public double TowerOuterHp = 6000.0;
|
|
public double TowerInnerHp = 7500.0;
|
|
public double BaseTowerHp = 9000.0;
|
|
public double CoreHp = 12000.0;
|
|
public double TowerDamage = 90.0;
|
|
public double BaseTowerDamage = 120.0;
|
|
/// <summary>Must exceed the longest unit reach (6.5 m + building radius).</summary>
|
|
public double TowerRange = 8.6;
|
|
public double TowerAttackInterval = 1.0;
|
|
public double BuildingRadius = 1.3;
|
|
public int BountyOuterTower = 150;
|
|
public int BountyInnerTower = 210;
|
|
public int BountyBaseTower = 270;
|
|
|
|
// Map
|
|
public double InnerTowerFraction = 0.17;
|
|
public double OuterTowerFraction = 0.35;
|
|
public double TowerSideOffset = 3.4;
|
|
|
|
public static LuneBalance Default() { return new LuneBalance(); }
|
|
|
|
public int RoundIncome(int roundNumber)
|
|
{
|
|
return BaseIncome + GdMath.Min(IncomeGrowthCap, IncomePerRound * GdMath.Max(0, roundNumber - 1));
|
|
}
|
|
}
|
|
}
|