using System; using System.Collections.Generic; using AppleHills.Data.CardSystem; using Core; using UnityEngine; namespace Data.CardSystem { /// /// Manages the player's card collection, booster packs, and related operations. /// Uses a singleton pattern for global access. /// public class CardSystemManager : MonoBehaviour { private static CardSystemManager _instance; private static bool _isQuitting = false; public static CardSystemManager Instance { get { if (_instance == null && Application.isPlaying && !_isQuitting) { _instance = FindAnyObjectByType(); if (_instance == null) { var go = new GameObject("CardSystemManager"); _instance = go.AddComponent(); DontDestroyOnLoad(go); } } return _instance; } } [Header("Card Collection")] [SerializeField] private List availableCards = new List(); // Runtime data - will be serialized for save/load [SerializeField] private CardInventory playerInventory = new CardInventory(); // Dictionary to quickly look up card definitions by ID private Dictionary _definitionLookup = new Dictionary(); // Event callbacks using System.Action public event Action> OnBoosterOpened; public event Action OnCardCollected; public event Action OnCardRarityUpgraded; public event Action OnBoosterCountChanged; private void Awake() { if (_instance != null && _instance != this) { Destroy(gameObject); return; } _instance = this; DontDestroyOnLoad(gameObject); // Build lookup dictionary BuildDefinitionLookup(); } private void OnApplicationQuit() { _isQuitting = true; } /// /// Builds a lookup dictionary for quick access to card definitions by ID /// private void BuildDefinitionLookup() { _definitionLookup.Clear(); foreach (var cardDef in availableCards) { if (cardDef != null && !string.IsNullOrEmpty(cardDef.Id)) { _definitionLookup[cardDef.Id] = cardDef; } } // Link existing card data to their definitions foreach (var cardData in playerInventory.CollectedCards.Values) { if (!string.IsNullOrEmpty(cardData.DefinitionId) && _definitionLookup.TryGetValue(cardData.DefinitionId, out CardDefinition def)) { cardData.SetDefinition(def); } } } /// /// Adds a booster pack to the player's inventory /// public void AddBoosterPack(int count = 1) { playerInventory.BoosterPackCount += count; OnBoosterCountChanged?.Invoke(playerInventory.BoosterPackCount); Logging.Debug($"[CardSystemManager] Added {count} booster pack(s). Total: {playerInventory.BoosterPackCount}"); } /// /// Opens a booster pack and returns the newly obtained cards /// public List OpenBoosterPack() { if (playerInventory.BoosterPackCount <= 0) { Logging.Warning("[CardSystemManager] Attempted to open a booster pack, but none are available."); return new List(); } playerInventory.BoosterPackCount--; OnBoosterCountChanged?.Invoke(playerInventory.BoosterPackCount); // Draw 3 cards based on rarity distribution List drawnCards = DrawRandomCards(3); // Add cards to the inventory foreach (var card in drawnCards) { AddCardToInventory(card); } // Notify listeners OnBoosterOpened?.Invoke(drawnCards); Logging.Debug($"[CardSystemManager] Opened a booster pack and obtained {drawnCards.Count} cards. Remaining boosters: {playerInventory.BoosterPackCount}"); return drawnCards; } /// /// Adds a card to the player's inventory, handles duplicates /// private void AddCardToInventory(CardData card) { // Check if the player already has this card type (definition) if (playerInventory.HasCard(card.DefinitionId)) { CardData existingCard = playerInventory.GetCard(card.DefinitionId); existingCard.CopiesOwned++; // Check if the card can be upgraded if (existingCard.TryUpgradeRarity()) { OnCardRarityUpgraded?.Invoke(existingCard); } Logging.Debug($"[CardSystemManager] Added duplicate card '{card.Name}'. Now have {existingCard.CopiesOwned} copies."); } else { // Add new card playerInventory.AddCard(card); OnCardCollected?.Invoke(card); Logging.Debug($"[CardSystemManager] Added new card '{card.Name}' to collection."); } } /// /// Draws random cards based on rarity distribution /// private List DrawRandomCards(int count) { List result = new List(); if (availableCards.Count == 0) { Debug.LogError("[CardSystemManager] No available cards defined!"); return result; } // Simple weighted random selection based on rarity for (int i = 0; i < count; i++) { // Determine card rarity first CardRarity rarity = DetermineRandomRarity(); // Filter cards by the selected rarity List cardsOfRarity = availableCards.FindAll(c => c.Rarity == rarity); if (cardsOfRarity.Count > 0) { // Select a random card of this rarity int randomIndex = UnityEngine.Random.Range(0, cardsOfRarity.Count); CardDefinition selectedDef = cardsOfRarity[randomIndex]; // Create card data from definition CardData newCard = selectedDef.CreateCardData(); result.Add(newCard); } else { // Fallback if no cards of the selected rarity Logging.Warning($"[CardSystemManager] No cards of rarity {rarity} available, selecting a random card instead."); int randomIndex = UnityEngine.Random.Range(0, availableCards.Count); CardDefinition randomDef = availableCards[randomIndex]; CardData newCard = randomDef.CreateCardData(); result.Add(newCard); } } return result; } /// /// Determines a random card rarity with appropriate weighting /// private CardRarity DetermineRandomRarity() { // Simple weighted random - can be adjusted for better distribution float rand = UnityEngine.Random.value; if (rand < 0.6f) return CardRarity.Common; if (rand < 0.85f) return CardRarity.Uncommon; if (rand < 0.95f) return CardRarity.Rare; if (rand < 0.99f) return CardRarity.Epic; return CardRarity.Legendary; } /// /// Returns all cards from the player's collection /// public List GetAllCollectedCards() { return playerInventory.GetAllCards(); } /// /// Returns cards from a specific zone /// public List GetCardsByZone(CardZone zone) { return playerInventory.GetCardsByZone(zone); } /// /// Returns cards of a specific rarity /// public List GetCardsByRarity(CardRarity rarity) { return playerInventory.GetCardsByRarity(rarity); } /// /// Returns the number of booster packs the player has /// public int GetBoosterPackCount() { return playerInventory.BoosterPackCount; } /// /// Returns whether a specific card definition has been collected /// public bool IsCardCollected(string definitionId) { return playerInventory.HasCard(definitionId); } /// /// Gets total unique card count /// public int GetUniqueCardCount() { return playerInventory.GetUniqueCardCount(); } /// /// Gets completion percentage for a specific zone (0-100) /// public float GetZoneCompletionPercentage(CardZone zone) { // Count available cards in this zone int totalInZone = availableCards.FindAll(c => c.Zone == zone).Count; if (totalInZone == 0) return 0; // Count collected cards in this zone int collectedInZone = playerInventory.GetCardsByZone(zone).Count; return (float)collectedInZone / totalInZone * 100f; } } }