Implement passive relics and six-family defense towers
This commit is contained in:
@@ -151,6 +151,344 @@ namespace BumpCombat.PlayModeTests
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DefensePrototype_DefaultBuildsCanDamageTheirPortalLanes()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
DefensePrototypeController controller = DefensePrototypeController.Instance;
|
||||
PlayerController player = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
MovePlayerNear(player, controller.Tuning.GetBuildPadPosition(0));
|
||||
Assert.That(controller.TryBuildTowerAtPad(0), Is.True);
|
||||
MovePlayerNear(player, controller.Tuning.GetBuildPadPosition(1));
|
||||
Assert.That(controller.TryBuildTowerAtPad(1), Is.True);
|
||||
DefenseTower upper = FindTower(0, DefenseTowerKind.Summon);
|
||||
DefenseTower lower = FindTower(1, DefenseTowerKind.Direct);
|
||||
Assert.That(upper, Is.Not.Null, "Upper portal is immune to fire.");
|
||||
Assert.That(lower, Is.Not.Null, "Lower portal is immune to Summon.");
|
||||
|
||||
yield return WaitForRouteAgents(2);
|
||||
DefenseRouteAgent upperAgent = FindAgentWithImmunity(DefenseTowerKind.Direct);
|
||||
DefenseRouteAgent lowerAgent = FindAgentWithImmunity(DefenseTowerKind.Summon);
|
||||
yield return WaitForAgentReady(upperAgent);
|
||||
yield return WaitForAgentReady(lowerAgent);
|
||||
FreezeEnemyControllers(FindRouteAgents());
|
||||
float upperHealth = upperAgent.Enemy.CurrentHealth;
|
||||
float lowerHealth = lowerAgent.Enemy.CurrentHealth;
|
||||
Assert.That(upper.TryAttack(upperAgent), Is.True);
|
||||
Assert.That(lowerAgent.Enemy.TryReposition(lower.transform.position), Is.True);
|
||||
Assert.That(lower.TryPulse(), Is.True);
|
||||
Assert.That(upperAgent.Enemy.CurrentHealth, Is.LessThan(upperHealth));
|
||||
Assert.That(lowerAgent.Enemy.CurrentHealth, Is.LessThan(lowerHealth));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DefensePrototype_AllSixTowersShowTheirGameplayRanges()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
DefensePrototypeController controller = DefensePrototypeController.Instance;
|
||||
PlayerController player = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
Assert.That(controller.TryAwardBondLedgerCurrency(200), Is.True);
|
||||
DefenseTowerKind[] kinds =
|
||||
{
|
||||
DefenseTowerKind.Direct, DefenseTowerKind.Summon,
|
||||
DefenseTowerKind.Lightning, DefenseTowerKind.Cold,
|
||||
DefenseTowerKind.Seismic, DefenseTowerKind.Empowering,
|
||||
};
|
||||
for (int pad = 0; pad < kinds.Length; pad++)
|
||||
{
|
||||
DefenseTower tower = BuildTower(controller, player, pad, kinds[pad]);
|
||||
Transform range = tower.transform.Find("Effect Range");
|
||||
Assert.That(range, Is.Not.Null, $"{kinds[pad]} range is missing.");
|
||||
LineRenderer line = range.GetComponent<LineRenderer>();
|
||||
Assert.That(line, Is.Not.Null);
|
||||
Assert.That(line.positionCount, Is.GreaterThan(16));
|
||||
float expected = kinds[pad] == DefenseTowerKind.Summon
|
||||
? controller.Tuning.SummonAreaRadius
|
||||
: kinds[pad] == DefenseTowerKind.Empowering
|
||||
? controller.Tuning.SupportRadius : controller.Tuning.TowerRange;
|
||||
Assert.That(line.GetPosition(0).x * tower.transform.lossyScale.x,
|
||||
Is.EqualTo(expected).Within(0.02f));
|
||||
}
|
||||
|
||||
DefenseTower fire = FindTower(0, DefenseTowerKind.Direct);
|
||||
MovePlayerNear(player, fire.transform.position);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(0, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(0, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(0, DefenseTowerBranch.Second), Is.True);
|
||||
LineRenderer fireRange = fire.transform.Find("Effect Range")
|
||||
.GetComponent<LineRenderer>();
|
||||
Assert.That(fireRange.GetPosition(0).x * fire.transform.lossyScale.x,
|
||||
Is.EqualTo(controller.Tuning.TowerRange * 0.5f).Within(0.02f));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DefensePrototype_DamageTowersShowSuccessfulAttackEffects()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
DefensePrototypeController controller = DefensePrototypeController.Instance;
|
||||
PlayerController player = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
Assert.That(controller.TryAwardBondLedgerCurrency(200), Is.True);
|
||||
yield return WaitForRouteAgents(2);
|
||||
DefenseRouteAgent target = FindAgentWithImmunity(DefenseTowerKind.Summon);
|
||||
yield return WaitForAgentReady(target);
|
||||
FreezeEnemyControllers(FindRouteAgents());
|
||||
|
||||
DefenseTowerKind[] kinds =
|
||||
{
|
||||
DefenseTowerKind.Direct, DefenseTowerKind.Lightning,
|
||||
DefenseTowerKind.Cold, DefenseTowerKind.Seismic,
|
||||
};
|
||||
for (int i = 0; i < kinds.Length; i++)
|
||||
{
|
||||
DefenseTower tower = BuildTower(controller, player, i, kinds[i]);
|
||||
Assert.That(target.Enemy.TryReposition(tower.transform.position), Is.True);
|
||||
Physics2D.SyncTransforms();
|
||||
Assert.That(tower.TryPulse(), Is.True, $"{kinds[i]} should attack.");
|
||||
GameObject effect = GameObject.Find($"{kinds[i]} Attack Effect");
|
||||
Assert.That(effect, Is.Not.Null, $"{kinds[i]} attack effect is missing.");
|
||||
SpriteRenderer impact = effect.transform.Find("Impact Sprite")
|
||||
?.GetComponent<SpriteRenderer>();
|
||||
Assert.That(impact, Is.Not.Null);
|
||||
Assert.That(impact.sprite, Is.Not.Null,
|
||||
"The placeholder impact must be replaceable by an imported sprite.");
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DefensePrototype_TowerAutomaticallyAttacksTargetInRange()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
DefensePrototypeController controller = DefensePrototypeController.Instance;
|
||||
PlayerController player = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
DefenseTower fire = BuildTower(controller, player, 1, DefenseTowerKind.Direct);
|
||||
yield return WaitForRouteAgents(2);
|
||||
DefenseRouteAgent target = FindAgentWithImmunity(DefenseTowerKind.Summon);
|
||||
yield return WaitForAgentReady(target);
|
||||
FreezeEnemyControllers(FindRouteAgents());
|
||||
Assert.That(target.Enemy.TryReposition(
|
||||
(Vector2)fire.transform.position + Vector2.left), Is.True);
|
||||
Physics2D.SyncTransforms();
|
||||
|
||||
float health = target.Enemy.CurrentHealth;
|
||||
bool effectSeen = false;
|
||||
float deadline = Time.realtimeSinceStartup + 2f;
|
||||
while (Time.realtimeSinceStartup < deadline
|
||||
&& (target.Enemy.CurrentHealth >= health || !effectSeen))
|
||||
{
|
||||
yield return null;
|
||||
effectSeen |= GameObject.Find("Direct Attack Effect") != null;
|
||||
}
|
||||
|
||||
Assert.That(target.Enemy.CurrentHealth, Is.LessThan(health),
|
||||
"Tower Update must acquire and damage a nonimmune route enemy.");
|
||||
Assert.That(effectSeen, Is.True,
|
||||
"An automatic attack must show the same effect as a manual pulse.");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DefensePrototype_SummonPlaysExistingAttackSpriteOnHit()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
DefensePrototypeController controller = DefensePrototypeController.Instance;
|
||||
PlayerController player = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
DefenseTower summon = BuildTower(
|
||||
controller, player, 0, DefenseTowerKind.Summon);
|
||||
yield return WaitForRouteAgents(2);
|
||||
DefenseRouteAgent target = FindAgentWithImmunity(DefenseTowerKind.Direct);
|
||||
yield return WaitForAgentReady(target);
|
||||
FreezeEnemyControllers(FindRouteAgents());
|
||||
DefenseSummonUnit unit = summon.GetComponentInChildren<DefenseSummonUnit>();
|
||||
Assert.That(unit, Is.Not.Null);
|
||||
Assert.That(target.Enemy.TryReposition(unit.transform.position), Is.True);
|
||||
Physics2D.SyncTransforms();
|
||||
|
||||
bool attackSpriteSeen = false;
|
||||
bool effectSeen = false;
|
||||
float deadline = Time.realtimeSinceStartup + 2f;
|
||||
while (Time.realtimeSinceStartup < deadline
|
||||
&& (!attackSpriteSeen || !effectSeen))
|
||||
{
|
||||
yield return null;
|
||||
Sprite sprite = unit.GetComponent<SpriteRenderer>().sprite;
|
||||
attackSpriteSeen |= sprite != null
|
||||
&& sprite.name.Contains("BumpAttack");
|
||||
effectSeen |= GameObject.Find("Summon Attack Effect") != null;
|
||||
}
|
||||
Assert.That(attackSpriteSeen, Is.True,
|
||||
"The summoned swordsman must play the existing attack sheet.");
|
||||
Assert.That(effectSeen, Is.True,
|
||||
"A successful summon hit must show its impact.");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DefensePrototype_AllSixFamiliesBuildAndUpgradeToDistinctFinalBranches()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
DefensePrototypeController controller = DefensePrototypeController.Instance;
|
||||
PlayerController player = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
Assert.That(controller.TryAwardBondLedgerCurrency(1000), Is.True);
|
||||
DefenseTowerKind[] kinds =
|
||||
{
|
||||
DefenseTowerKind.Direct,
|
||||
DefenseTowerKind.Summon,
|
||||
DefenseTowerKind.Lightning,
|
||||
DefenseTowerKind.Cold,
|
||||
DefenseTowerKind.Seismic,
|
||||
DefenseTowerKind.Empowering,
|
||||
};
|
||||
|
||||
for (int pad = 0; pad < kinds.Length; pad++)
|
||||
{
|
||||
DefenseTower tower = BuildTower(controller, player, pad, kinds[pad]);
|
||||
Assert.That(tower.Tier, Is.EqualTo(1));
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(
|
||||
pad, DefenseTowerBranch.First), Is.False);
|
||||
int beforeUpgrade = controller.ConstructionCurrency;
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(
|
||||
pad, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(tower.Tier, Is.EqualTo(2));
|
||||
Assert.That(controller.ConstructionCurrency,
|
||||
Is.EqualTo(beforeUpgrade - controller.Tuning.Tier2UpgradeCost));
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(
|
||||
pad, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(tower.Tier, Is.EqualTo(3));
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(
|
||||
pad, DefenseTowerBranch.None), Is.False);
|
||||
DefenseTowerBranch branch = pad % 2 == 0
|
||||
? DefenseTowerBranch.First : DefenseTowerBranch.Second;
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(pad, branch), Is.True);
|
||||
Assert.That(tower.Tier, Is.EqualTo(4));
|
||||
Assert.That(tower.Branch, Is.EqualTo(branch));
|
||||
Assert.That(DefenseTower.GetBranchName(kinds[pad], branch),
|
||||
Is.Not.Empty);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(
|
||||
pad, DefenseTowerBranch.First), Is.False);
|
||||
tower.enabled = false;
|
||||
}
|
||||
|
||||
Assert.That(FindTowers().Length, Is.EqualTo(6));
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator DefensePrototype_SentinelAndScoutHaveDifferentUnitCounts()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
DefensePrototypeController controller = DefensePrototypeController.Instance;
|
||||
PlayerController player = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
Assert.That(controller.TryAwardBondLedgerCurrency(500), Is.True);
|
||||
DefenseTower sentinel = BuildTower(controller, player, 0,
|
||||
DefenseTowerKind.Summon);
|
||||
DefenseTower scout = BuildTower(controller, player, 1,
|
||||
DefenseTowerKind.Summon);
|
||||
|
||||
Assert.That(player.TryReposition(sentinel.transform.position), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(0, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(0, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(0, DefenseTowerBranch.First), Is.True);
|
||||
Assert.That(player.TryReposition(scout.transform.position), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(1, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(1, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(1, DefenseTowerBranch.Second), Is.True);
|
||||
yield return null;
|
||||
|
||||
Assert.That(sentinel.GetComponentsInChildren<DefenseSummonUnit>().Length,
|
||||
Is.EqualTo(1));
|
||||
Assert.That(scout.GetComponentsInChildren<DefenseSummonUnit>().Length,
|
||||
Is.EqualTo(6));
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator DefensePrototype_SmotheringBoostsTowerDamageInsideSupportAura()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
DefensePrototypeController controller = DefensePrototypeController.Instance;
|
||||
PlayerController player = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
Assert.That(controller.TryAwardBondLedgerCurrency(200), Is.True);
|
||||
yield return WaitForRouteAgents(2);
|
||||
DefenseRouteAgent target = FindAgentWithImmunity(DefenseTowerKind.Summon);
|
||||
Assert.That(target, Is.Not.Null);
|
||||
yield return WaitForAgentReady(target);
|
||||
FreezeEnemyControllers(FindRouteAgents());
|
||||
|
||||
DefenseTower fire = BuildTower(controller, player, 0, DefenseTowerKind.Direct);
|
||||
DefenseTower support = BuildTower(controller, player, 4,
|
||||
DefenseTowerKind.Empowering);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(4, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(4, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(4, DefenseTowerBranch.Second), Is.True);
|
||||
Assert.That(target.Enemy.TryReposition(support.transform.position), Is.True);
|
||||
|
||||
float health = target.Enemy.CurrentHealth;
|
||||
Assert.That(controller.TryApplyTowerDamage(fire, target, 10f), Is.True);
|
||||
float expected = BumpCombat.Combat.DamageCalculator.FinalizeDamage(
|
||||
10f * (1f + controller.Tuning.SupportDamageBonusPerTier * 4)
|
||||
* (1f + controller.Tuning.SmotheringDamageBonus));
|
||||
Assert.That(health - target.Enemy.CurrentHealth,
|
||||
Is.EqualTo(expected).Within(0.01f));
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator DefensePrototype_EnemyDeathAwardsConstructionCurrencyOnceArrivalDoesNot()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
DefensePrototypeController controller = DefensePrototypeController.Instance;
|
||||
PlayerController player = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
DefenseTower fire = BuildTower(controller, player, 0, DefenseTowerKind.Direct);
|
||||
fire.enabled = false;
|
||||
MovePlayerNear(player, Vector2.zero);
|
||||
yield return WaitForRouteAgents(2);
|
||||
DefenseRouteAgent killTarget = FindAgentWithImmunity(DefenseTowerKind.Summon);
|
||||
DefenseRouteAgent arrivalTarget = FindAgentWithImmunity(DefenseTowerKind.Direct);
|
||||
Assert.That(killTarget, Is.Not.Null);
|
||||
Assert.That(arrivalTarget, Is.Not.Null);
|
||||
yield return WaitForAgentReady(killTarget);
|
||||
yield return WaitForAgentReady(arrivalTarget);
|
||||
FreezeEnemyControllers(FindRouteAgents());
|
||||
|
||||
int currency = controller.ConstructionCurrency;
|
||||
Assert.That(controller.TryApplyTowerDamage(fire, killTarget, 10000f), Is.True);
|
||||
Assert.That(killTarget.Enemy.IsDead, Is.True);
|
||||
Assert.That(controller.ConstructionCurrency,
|
||||
Is.EqualTo(currency + controller.Tuning.EnemyKillCurrency));
|
||||
Assert.That(controller.TryApplyTowerDamage(fire, killTarget, 10000f), Is.False);
|
||||
Assert.That(controller.ConstructionCurrency,
|
||||
Is.EqualTo(currency + controller.Tuning.EnemyKillCurrency));
|
||||
|
||||
DriveAgentToArrival(arrivalTarget);
|
||||
Assert.That(controller.ConstructionCurrency,
|
||||
Is.EqualTo(currency + controller.Tuning.EnemyKillCurrency));
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator DefensePrototype_ColdSeismicAndImbuingHaveCombatEffects()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
DefensePrototypeController controller = DefensePrototypeController.Instance;
|
||||
PlayerController player = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
Assert.That(controller.TryAwardBondLedgerCurrency(500), Is.True);
|
||||
yield return WaitForRouteAgents(2);
|
||||
DefenseRouteAgent target = FindAgentWithImmunity(DefenseTowerKind.Direct);
|
||||
Assert.That(target, Is.Not.Null);
|
||||
yield return WaitForAgentReady(target);
|
||||
FreezeEnemyControllers(FindRouteAgents());
|
||||
|
||||
DefenseTower cold = BuildTower(controller, player, 2, DefenseTowerKind.Cold);
|
||||
DefenseTower support = BuildTower(controller, player, 5,
|
||||
DefenseTowerKind.Empowering);
|
||||
Assert.That(target.Enemy.TryReposition(cold.transform.position), Is.True);
|
||||
float health = target.Enemy.CurrentHealth;
|
||||
Assert.That(cold.TryPulse(), Is.True);
|
||||
Assert.That(target.Enemy.CurrentHealth, Is.LessThan(health));
|
||||
Assert.That(target.Enemy.MovementSpeedMultiplier, Is.LessThan(1f));
|
||||
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(5, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(5, DefenseTowerBranch.None), Is.True);
|
||||
Assert.That(controller.TryUpgradeTowerAtPad(5, DefenseTowerBranch.First), Is.True);
|
||||
Assert.That(controller.GetTowerAttackIntervalMultiplier(cold),
|
||||
Is.EqualTo(controller.Tuning.ImbuingAttackIntervalMultiplier));
|
||||
|
||||
DefenseTower seismic = BuildTower(controller, player, 4,
|
||||
DefenseTowerKind.Seismic);
|
||||
Assert.That(target.Enemy.TryReposition(seismic.transform.position), Is.True);
|
||||
Assert.That(seismic.TryPulse(), Is.True);
|
||||
Assert.That(target.Enemy.IsStunned, Is.True);
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator DefensePrototype_TowerDamageUsesSightEfficiencyAndPortalImmunity()
|
||||
{
|
||||
@@ -452,15 +790,14 @@ namespace BumpCombat.PlayModeTests
|
||||
Assert.That(relicReward, Is.Not.Null);
|
||||
Assert.That(relicReward.DebugIsSelectionVisible, Is.True,
|
||||
"Collecting a cleared portal reward must open its passive relic choice.");
|
||||
Assert.That(relicReward.DebugShownCount, Is.EqualTo(3),
|
||||
"The first portal must offer all three phase-five relics.");
|
||||
Assert.That(relicReward.DebugShownPassiveRelicCount, Is.EqualTo(3),
|
||||
"The first portal must offer three eligible relics from the current catalog.");
|
||||
Assert.That(relicReward.DebugChooseOption(0), Is.True);
|
||||
yield return null;
|
||||
Assert.That(
|
||||
player.GetComponent<PassiveRelicController>().Owns(
|
||||
PassiveRelicId.TwinHornTalisman),
|
||||
Is.True,
|
||||
"Choosing the first portal option must acquire the shown passive relic.");
|
||||
player.GetComponent<PassiveRelicController>().OwnedCount,
|
||||
Is.EqualTo(1),
|
||||
"Choosing the first portal option must acquire one passive relic.");
|
||||
Assert.That(RunManager.Instance.IsSelectionOpen, Is.False);
|
||||
Assert.That(RunManager.Instance.IsRunCleared, Is.False,
|
||||
"Collecting one portal reward must not finish the two-portal run.");
|
||||
@@ -473,10 +810,12 @@ namespace BumpCombat.PlayModeTests
|
||||
+ controller.Tuning.PortalRewardCurrency * 2));
|
||||
Assert.That(relicReward.DebugIsSelectionVisible, Is.True,
|
||||
"The second cleared portal must offer another passive relic choice.");
|
||||
Assert.That(relicReward.DebugShownCount, Is.EqualTo(2),
|
||||
"A relic already chosen at the first portal must not appear again.");
|
||||
Assert.That(relicReward.DebugShownPassiveRelicCount, Is.EqualTo(3),
|
||||
"The expanded catalog still offers three candidates at the second portal.");
|
||||
Assert.That(relicReward.DebugChooseOption(0), Is.True);
|
||||
yield return null;
|
||||
Assert.That(player.GetComponent<PassiveRelicController>().OwnedCount,
|
||||
Is.EqualTo(2));
|
||||
Assert.That(RunManager.Instance.IsRunCleared, Is.True,
|
||||
"The run clears only after both portal relic choices are resolved.");
|
||||
}
|
||||
@@ -1022,6 +1361,419 @@ namespace BumpCombat.PlayModeTests
|
||||
"A Thunder Crash echo must not grant its manual invulnerability.");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WaveNail_UsesBaseBumpDamageAndDamagesEachEnemyOnce()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.WaveNail), Is.True);
|
||||
Vector2 origin = (Vector2)passiveRelicPlayer.transform.position
|
||||
+ new Vector2(4f, 4f);
|
||||
EnemyController original = CreateRelicTestEnemy(origin, ArtifactColor.Red);
|
||||
EnemyController nearby = CreateRelicTestEnemy(origin + Vector2.right, ArtifactColor.Red);
|
||||
yield return null;
|
||||
original.enabled = false;
|
||||
nearby.enabled = false;
|
||||
GameObject duplicateCollider = new("Wave duplicate collider");
|
||||
duplicateCollider.transform.SetParent(nearby.transform, false);
|
||||
duplicateCollider.AddComponent<CircleCollider2D>().radius = 0.25f;
|
||||
Physics2D.SyncTransforms();
|
||||
|
||||
float before = nearby.CurrentHealth;
|
||||
CombatHitResult hit = new(
|
||||
passiveRelicPlayer.gameObject,
|
||||
original.gameObject,
|
||||
false,
|
||||
HitSide.Front,
|
||||
20f,
|
||||
Vector2.right,
|
||||
0f,
|
||||
origin,
|
||||
baseBumpDamage: 10f);
|
||||
CombatEvents.RaiseValidHit(hit);
|
||||
float expected = DamageCalculator.FinalizeDamage(
|
||||
10f * GameplayConstants.Current.PassiveRelics.WaveNailDamageFraction);
|
||||
Assert.That(nearby.CurrentHealth, Is.EqualTo(before - expected).Within(0.01f));
|
||||
CombatEvents.RaiseValidHit(hit);
|
||||
Assert.That(nearby.CurrentHealth, Is.EqualTo(before - expected).Within(0.01f),
|
||||
"One relic cooldown must cover the next valid hit.");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CapacitorRing_ExcludesOriginalAndLimitsChainToThree()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.CapacitorRing), Is.True);
|
||||
Vector2 origin = (Vector2)passiveRelicPlayer.transform.position
|
||||
+ new Vector2(4f, 4f);
|
||||
EnemyController original = CreateRelicTestEnemy(origin, ArtifactColor.Red);
|
||||
EnemyController[] neighbors = new EnemyController[4];
|
||||
for (int i = 0; i < neighbors.Length; i++)
|
||||
{
|
||||
neighbors[i] = CreateRelicTestEnemy(
|
||||
origin + Vector2.right * (0.5f + i * 0.5f),
|
||||
ArtifactColor.Red);
|
||||
}
|
||||
yield return null;
|
||||
original.enabled = false;
|
||||
foreach (EnemyController neighbor in neighbors) neighbor.enabled = false;
|
||||
Physics2D.SyncTransforms();
|
||||
|
||||
float originalBefore = original.CurrentHealth;
|
||||
float[] before = System.Array.ConvertAll(neighbors, enemy => enemy.CurrentHealth);
|
||||
CombatEvents.RaiseValidHit(new CombatHitResult(
|
||||
passiveRelicPlayer.gameObject,
|
||||
original.gameObject,
|
||||
false,
|
||||
HitSide.Front,
|
||||
10f,
|
||||
Vector2.right,
|
||||
0f,
|
||||
origin,
|
||||
baseBumpDamage: 10f));
|
||||
Assert.That(original.CurrentHealth, Is.EqualTo(originalBefore));
|
||||
float expected = DamageCalculator.FinalizeDamage(
|
||||
10f * GameplayConstants.Current.PassiveRelics.CapacitorRingDamageFraction);
|
||||
for (int i = 0; i < neighbors.Length; i++)
|
||||
{
|
||||
Assert.That(neighbors[i].CurrentHealth,
|
||||
Is.EqualTo(before[i] - (i < 3 ? expected : 0f)).Within(0.01f));
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator EmberWick_AppliesExistingPhoenixIgnite()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.EmberWick), Is.True);
|
||||
Vector2 origin = (Vector2)passiveRelicPlayer.transform.position
|
||||
+ new Vector2(4f, 4f);
|
||||
EnemyController target = CreateRelicTestEnemy(origin, ArtifactColor.Red);
|
||||
yield return null;
|
||||
target.enabled = false;
|
||||
CombatEvents.RaiseValidHit(new CombatHitResult(
|
||||
passiveRelicPlayer.gameObject,
|
||||
target.gameObject,
|
||||
false,
|
||||
HitSide.Front,
|
||||
10f,
|
||||
Vector2.right,
|
||||
0f,
|
||||
origin,
|
||||
baseBumpDamage: 10f));
|
||||
Assert.That(target.IsIgnited, Is.True);
|
||||
ActiveArtifactDefinition phoenix = null;
|
||||
for (int i = 0; i < passiveRelicArtifacts.CatalogCount; i++)
|
||||
{
|
||||
ActiveArtifactDefinition definition = passiveRelicArtifacts.GetCatalogArtifactAt(i);
|
||||
if (definition != null && definition.Effect == ActiveArtifactEffect.Phoenix)
|
||||
{
|
||||
phoenix = definition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert.That(phoenix, Is.Not.Null);
|
||||
Assert.That(target.IgniteRemaining,
|
||||
Is.EqualTo(phoenix.NormalIgniteDuration).Within(0.01f));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator RuptureSeed_TriggersFromDirectRelicAttackKill()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Vector2 origin = (Vector2)passiveRelicPlayer.transform.position + new Vector2(4f, 4f);
|
||||
EnemyController victim = CreateRelicTestEnemy(origin, ArtifactColor.Red);
|
||||
EnemyController neighbor = CreateRelicTestEnemy(origin + Vector2.right, ArtifactColor.Red);
|
||||
yield return null;
|
||||
victim.enabled = false;
|
||||
neighbor.enabled = false;
|
||||
float before = neighbor.CurrentHealth;
|
||||
Assert.That(victim.TryTakeDamage(victim.CurrentHealth + 1f, Vector2.zero,
|
||||
0f, false, false, EnemyDamageSource.PassiveRelicAttack), Is.True);
|
||||
Assert.That(neighbor.CurrentHealth, Is.LessThan(before));
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator EmberCarrier_TransfersRemainingIgniteOnCreditedKill()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(ActiveArtifactEffect.Phoenix);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.EmberCarrier), Is.True);
|
||||
Vector2 origin = (Vector2)passiveRelicPlayer.transform.position + new Vector2(4f, 4f);
|
||||
EnemyController victim = CreateRelicTestEnemy(origin, ArtifactColor.Red);
|
||||
EnemyController neighbor = CreateRelicTestEnemy(origin + Vector2.right, ArtifactColor.Red);
|
||||
yield return null;
|
||||
victim.enabled = false;
|
||||
neighbor.enabled = false;
|
||||
Assert.That(victim.ApplyIgnite(3f, 1f, 2f), Is.True);
|
||||
Assert.That(victim.TryTakeDamage(victim.CurrentHealth + 1f, Vector2.zero, 0f,
|
||||
false, false, EnemyDamageSource.Player), Is.True);
|
||||
Assert.That(neighbor.IsIgnited, Is.True);
|
||||
Assert.That(neighbor.IgniteRemaining, Is.GreaterThan(0f));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator RiftWedge_ThreeOrdinaryHitsApplyExistingVulnerability()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.RiftWedge), Is.True);
|
||||
Vector2 origin = (Vector2)passiveRelicPlayer.transform.position + new Vector2(4f, 4f);
|
||||
EnemyController target = CreateRelicTestEnemy(origin, ArtifactColor.Red);
|
||||
yield return null;
|
||||
target.enabled = false;
|
||||
CombatHitResult hit = new(passiveRelicPlayer.gameObject, target.gameObject,
|
||||
false, HitSide.Front, 1f, Vector2.right, 0f, origin, baseBumpDamage: 1f);
|
||||
CombatEvents.RaiseValidHit(hit);
|
||||
CombatEvents.RaiseValidHit(hit);
|
||||
Assert.That(target.IsBumpVulnerable, Is.False);
|
||||
CombatEvents.RaiseValidHit(hit);
|
||||
Assert.That(target.IsBumpVulnerable, Is.True);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ExecutionerSigil_FinishesLowHealthNonBossAfterOrdinaryHit()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.ExecutionerSigil), Is.True);
|
||||
Vector2 origin = (Vector2)passiveRelicPlayer.transform.position + new Vector2(4f, 4f);
|
||||
EnemyController target = CreateRelicTestEnemy(origin, ArtifactColor.Red);
|
||||
yield return null;
|
||||
target.enabled = false;
|
||||
SetEnemyCurrentHealth(target, target.MaximumHealth * 0.09f);
|
||||
CombatEvents.RaiseValidHit(new CombatHitResult(passiveRelicPlayer.gameObject,
|
||||
target.gameObject, false, HitSide.Front, 1f, Vector2.right, 0f,
|
||||
origin, baseBumpDamage: 1f));
|
||||
Assert.That(target.IsDead, Is.True);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator BackflowHeart_GrantsShieldAfterActualHpLossAndAbsorbsNextHit()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.BackflowHeart), Is.True);
|
||||
PlayerHealth health = passiveRelicPlayer.GetComponent<PlayerHealth>();
|
||||
SetTestField(health, "invulnerableUntil", Time.time - 1f);
|
||||
Assert.That(health.TryTakeDamage(health.MaxHealth * 0.3f,
|
||||
Vector2.right, 0f, fromEnemyAttack: false), Is.True);
|
||||
Assert.That(health.CurrentShield, Is.Zero);
|
||||
SetTestField(health, "invulnerableUntil", Time.time - 1f);
|
||||
Assert.That(health.TryTakeDamage(health.MaxHealth * 0.4f,
|
||||
Vector2.right, 0f), Is.True);
|
||||
Assert.That(health.CurrentShield, Is.GreaterThan(0f));
|
||||
float hpAfter = health.CurrentHealth;
|
||||
SetTestField(health, "invulnerableUntil", Time.time - 1f);
|
||||
Assert.That(health.TryTakeDamage(1f, Vector2.right, 0f), Is.True);
|
||||
Assert.That(health.CurrentHealth, Is.EqualTo(hpAfter));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CounterBell_SlowsNearbyEnemyAfterActualHpLoss()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.CounterBell), Is.True);
|
||||
EnemyController target = CreateRelicTestEnemy(
|
||||
(Vector2)passiveRelicPlayer.transform.position + Vector2.right,
|
||||
ArtifactColor.Red);
|
||||
yield return null;
|
||||
target.enabled = false;
|
||||
PlayerHealth health = passiveRelicPlayer.GetComponent<PlayerHealth>();
|
||||
SetTestField(health, "invulnerableUntil", Time.time - 1f);
|
||||
Assert.That(health.TryTakeDamage(10f, Vector2.right, 0f), Is.True);
|
||||
Assert.That(target.MovementSpeedMultiplier, Is.EqualTo(0.7f).Within(0.001f));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SprintWheel_ConsumesOneChargeOnNextOrdinaryBump()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.SprintWheel), Is.True);
|
||||
Vector2 origin = (Vector2)passiveRelicPlayer.transform.position + new Vector2(4f, 4f);
|
||||
EnemyController original = CreateRelicTestEnemy(origin, ArtifactColor.Red);
|
||||
EnemyController neighbor = CreateRelicTestEnemy(origin + Vector2.right, ArtifactColor.Red);
|
||||
yield return null;
|
||||
original.enabled = false;
|
||||
neighbor.enabled = false;
|
||||
Collider2D playerCollider = passiveRelicPlayer.GetComponent<Collider2D>();
|
||||
float diameter = Mathf.Max(playerCollider.bounds.size.x, playerCollider.bounds.size.y);
|
||||
passiveRelicController.AddVoluntaryMovement(diameter *
|
||||
GameplayConstants.Current.PassiveRelics.SprintWheelRequiredBodyDiameters);
|
||||
CombatHitResult hit = new(passiveRelicPlayer.gameObject, original.gameObject,
|
||||
false, HitSide.Front, 10f, Vector2.right, 0f, origin, baseBumpDamage: 10f);
|
||||
float before = neighbor.CurrentHealth;
|
||||
CombatEvents.RaiseValidHit(hit);
|
||||
Assert.That(neighbor.CurrentHealth, Is.LessThan(before));
|
||||
float after = neighbor.CurrentHealth;
|
||||
CombatEvents.RaiseValidHit(hit);
|
||||
Assert.That(neighbor.CurrentHealth, Is.EqualTo(after));
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator ConditionalRelics_RequireIgniteAndOwnedDamagingArtifact()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
List<ActiveArtifactDefinition> owned = typeof(ActiveArtifactController)
|
||||
.GetField("ownedArtifacts", BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
?.GetValue(passiveRelicArtifacts) as List<ActiveArtifactDefinition>;
|
||||
Assert.That(owned, Is.Not.Null);
|
||||
owned.Clear();
|
||||
Assert.That(passiveRelicController.GetAvailableRelics(),
|
||||
Has.None.EqualTo(PassiveRelicId.EmberCarrier));
|
||||
Assert.That(passiveRelicController.GetAvailableRelics(),
|
||||
Has.None.EqualTo(PassiveRelicId.ResonantCrystal));
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.EmberWick), Is.True);
|
||||
Assert.That(passiveRelicController.GetAvailableRelics(),
|
||||
Has.Some.EqualTo(PassiveRelicId.EmberCarrier));
|
||||
ActiveArtifactDefinition phoenix = null;
|
||||
for (int i = 0; i < passiveRelicArtifacts.CatalogCount; i++)
|
||||
{
|
||||
ActiveArtifactDefinition definition = passiveRelicArtifacts.GetCatalogArtifactAt(i);
|
||||
if (definition != null && definition.Effect == ActiveArtifactEffect.Phoenix)
|
||||
{
|
||||
phoenix = definition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert.That(phoenix, Is.Not.Null);
|
||||
owned.Add(phoenix);
|
||||
Assert.That(passiveRelicController.GetAvailableRelics(),
|
||||
Has.Some.EqualTo(PassiveRelicId.ResonantCrystal));
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator HunterFeather_BoostsMoveSpeedAfterPlayerKill()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.HunterFeather), Is.True);
|
||||
PlayerStats stats = passiveRelicPlayer.GetComponent<PlayerStats>();
|
||||
float before = stats.MoveSpeed;
|
||||
EnemyController victim = CreateRelicTestEnemy(
|
||||
(Vector2)passiveRelicPlayer.transform.position + new Vector2(4f, 4f),
|
||||
ArtifactColor.Red);
|
||||
yield return null;
|
||||
victim.enabled = false;
|
||||
Assert.That(victim.TryTakeDamage(victim.CurrentHealth + 1f, Vector2.zero,
|
||||
0f, false, false, EnemyDamageSource.Player), Is.True);
|
||||
Assert.That(stats.MoveSpeed, Is.GreaterThan(before));
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator BloodFang_HealsOnlyAfterValidHit()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.BloodFang), Is.True);
|
||||
PlayerHealth health = passiveRelicPlayer.GetComponent<PlayerHealth>();
|
||||
SetTestField(health, "<CurrentHealth>k__BackingField", health.MaxHealth - 20f);
|
||||
Vector2 origin = (Vector2)passiveRelicPlayer.transform.position + new Vector2(4f, 4f);
|
||||
EnemyController target = CreateRelicTestEnemy(origin, ArtifactColor.Red);
|
||||
yield return null;
|
||||
target.enabled = false;
|
||||
float before = health.CurrentHealth;
|
||||
CombatEvents.RaiseValidHit(new CombatHitResult(passiveRelicPlayer.gameObject,
|
||||
target.gameObject, true, HitSide.Front, 1f, Vector2.right, 0f,
|
||||
origin, baseBumpDamage: 1f));
|
||||
Assert.That(health.CurrentHealth, Is.GreaterThan(before));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator RecoveryFunnel_RestoresGaugeFromPlayerCreditedKill()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.RecoveryFunnel), Is.True);
|
||||
SetTestField(passiveRelicArtifacts, "<CurrentGauge>k__BackingField", 0f);
|
||||
EnemyController victim = CreateRelicTestEnemy(
|
||||
(Vector2)passiveRelicPlayer.transform.position + new Vector2(4f, 4f),
|
||||
ArtifactColor.Red);
|
||||
yield return null;
|
||||
victim.enabled = false;
|
||||
Assert.That(victim.TryTakeDamage(victim.CurrentHealth + 1f, Vector2.zero,
|
||||
0f, false, false, EnemyDamageSource.Player), Is.True);
|
||||
Assert.That(passiveRelicArtifacts.CurrentGauge, Is.GreaterThan(0f));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator PilgrimPouch_CreatesAtMostOneHealingOrb()
|
||||
{
|
||||
yield return PreparePassiveRelicFixture(null);
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.PilgrimPouch), Is.True);
|
||||
Vector2 origin = (Vector2)passiveRelicPlayer.transform.position + new Vector2(4f, 4f);
|
||||
EnemyController first = CreateRelicTestEnemy(origin, ArtifactColor.Red);
|
||||
EnemyController second = CreateRelicTestEnemy(origin + Vector2.right * 5f,
|
||||
ArtifactColor.Red);
|
||||
yield return null;
|
||||
first.enabled = false;
|
||||
second.enabled = false;
|
||||
Assert.That(first.TryTakeDamage(first.CurrentHealth + 1f, Vector2.zero,
|
||||
0f, false, false, EnemyDamageSource.Player), Is.True);
|
||||
Assert.That(UnityEngine.Object.FindObjectsByType<PassiveRelicHealingOrb>(
|
||||
FindObjectsInactive.Exclude, FindObjectsSortMode.None).Length, Is.EqualTo(1));
|
||||
Assert.That(second.TryTakeDamage(second.CurrentHealth + 1f, Vector2.zero,
|
||||
0f, false, false, EnemyDamageSource.Player), Is.True);
|
||||
Assert.That(UnityEngine.Object.FindObjectsByType<PassiveRelicHealingOrb>(
|
||||
FindObjectsInactive.Exclude, FindObjectsSortMode.None).Length, Is.EqualTo(1));
|
||||
PlayerHealth health = passiveRelicPlayer.GetComponent<PlayerHealth>();
|
||||
SetTestField(health, "<CurrentHealth>k__BackingField", health.MaxHealth - 20f);
|
||||
float hpBefore = health.CurrentHealth;
|
||||
Assert.That(passiveRelicPlayer.TryReposition(origin), Is.True);
|
||||
yield return null;
|
||||
Assert.That(health.CurrentHealth, Is.GreaterThan(hpBefore));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator BattleBaton_BoostsVisibleDamageTowersNotSummons()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
DefensePrototypeController controller = DefensePrototypeController.Instance;
|
||||
PlayerController player = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
Assert.That(controller.TryAwardBondLedgerCurrency(100), Is.True);
|
||||
DefenseTower direct = BuildTower(controller, player, 0, DefenseTowerKind.Direct);
|
||||
DefenseTower summon = BuildTower(controller, player, 1, DefenseTowerKind.Summon);
|
||||
DefenseTower lightning = BuildTower(controller, player, 4,
|
||||
DefenseTowerKind.Lightning);
|
||||
Assert.That(player.TryReposition(summon.transform.position), Is.True);
|
||||
Assert.That(controller.TryBoostVisibleTowers(3f), Is.False,
|
||||
"Only a summon tower is currently within sight.");
|
||||
Assert.That(player.TryReposition(direct.transform.position), Is.True);
|
||||
Assert.That(controller.TryBoostVisibleTowers(3f), Is.True);
|
||||
Dictionary<DefenseTower, float> boosted = typeof(DefensePrototypeController)
|
||||
.GetField("boostedTowers", BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
?.GetValue(controller) as Dictionary<DefenseTower, float>;
|
||||
Assert.That(boosted, Is.Not.Null);
|
||||
Assert.That(boosted.ContainsKey(direct), Is.True);
|
||||
Assert.That(boosted.ContainsKey(lightning), Is.True);
|
||||
Assert.That(boosted.ContainsKey(summon), Is.False);
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator BondLedger_AwardsCurrencyForRecentlyBumpedTowerKill()
|
||||
{
|
||||
yield return StartDefenseRun();
|
||||
passiveRelicPlayer = UnityEngine.Object.FindAnyObjectByType<PlayerController>();
|
||||
passiveRelicController = passiveRelicPlayer.GetComponent<PassiveRelicController>();
|
||||
Assert.That(passiveRelicController.TryAcquire(PassiveRelicId.BondLedger), Is.True);
|
||||
#if UNITY_EDITOR
|
||||
PassiveRelicController.RandomRollForTests = () => 0f;
|
||||
#endif
|
||||
SpawnDirector director = UnityEngine.Object.FindAnyObjectByType<SpawnDirector>();
|
||||
director.enabled = false;
|
||||
EnemyController[] prefabs = typeof(SpawnDirector).GetField("enemyPrefabs",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(director) as EnemyController[];
|
||||
Assert.That(prefabs, Is.Not.Null);
|
||||
foreach (EnemyController prefab in prefabs)
|
||||
{
|
||||
if (prefab != null && prefab.Definition != null
|
||||
&& prefab.Definition.Kind == EnemyKind.Skeleton)
|
||||
{
|
||||
passiveRelicEnemyPrefab = prefab;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert.That(passiveRelicEnemyPrefab, Is.Not.Null);
|
||||
Vector2 origin = (Vector2)passiveRelicPlayer.transform.position + new Vector2(4f, 4f);
|
||||
EnemyController victim = CreateRelicTestEnemy(origin, ArtifactColor.Red);
|
||||
yield return null;
|
||||
victim.enabled = false;
|
||||
CombatEvents.RaiseValidHit(new CombatHitResult(passiveRelicPlayer.gameObject,
|
||||
victim.gameObject, false, HitSide.Front, 1f, Vector2.right, 0f,
|
||||
origin, baseBumpDamage: 1f));
|
||||
int before = DefensePrototypeController.Instance.ConstructionCurrency;
|
||||
Assert.That(victim.TryTakeDamage(victim.CurrentHealth + 1f, Vector2.zero,
|
||||
0f, false, false, EnemyDamageSource.Tower), Is.True);
|
||||
Assert.That(DefensePrototypeController.Instance.ConstructionCurrency,
|
||||
Is.EqualTo(before + 1));
|
||||
}
|
||||
private PassiveRelicController passiveRelicController;
|
||||
private ActiveArtifactController passiveRelicArtifacts;
|
||||
private PlayerController passiveRelicPlayer;
|
||||
|
||||
Reference in New Issue
Block a user