S4-07 process 1

This commit is contained in:
SepComet
2026-03-11 10:18:14 +08:00
parent 52f9e212b9
commit 9de2e50262
32 changed files with 803 additions and 194 deletions
+204 -3
View File
@@ -1,7 +1,9 @@
using Components;
using GeometryTD.DataTable;
using GeometryTD.Definition;
using GeometryTD.Entity;
using GeometryTD.Entity.EntityData;
using GeometryTD.CustomUtility;
using NUnit.Framework;
using UnityEngine;
@@ -47,6 +49,47 @@ namespace GeometryTD.Tests.EditMode
Assert.That(lowHealthHit.FinalDamage, Is.EqualTo(150));
Assert.That(highHealthHit.FinalDamage, Is.EqualTo(100));
}
[Test]
public void ResolveBeforeHit_Shatter_OnlyTriggersOnSlowedTarget()
{
AttackPayload attackPayload = new AttackPayload
{
BaseDamage = 100,
AttackPropertyType = AttackPropertyType.Physics,
TagRuntimes = new[]
{
new TagRuntimeData { TagType = TagType.Shatter, TotalStack = 2 }
}
};
HitContext slowedHit = TagEffectResolver.ResolveBeforeHit(attackPayload, 100, 100, true);
HitContext normalHit = TagEffectResolver.ResolveBeforeHit(attackPayload, 100, 100, false);
Assert.That(slowedHit.FinalDamage, Is.EqualTo(150));
Assert.That(normalHit.FinalDamage, Is.EqualTo(100));
}
[Test]
public void ResolveBeforeHit_Shatter_CanStackWithOtherNumericTags()
{
AttackPayload attackPayload = new AttackPayload
{
BaseDamage = 100,
AttackPropertyType = AttackPropertyType.Physics,
TagRuntimes = new[]
{
new TagRuntimeData { TagType = TagType.Crit, TotalStack = 1 },
new TagRuntimeData { TagType = TagType.Execution, TotalStack = 1 },
new TagRuntimeData { TagType = TagType.Shatter, TotalStack = 1 }
}
};
HitContext hitContext = TagEffectResolver.ResolveBeforeHit(attackPayload, 30, 100, true, 0.05f);
Assert.That(hitContext.IsCriticalHit, Is.True);
Assert.That(hitContext.FinalDamage, Is.EqualTo(281));
}
}
public sealed class EnemyTagStatusRuntimeTests
@@ -124,6 +167,101 @@ namespace GeometryTD.Tests.EditMode
Assert.That(runtime.GetMoveSpeedMultiplier(), Is.EqualTo(1f).Within(0.001f));
}
[Test]
public void ApplyAfterHit_FireWithInferno_IncreasesBurnDamageAndDuration()
{
EnemyTagStatusRuntime runtime = new EnemyTagStatusRuntime();
AttackPayload attackPayload = new AttackPayload
{
BaseDamage = 100,
TagRuntimes = new[]
{
new TagRuntimeData { TagType = TagType.Fire, TotalStack = 1 },
new TagRuntimeData { TagType = TagType.Inferno, TotalStack = 1 }
}
};
int totalDamage = 0;
TagEffectResolver.ApplyAfterHit(attackPayload, runtime);
Assert.That(runtime.HasStatus(TagType.Fire), Is.True);
Assert.That(runtime.HasStatus(TagType.Inferno), Is.False);
runtime.Tick(1f, damage => totalDamage += damage);
runtime.Tick(1f, damage => totalDamage += damage);
runtime.Tick(1f, damage => totalDamage += damage);
runtime.Tick(1f, damage => totalDamage += damage);
runtime.Tick(1f, damage => totalDamage += damage);
Assert.That(totalDamage, Is.EqualTo(200));
Assert.That(runtime.HasStatus(TagType.Fire), Is.False);
}
[Test]
public void ApplyAfterHit_InfernoWithoutFire_DoesNotCreateStatus()
{
EnemyTagStatusRuntime runtime = new EnemyTagStatusRuntime();
AttackPayload attackPayload = new AttackPayload
{
BaseDamage = 100,
TagRuntimes = new[]
{
new TagRuntimeData { TagType = TagType.Inferno, TotalStack = 1 }
}
};
TagEffectResolver.ApplyAfterHit(attackPayload, runtime);
Assert.That(runtime.HasStatus(TagType.Fire), Is.False);
Assert.That(runtime.HasStatus(TagType.Inferno), Is.False);
}
[Test]
public void ApplyAfterHit_IceWithAbsoluteZero_IncreasesSlowStrengthAndDuration()
{
EnemyTagStatusRuntime runtime = new EnemyTagStatusRuntime();
AttackPayload attackPayload = new AttackPayload
{
BaseDamage = 100,
TagRuntimes = new[]
{
new TagRuntimeData { TagType = TagType.Ice, TotalStack = 2 },
new TagRuntimeData { TagType = TagType.AbsoluteZero, TotalStack = 1 }
}
};
TagEffectResolver.ApplyAfterHit(attackPayload, runtime);
Assert.That(runtime.HasStatus(TagType.Ice), Is.True);
Assert.That(runtime.HasStatus(TagType.AbsoluteZero), Is.False);
Assert.That(runtime.GetMoveSpeedMultiplier(), Is.EqualTo(0.5f).Within(0.001f));
runtime.Tick(2.5f, null);
Assert.That(runtime.HasStatus(TagType.Ice), Is.True);
runtime.Tick(0.5f, null);
Assert.That(runtime.HasStatus(TagType.Ice), Is.False);
Assert.That(runtime.GetMoveSpeedMultiplier(), Is.EqualTo(1f).Within(0.001f));
}
[Test]
public void ApplyAfterHit_AbsoluteZeroWithoutIce_DoesNotCreateStatus()
{
EnemyTagStatusRuntime runtime = new EnemyTagStatusRuntime();
AttackPayload attackPayload = new AttackPayload
{
BaseDamage = 100,
TagRuntimes = new[]
{
new TagRuntimeData { TagType = TagType.AbsoluteZero, TotalStack = 1 }
}
};
TagEffectResolver.ApplyAfterHit(attackPayload, runtime);
Assert.That(runtime.HasStatus(TagType.Ice), Is.False);
Assert.That(runtime.HasStatus(TagType.AbsoluteZero), Is.False);
}
[Test]
public void Tick_OnlyUpdatesActivatedStatusTags()
{
@@ -177,21 +315,84 @@ namespace GeometryTD.Tests.EditMode
}
[Test]
public void Definitions_Keep_Unimplemented_Tags_As_Explicit_NoOpPlaceholders()
public void Definitions_Mark_FirstBatch_SevenTags_AsImplemented()
{
Assert.That(TagConfigRegistry.TryGetDefinition(TagType.Shatter, out TagDefinitionData shatter), Is.True);
Assert.That(shatter.Config, Is.TypeOf<ShatterTagConfig>());
Assert.That(((ShatterTagConfig)shatter.Config).IsImplemented, Is.False);
Assert.That(((ShatterTagConfig)shatter.Config).IsImplemented, Is.True);
Assert.That(TagConfigRegistry.TryGetDefinition(TagType.Inferno, out TagDefinitionData inferno), Is.True);
Assert.That(inferno.Config, Is.TypeOf<InfernoTagConfig>());
Assert.That(((InfernoTagConfig)inferno.Config).IsImplemented, Is.False);
Assert.That(((InfernoTagConfig)inferno.Config).IsImplemented, Is.True);
Assert.That(TagConfigRegistry.TryGetDefinition(TagType.AbsoluteZero, out TagDefinitionData absoluteZero), Is.True);
Assert.That(absoluteZero.Config, Is.TypeOf<AbsoluteZeroTagConfig>());
Assert.That(((AbsoluteZeroTagConfig)absoluteZero.Config).IsImplemented, Is.True);
Assert.That(TagConfigRegistry.TryGetDefinition(TagType.Pierce, out TagDefinitionData pierce), Is.True);
Assert.That(pierce.Config, Is.TypeOf<PierceTagConfig>());
Assert.That(((PierceTagConfig)pierce.Config).IsImplemented, Is.False);
}
[Test]
public void LoadFromRows_Overrides_TriggerPhase_And_ConfigValues()
{
DRTagConfig fireRow = new DRTagConfig();
bool parsed = fireRow.ParseDataRow("\t1\t元素\tFire\tOnAfterHit\t火焰测试描述\t{\"BurnDurationSeconds\":4,\"BurnDamagePerSecondPerStack\":25,\"MaxEffectiveStack\":3}", null);
Assert.That(parsed, Is.True);
TagConfigRegistry.LoadFromRows(new[] { fireRow });
Assert.That(TagConfigRegistry.TryGetDefinition(TagType.Fire, out TagDefinitionData fire), Is.True);
Assert.That(fire.TriggerPhase, Is.EqualTo(TagTriggerPhase.OnAfterHit));
Assert.That(fire.Description, Is.EqualTo("火焰测试描述"));
Assert.That(fire.Config, Is.TypeOf<FireTagConfig>());
FireTagConfig config = (FireTagConfig)fire.Config;
Assert.That(config.BurnDurationSeconds, Is.EqualTo(4f).Within(0.001f));
Assert.That(config.BurnDamagePerSecondPerStack, Is.EqualTo(25f).Within(0.001f));
Assert.That(config.MaxEffectiveStack, Is.EqualTo(3));
TagConfigRegistry.ResetToDefaults();
}
[Test]
public void BuildTagDescriptionText_Uses_Registry_Descriptions()
{
DRTagConfig fireRow = new DRTagConfig();
DRTagConfig shatterRow = new DRTagConfig();
Assert.That(fireRow.ParseDataRow("\t1\t元素\tFire\tOnAfterHit\t持续燃烧\t{\"BurnDurationSeconds\":3,\"BurnDamagePerSecondPerStack\":20,\"MaxEffectiveStack\":5}", null), Is.True);
Assert.That(shatterRow.ParseDataRow("\t7\t控制\tShatter\tOnBeforeHit\t对减速目标增伤\t{\"RequiresSlowedTarget\":true,\"DamageBonusPerStack\":0.25}", null), Is.True);
TagConfigRegistry.LoadFromRows(new[] { fireRow, shatterRow });
string description = TagDisplayUtility.BuildTagDescriptionText(new[] { TagType.Fire, TagType.Shatter });
Assert.That(description, Does.Contain("持续燃烧"));
Assert.That(description, Does.Contain("对减速目标增伤"));
TagConfigRegistry.ResetToDefaults();
}
[Test]
public void BuildTagDescriptionText_FromTagRuntimes_Preserves_StackText()
{
DRTagConfig iceRow = new DRTagConfig();
Assert.That(iceRow.ParseDataRow("\t5\t控制\tIce\tOnAfterHit\t命中附加减速\t{\"SlowDurationSeconds\":2,\"SlowRatioPerStack\":0.2,\"MinMoveSpeedMultiplier\":0.4}", null), Is.True);
TagConfigRegistry.LoadFromRows(new[] { iceRow });
string description = TagDisplayUtility.BuildTagDescriptionText(new[]
{
new TagRuntimeData { TagType = TagType.Ice, TotalStack = 2 }
});
Assert.That(description, Does.Contain("Ice x2"));
Assert.That(description, Does.Contain("命中附加减速"));
TagConfigRegistry.ResetToDefaults();
}
[Test]
public void AttackShape_Placeholders_Are_Routable_Without_Runtime_Effect()
{