158 lines
7.4 KiB
C#
158 lines
7.4 KiB
C#
using System.Collections;
|
|
using System.Linq;
|
|
using BumpCombat.Combat;
|
|
using BumpCombat.Constants;
|
|
using BumpCombat.Defense;
|
|
using BumpCombat.Defense.Comparison;
|
|
using BumpCombat.Player;
|
|
using BumpCombat.Progression;
|
|
using NUnit.Framework;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.TestTools;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace BumpCombat.Tests
|
|
{
|
|
public sealed class Defense25DComparisonPresentationPlayModeTests
|
|
{
|
|
private Defense25DComparison world;
|
|
private Defense25DComparisonSettings settings;
|
|
private float previousTimeScale;
|
|
private const string SettingsPath = "Assets/_Project/Constants/Defense25DComparison/ComparisonSettings.asset";
|
|
|
|
[UnitySetUp]
|
|
public IEnumerator SetUp()
|
|
{
|
|
previousTimeScale = Time.timeScale;
|
|
Time.timeScale = 1f;
|
|
settings = Object.Instantiate(AssetDatabase.LoadAssetAtPath<Defense25DComparisonSettings>(SettingsPath));
|
|
Assert.That(settings, Is.Not.Null);
|
|
settings.Enemy = AssetDatabase.LoadAssetAtPath<BumpCombat.Enemies.EnemyDefinition>(
|
|
"Assets/_Project/Constants/Enemies/Slime.asset");
|
|
settings.EnemyArt = ReadCharacter();
|
|
world = new GameObject("Presentation integration world").AddComponent<Defense25DComparison>();
|
|
world.Initialize(settings);
|
|
world.AutoSpawn = false;
|
|
world.ReadInput = false;
|
|
yield return new WaitForFixedUpdate();
|
|
}
|
|
|
|
[UnityTearDown]
|
|
public IEnumerator TearDown()
|
|
{
|
|
if (world != null) Object.Destroy(world.gameObject);
|
|
if (settings != null) Object.Destroy(settings);
|
|
Time.timeScale = previousTimeScale;
|
|
yield return null;
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator BuildCatalogUsesAllSixRealTowerSpritesAndBuildsSelectedTypeAtSelectedPad()
|
|
{
|
|
Assert.That(world.TowerShowcaseKinds.Count(), Is.EqualTo(6));
|
|
foreach (DefenseTowerKind kind in world.TowerShowcaseKinds)
|
|
Assert.That(world.GetTowerShowcaseSprite(kind), Is.Not.Null, $"Missing actual idle art for {kind}");
|
|
|
|
const int pad = 2;
|
|
Vector2 position = GameplayConstants.Current.Defense.GetBuildPadPosition(pad);
|
|
world.Player.ResetAt(position);
|
|
Assert.That(world.SelectBuildKind(DefenseTowerKind.Lightning), Is.True);
|
|
Assert.That(world.SelectBuildPad(pad), Is.True);
|
|
int before = world.TowerManager.ConstructionCurrency;
|
|
Assert.That(world.BuildSelectedTower(), Is.True);
|
|
|
|
Defense25DTower tower = world.TowerManager.GetTowerAtPad(pad);
|
|
Assert.That(tower, Is.Not.Null);
|
|
Assert.That(tower.Kind, Is.EqualTo(DefenseTowerKind.Lightning));
|
|
Assert.That(world.TowerManager.ConstructionCurrency, Is.LessThan(before));
|
|
yield return null;
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator SelectedTowerOffersOnlyLegalTierAndFinalBranchUpgrades()
|
|
{
|
|
const int pad = 0;
|
|
world.Player.ResetAt(GameplayConstants.Current.Defense.GetBuildPadPosition(pad));
|
|
world.TowerManager.AddCurrency(1000);
|
|
Assert.That(world.SelectBuildPad(pad), Is.True);
|
|
Assert.That(world.BuildSelectedTower(), Is.True);
|
|
Assert.That(world.UpgradeSelectedTower(DefenseTowerBranch.First), Is.False,
|
|
"Branches are only selected when upgrading from tier three.");
|
|
Assert.That(world.UpgradeSelectedTower(DefenseTowerBranch.None), Is.True);
|
|
Assert.That(world.TowerManager.GetTowerAtPad(pad).Tier, Is.EqualTo(2));
|
|
Assert.That(world.UpgradeSelectedTower(DefenseTowerBranch.None), Is.True);
|
|
Assert.That(world.TowerManager.GetTowerAtPad(pad).Tier, Is.EqualTo(3));
|
|
Assert.That(world.UpgradeSelectedTower(DefenseTowerBranch.Second), Is.True);
|
|
Defense25DTower tierFour = world.TowerManager.GetTowerAtPad(pad);
|
|
Assert.That(tierFour.Tier, Is.EqualTo(4));
|
|
Assert.That(tierFour.Branch, Is.EqualTo(DefenseTowerBranch.Second));
|
|
Assert.That(world.UpgradeSelectedTower(DefenseTowerBranch.First), Is.False);
|
|
yield return null;
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator RelicCannotBeGrantedOutsideACollectedPortalReward()
|
|
{
|
|
PassiveRelicId available = world.Loadout.GetAvailableRelics().First();
|
|
Assert.That(world.QueueFieldRelicRewardForCollectedPortal(0), Is.False);
|
|
Assert.That(world.HasPendingFieldRelicReward, Is.False);
|
|
Assert.That(world.ResolveFieldRelicChoice(available), Is.False);
|
|
Assert.That(world.Loadout.OwnsRelic(available), Is.False);
|
|
Assert.That(world.Paused, Is.False);
|
|
yield return null;
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator PresentationPointerRegionsConsumeUiClicksButLeaveArenaPointerFree()
|
|
{
|
|
Rect viewport = Defense25DView.GetViewport(Screen.width, Screen.height);
|
|
float scale = viewport.width / Defense25DView.Width;
|
|
Vector2 ScreenPoint(float x, float y) => new(viewport.x + x * scale,
|
|
Screen.height - (viewport.y + y * scale));
|
|
|
|
foreach (Rect control in world.GetPersistentDefenseUiHitRects())
|
|
Assert.That(world.IsPointerOverDefenseUI(ScreenPoint(control.center.x, control.center.y)), Is.True,
|
|
$"Clicks on persistent HUD control {control} must not also operate the arena.");
|
|
Assert.That(world.SelectBuildPad(0), Is.True);
|
|
Rect details = world.GetSelectedPadDetailsRect();
|
|
Assert.That(details.width, Is.GreaterThan(0f));
|
|
Assert.That(world.IsPointerOverDefenseUI(ScreenPoint(details.center.x, details.center.y)), Is.True,
|
|
"Clicks in the selected pad's contextual panel must not reach the arena.");
|
|
Assert.That(world.IsPointerOverDefenseUI(ScreenPoint(320, 180)), Is.False,
|
|
"The central field remains available for aiming and movement.");
|
|
yield return null;
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator ShowcaseModeUsesDedicatedEntryAndExitHooks()
|
|
{
|
|
int entered = 0;
|
|
int exited = 0;
|
|
world.BindValidationShowcase(() => { entered++; return true; }, () => exited++);
|
|
Assert.That(world.EnterValidationShowcase(), Is.True);
|
|
Assert.That(world.IsValidationShowcaseActive, Is.True);
|
|
Assert.That(world.EnterValidationShowcase(), Is.False);
|
|
Assert.That(entered, Is.EqualTo(1));
|
|
Assert.That(world.ExitValidationShowcase(), Is.True);
|
|
Assert.That(world.IsValidationShowcaseActive, Is.False);
|
|
Assert.That(exited, Is.EqualTo(1));
|
|
yield return null;
|
|
}
|
|
|
|
private static ComparisonSpriteFrames ReadCharacter()
|
|
{
|
|
Sprite[] Read(string suffix) => AssetDatabase.LoadAllAssetsAtPath(
|
|
$"Assets/_Project/Art/Characters/Slime/Slime_{suffix}.png")
|
|
.OfType<Sprite>()
|
|
.OrderBy(sprite => int.TryParse(sprite.name[(sprite.name.LastIndexOf('_') + 1)..], out int frame) ? frame : 0)
|
|
.ToArray();
|
|
return new ComparisonSpriteFrames
|
|
{
|
|
Idle = Read("Idle"), Walk = Read("Walk"), Attack = Read("Attack"),
|
|
Hurt = Read("Hurt"), Death = Read("Death"),
|
|
};
|
|
}
|
|
}
|
|
}
|