using System; using System.Collections.Generic; using System.Collections.ObjectModel; namespace ProjectI.Builds { public sealed class PlayerBuildState { private readonly AbilityUnlockState unlocks; public BuildLoadout Loadout { get; private set; } public BuildStats Stats { get; private set; } public IReadOnlyDictionary Catalog { get; } public PlayerBuildState(IReadOnlyDictionary catalog, AbilityUnlockState unlocks) { if (catalog == null) throw new ArgumentNullException(nameof(catalog)); this.unlocks = unlocks ?? throw new ArgumentNullException(nameof(unlocks)); var snapshot = new Dictionary(); foreach (var pair in catalog) { if (pair.Value == null || pair.Key != pair.Value.Id) throw new ArgumentException("Catalog keys must match non-null ability IDs.", nameof(catalog)); snapshot.Add(pair.Key, pair.Value); } Catalog = new ReadOnlyDictionary(snapshot); Stats = new BuildStats(50, 5, 1); TryEquip(BuildLoadout.Default, false); } public bool TryEquip(BuildLoadout loadout, bool runStarted) { if (runStarted || loadout.PassiveFirst == loadout.PassiveSecond || loadout.ActiveFirst == loadout.ActiveSecond || loadout.ActiveThird == loadout.ActiveFirst || loadout.ActiveThird == loadout.ActiveSecond) return false; if (!ValidSlot(loadout.PassiveFirst, AbilitySlot.Passive) || !ValidSlot(loadout.PassiveSecond, AbilitySlot.Passive) || !ValidSlot(loadout.ActiveFirst, AbilitySlot.Active) || !ValidSlot(loadout.ActiveSecond, AbilitySlot.Active) || !ValidSlot(loadout.ActiveThird, AbilitySlot.Active) || !ValidSlot(loadout.Ultimate, AbilitySlot.Ultimate) || !ValidSlot(loadout.Melee, AbilitySlot.Melee)) return false; double health = 0, movement = 0, attack = 0, ability = 0; AddStats(Catalog[loadout.PassiveFirst], ref health, ref movement, ref attack, ref ability); AddStats(Catalog[loadout.PassiveSecond], ref health, ref movement, ref attack, ref ability); AddStats(Catalog[loadout.ActiveFirst], ref health, ref movement, ref attack, ref ability); AddStats(Catalog[loadout.ActiveSecond], ref health, ref movement, ref attack, ref ability); AddStats(Catalog[loadout.ActiveThird], ref health, ref movement, ref attack, ref ability); AddStats(Catalog[loadout.Ultimate], ref health, ref movement, ref attack, ref ability); AddStats(Catalog[loadout.Melee], ref health, ref movement, ref attack, ref ability); var stats = new BuildStats( (float)Math.Min(float.MaxValue, Math.Max(1, 50 * (1 + health))), (float)Math.Min(12, Math.Max(1, 5 * (1 + movement))), (float)Math.Min(float.MaxValue, Math.Max(.1, 1 + attack)), (float)Math.Min(float.MaxValue, Math.Max(.1, 1 + ability))); Loadout = loadout; Stats = stats; return true; } private bool ValidSlot(int id, AbilitySlot slot) => unlocks.IsUnlocked(id) && Catalog.TryGetValue(id, out var ability) && ability.Slot == slot; private static void AddStats(AbilityTuning ability, ref double health, ref double movement, ref double attack, ref double abilityDamage) { health += ability.HealthPercent; movement += ability.MovementPercent; attack += ability.AttackDamagePercent; abilityDamage += ability.AbilityDamagePercent; } } }