[Fix] Limited Use Modifier
This commit is contained in:
@@ -1,9 +1,7 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using VContainer;
|
using VContainer;
|
||||||
using YachtDice.Categories;
|
|
||||||
using YachtDice.Economy;
|
using YachtDice.Economy;
|
||||||
using YachtDice.Modifiers.Runtime;
|
using YachtDice.Modifiers.Runtime;
|
||||||
using YachtDice.Scoring;
|
|
||||||
|
|
||||||
namespace YachtDice.Inventory
|
namespace YachtDice.Inventory
|
||||||
{
|
{
|
||||||
@@ -12,16 +10,14 @@ namespace YachtDice.Inventory
|
|||||||
[SerializeField] private InventoryView inventoryView;
|
[SerializeField] private InventoryView inventoryView;
|
||||||
|
|
||||||
private InventoryModel _model;
|
private InventoryModel _model;
|
||||||
private ScoringSystem _scoringSystem;
|
|
||||||
private CurrencyBank _currencyBank;
|
private CurrencyBank _currencyBank;
|
||||||
|
|
||||||
public InventoryModel Model => _model;
|
public InventoryModel Model => _model;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public void Construct(InventoryModel model, ScoringSystem scoringSystem, CurrencyBank currencyBank)
|
public void Construct(InventoryModel model, CurrencyBank currencyBank)
|
||||||
{
|
{
|
||||||
this._model = model;
|
this._model = model;
|
||||||
this._scoringSystem = scoringSystem;
|
|
||||||
this._currencyBank = currencyBank;
|
this._currencyBank = currencyBank;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +28,6 @@ namespace YachtDice.Inventory
|
|||||||
inventoryView.OnSellClicked += HandleSell;
|
inventoryView.OnSellClicked += HandleSell;
|
||||||
|
|
||||||
_model.OnInventoryChanged += HandleInventoryChanged;
|
_model.OnInventoryChanged += HandleInventoryChanged;
|
||||||
_scoringSystem.OnCategoryConfirmed += HandleCategoryConfirmed;
|
|
||||||
|
|
||||||
RefreshView();
|
RefreshView();
|
||||||
}
|
}
|
||||||
@@ -48,9 +43,6 @@ namespace YachtDice.Inventory
|
|||||||
|
|
||||||
if (_model != null)
|
if (_model != null)
|
||||||
_model.OnInventoryChanged -= HandleInventoryChanged;
|
_model.OnInventoryChanged -= HandleInventoryChanged;
|
||||||
|
|
||||||
if (_scoringSystem != null)
|
|
||||||
_scoringSystem.OnCategoryConfirmed -= HandleCategoryConfirmed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggleVisibility()
|
public void ToggleVisibility()
|
||||||
@@ -89,11 +81,6 @@ namespace YachtDice.Inventory
|
|||||||
RefreshView();
|
RefreshView();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleCategoryConfirmed(CategoryDefinition category, ScoreResult result)
|
|
||||||
{
|
|
||||||
_model.ConsumeUseOnActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RefreshView()
|
private void RefreshView()
|
||||||
{
|
{
|
||||||
if (inventoryView != null && _model != null)
|
if (inventoryView != null && _model != null)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace YachtDice.Modifiers.Core
|
|||||||
|
|
||||||
// Trigger info
|
// Trigger info
|
||||||
public TriggerType Trigger;
|
public TriggerType Trigger;
|
||||||
|
public bool IsPreview;
|
||||||
|
|
||||||
// Side-effect accumulators
|
// Side-effect accumulators
|
||||||
public int CurrencyDelta;
|
public int CurrencyDelta;
|
||||||
|
|||||||
@@ -90,10 +90,13 @@ namespace YachtDice.Modifiers.Pipeline
|
|||||||
var effects = behavior.Effects;
|
var effects = behavior.Effects;
|
||||||
for (int e = 0; e < effects.Count; e++)
|
for (int e = 0; e < effects.Count; e++)
|
||||||
{
|
{
|
||||||
if (effects[e] == null) continue;
|
var effect = effects[e];
|
||||||
|
if (effect == null) continue;
|
||||||
|
if (context.IsPreview && effect.Phase == ModifierPhase.SideEffect) continue;
|
||||||
|
|
||||||
_effectBuffer.Add(new EffectEntry
|
_effectBuffer.Add(new EffectEntry
|
||||||
{
|
{
|
||||||
Effect = effects[e],
|
Effect = effect,
|
||||||
Instance = inst,
|
Instance = inst,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -113,6 +116,8 @@ namespace YachtDice.Modifiers.Pipeline
|
|||||||
trace.AddEffectApplied(entry.Instance.Definition.Id, entry.Effect.name, entry.Effect.Phase);
|
trace.AddEffectApplied(entry.Instance.Definition.Id, entry.Effect.name, entry.Effect.Phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_registry.RemoveExpired();
|
||||||
|
|
||||||
if (trace != null)
|
if (trace != null)
|
||||||
{
|
{
|
||||||
string traceStr = trace.ToString();
|
string traceStr = trace.ToString();
|
||||||
|
|||||||
@@ -195,6 +195,36 @@ namespace YachtDice.Modifiers.Runtime
|
|||||||
OnChanged?.Invoke();
|
OnChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RemoveExpired()
|
||||||
|
{
|
||||||
|
var changed = false;
|
||||||
|
var activeChanged = false;
|
||||||
|
|
||||||
|
for (var i = _instances.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var instance = _instances[i];
|
||||||
|
if (!instance.IsExpired)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (instance.IsActive)
|
||||||
|
activeChanged = true;
|
||||||
|
|
||||||
|
instance.IsActive = false;
|
||||||
|
_instances.RemoveAt(i);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_activeCacheDirty = true;
|
||||||
|
|
||||||
|
if (activeChanged)
|
||||||
|
OnActiveModifiersChanged?.Invoke(Active);
|
||||||
|
|
||||||
|
OnChanged?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
private void RebuildActiveCache()
|
private void RebuildActiveCache()
|
||||||
{
|
{
|
||||||
_activeCache.Clear();
|
_activeCache.Clear();
|
||||||
|
|||||||
@@ -76,8 +76,9 @@ namespace YachtDice.Scoring
|
|||||||
baseScore, dice, category,
|
baseScore, dice, category,
|
||||||
currentRoll, currentTurn, playerCurrency,
|
currentRoll, currentTurn, playerCurrency,
|
||||||
_modifierRegistry.Active);
|
_modifierRegistry.Active);
|
||||||
|
context.IsPreview = true;
|
||||||
|
|
||||||
_eventBus.Fire(TriggerType.OnCategoryScored, context).Forget();
|
_eventBus.Fire(TriggerType.OnCategoryScored, context).GetAwaiter().GetResult();
|
||||||
|
|
||||||
return context.ToScoreResult();
|
return context.ToScoreResult();
|
||||||
}
|
}
|
||||||
@@ -143,7 +144,7 @@ namespace YachtDice.Scoring
|
|||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
_modifierRegistry.Active);
|
_modifierRegistry.Active);
|
||||||
|
|
||||||
_eventBus.Fire(TriggerType.OnCategoryScored, context).Forget();
|
_eventBus.Fire(TriggerType.OnCategoryScored, context).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
ScoreResult result;
|
ScoreResult result;
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
using YachtDice.Categories;
|
||||||
|
using YachtDice.Dice;
|
||||||
|
using YachtDice.Economy;
|
||||||
|
using YachtDice.Events;
|
||||||
|
using YachtDice.Modifiers.Core;
|
||||||
|
using YachtDice.Modifiers.Definition;
|
||||||
|
using YachtDice.Modifiers.Effects;
|
||||||
|
using YachtDice.Modifiers.Pipeline;
|
||||||
|
using YachtDice.Modifiers.Runtime;
|
||||||
|
using YachtDice.Scoring;
|
||||||
|
|
||||||
|
namespace YachtDice.Tests
|
||||||
|
{
|
||||||
|
public class LimitedUseModifierFlowTests
|
||||||
|
{
|
||||||
|
private readonly List<Object> _createdAssets = new();
|
||||||
|
|
||||||
|
private CategoryDefinition _onesCategory;
|
||||||
|
private CategoryDefinition _twosCategory;
|
||||||
|
private CategoryDefinition _chanceCategory;
|
||||||
|
private DiceDefinition _standardDice;
|
||||||
|
private CategoryCatalog _catalog;
|
||||||
|
private CurrencyBank _currencyBank;
|
||||||
|
private ModifierRegistry _registry;
|
||||||
|
private ScoringSystem _scoringSystem;
|
||||||
|
private ModifierInstance _instance;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
_standardDice = DiceDefinition.CreateForTest<StandardDice>("d6", "d6");
|
||||||
|
_onesCategory = SumOfValueCategory.CreateForTest("ones", "Единицы", 1);
|
||||||
|
_twosCategory = SumOfValueCategory.CreateForTest("twos", "Двойки", 2);
|
||||||
|
_chanceCategory = SumAllCategory.CreateForTest("chance", "Шанс");
|
||||||
|
_catalog = CategoryCatalog.CreateForTest(new List<CategoryDefinition>
|
||||||
|
{
|
||||||
|
_onesCategory,
|
||||||
|
_twosCategory,
|
||||||
|
_chanceCategory,
|
||||||
|
});
|
||||||
|
|
||||||
|
_createdAssets.Add(_standardDice);
|
||||||
|
_createdAssets.Add(_onesCategory);
|
||||||
|
_createdAssets.Add(_twosCategory);
|
||||||
|
_createdAssets.Add(_chanceCategory);
|
||||||
|
_createdAssets.Add(_catalog);
|
||||||
|
|
||||||
|
var bankGo = new GameObject("CurrencyBank");
|
||||||
|
_currencyBank = bankGo.AddComponent<CurrencyBank>();
|
||||||
|
_currencyBank.SetBalance(100);
|
||||||
|
|
||||||
|
_registry = new ModifierRegistry(5);
|
||||||
|
var pipeline = new ModifierPipeline(_registry)
|
||||||
|
{
|
||||||
|
TracingEnabled = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
var eventBus = new GameEventBus(pipeline);
|
||||||
|
|
||||||
|
var scoringGo = new GameObject("ScoringSystem");
|
||||||
|
_scoringSystem = scoringGo.AddComponent<ScoringSystem>();
|
||||||
|
_scoringSystem.Construct(eventBus, _registry, _catalog, _currencyBank);
|
||||||
|
|
||||||
|
var multiply = AddCreatedAsset(MultiplyScoreEffect.CreateForTest(2f, ModifierPhase.Multiplicative));
|
||||||
|
var consume = AddCreatedAsset(ConsumeChargeEffect.CreateForTest(1, ModifierPhase.SideEffect));
|
||||||
|
var behavior = AddCreatedAsset(ModifierBehavior.CreateForTest(
|
||||||
|
TriggerType.OnCategoryScored,
|
||||||
|
null,
|
||||||
|
new List<Effect> { multiply, consume }));
|
||||||
|
var definition = AddCreatedAsset(ModifierDefinition.CreateForTest(
|
||||||
|
"mod_multiplier_2x_limited",
|
||||||
|
new List<ModifierBehavior> { behavior },
|
||||||
|
hasLimitedUses: true,
|
||||||
|
maxUses: 3));
|
||||||
|
|
||||||
|
_instance = _registry.Add(definition);
|
||||||
|
_registry.TryActivate(_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
foreach (var scoring in Object.FindObjectsByType<ScoringSystem>(FindObjectsSortMode.None))
|
||||||
|
Object.DestroyImmediate(scoring.gameObject);
|
||||||
|
|
||||||
|
foreach (var bank in Object.FindObjectsByType<CurrencyBank>(FindObjectsSortMode.None))
|
||||||
|
Object.DestroyImmediate(bank.gameObject);
|
||||||
|
|
||||||
|
for (var i = 0; i < _createdAssets.Count; i++)
|
||||||
|
{
|
||||||
|
if (_createdAssets[i] != null)
|
||||||
|
Object.DestroyImmediate(_createdAssets[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_createdAssets.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void PreviewScore_DoesNotConsumeCharges()
|
||||||
|
{
|
||||||
|
_scoringSystem.PreviewScore(CreateDice(1, 1, 2, 3, 4), _onesCategory);
|
||||||
|
_scoringSystem.PreviewScore(CreateDice(2, 2, 2, 3, 4), _twosCategory);
|
||||||
|
|
||||||
|
Assert.AreEqual(3, _instance.RemainingUses);
|
||||||
|
Assert.AreEqual(1, _registry.All.Count);
|
||||||
|
Assert.IsTrue(_instance.IsActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ScoreCategory_ConsumesExactlyOneCharge()
|
||||||
|
{
|
||||||
|
_scoringSystem.ScoreCategory(CreateDice(1, 1, 2, 3, 4), _onesCategory);
|
||||||
|
|
||||||
|
Assert.AreEqual(2, _instance.RemainingUses);
|
||||||
|
Assert.AreEqual(1, _registry.All.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ScoreCategory_RemovesModifier_WhenChargesExhausted()
|
||||||
|
{
|
||||||
|
_scoringSystem.ScoreCategory(CreateDice(1, 1, 2, 3, 4), _onesCategory);
|
||||||
|
_scoringSystem.ScoreCategory(CreateDice(2, 2, 2, 3, 4), _twosCategory);
|
||||||
|
_scoringSystem.ScoreCategory(CreateDice(1, 2, 3, 4, 5), _chanceCategory);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, _registry.All.Count);
|
||||||
|
Assert.AreEqual(0, _registry.ActiveCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IReadOnlyList<IDice> CreateDice(params int[] values)
|
||||||
|
{
|
||||||
|
var dice = new DiceInstance[values.Length];
|
||||||
|
for (var i = 0; i < values.Length; i++)
|
||||||
|
dice[i] = new DiceInstance(_standardDice, values[i]);
|
||||||
|
return dice;
|
||||||
|
}
|
||||||
|
|
||||||
|
private T AddCreatedAsset<T>(T asset) where T : Object
|
||||||
|
{
|
||||||
|
_createdAssets.Add(asset);
|
||||||
|
return asset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0dbdebf1eec04ff9af5ca19c0bc5f9b3
|
||||||
Reference in New Issue
Block a user