Slotting cards in album after revealing
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AppleHills.Data.CardSystem;
|
||||
using Bootstrap;
|
||||
using Core;
|
||||
@@ -23,6 +24,10 @@ namespace Data.CardSystem
|
||||
|
||||
// Runtime data - will be serialized for save/load
|
||||
[SerializeField] private CardInventory playerInventory = new CardInventory();
|
||||
|
||||
// Album system - cards waiting to be placed in album
|
||||
private List<CardData> _pendingRevealCards = new List<CardData>();
|
||||
private HashSet<string> _placedInAlbumCardIds = new HashSet<string>();
|
||||
|
||||
// Dictionary to quickly look up card definitions by ID
|
||||
private Dictionary<string, CardDefinition> _definitionLookup = new Dictionary<string, CardDefinition>();
|
||||
@@ -32,6 +37,8 @@ namespace Data.CardSystem
|
||||
public event Action<CardData> OnCardCollected;
|
||||
public event Action<CardData> OnCardRarityUpgraded;
|
||||
public event Action<int> OnBoosterCountChanged;
|
||||
public event Action<CardData> OnPendingCardAdded;
|
||||
public event Action<CardData> OnCardPlacedInAlbum;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -175,19 +182,34 @@ namespace Data.CardSystem
|
||||
|
||||
/// <summary>
|
||||
/// Check if a card is new to the player's collection at the specified rarity
|
||||
/// Checks both owned inventory and pending reveal queue
|
||||
/// </summary>
|
||||
/// <param name="cardData">The card to check</param>
|
||||
/// <param name="existingCard">Out parameter - the existing card if found, null otherwise</param>
|
||||
/// <returns>True if this is a new card at this rarity, false if already owned</returns>
|
||||
/// <returns>True if this is a new card at this rarity, false if already owned or pending</returns>
|
||||
public bool IsCardNew(CardData cardData, out CardData existingCard)
|
||||
{
|
||||
// First check inventory (cards already placed in album)
|
||||
if (playerInventory.HasCard(cardData.DefinitionId, cardData.Rarity))
|
||||
{
|
||||
existingCard = playerInventory.GetCard(cardData.DefinitionId, cardData.Rarity);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Then check pending reveal queue (cards waiting to be placed)
|
||||
CardData pendingCard = _pendingRevealCards.FirstOrDefault(c =>
|
||||
c.DefinitionId == cardData.DefinitionId && c.Rarity == cardData.Rarity);
|
||||
|
||||
if (pendingCard != null)
|
||||
{
|
||||
// Return the actual pending card with its real CopiesOwned count
|
||||
// Pending status is just about placement location, not copy count
|
||||
existingCard = pendingCard;
|
||||
return false; // Not new - already in pending queue
|
||||
}
|
||||
|
||||
existingCard = null;
|
||||
return true;
|
||||
return true; // Truly new - not in inventory or pending
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -201,28 +223,46 @@ namespace Data.CardSystem
|
||||
|
||||
/// <summary>
|
||||
/// Adds a card to the player's inventory, handles duplicates
|
||||
/// Checks both inventory and pending lists to find existing cards
|
||||
/// </summary>
|
||||
private void AddCardToInventory(CardData card)
|
||||
{
|
||||
// Check if the player already has this card at this rarity
|
||||
// Guard: Ensure card has at least 1 copy
|
||||
if (card.CopiesOwned <= 0)
|
||||
{
|
||||
card.CopiesOwned = 1;
|
||||
Logging.Warning($"[CardSystemManager] Card '{card.Name}' had {card.CopiesOwned} copies, setting to 1");
|
||||
}
|
||||
|
||||
// First check inventory (cards already placed in album)
|
||||
if (playerInventory.HasCard(card.DefinitionId, card.Rarity))
|
||||
{
|
||||
CardData existingCard = playerInventory.GetCard(card.DefinitionId, card.Rarity);
|
||||
existingCard.CopiesOwned++;
|
||||
|
||||
// Note: Upgrades are now handled separately in BoosterOpeningPage
|
||||
// We don't auto-upgrade here anymore
|
||||
|
||||
Logging.Debug($"[CardSystemManager] Added duplicate card '{card.Name}' ({card.Rarity}). Now have {existingCard.CopiesOwned} copies.");
|
||||
Logging.Debug($"[CardSystemManager] Added duplicate card '{card.Name}' ({card.Rarity}) to INVENTORY. Now have {existingCard.CopiesOwned} copies.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
// Then check pending reveal queue
|
||||
CardData pendingCard = _pendingRevealCards.FirstOrDefault(c =>
|
||||
c.DefinitionId == card.DefinitionId && c.Rarity == card.Rarity);
|
||||
|
||||
if (pendingCard != null)
|
||||
{
|
||||
// Add new card at this rarity
|
||||
playerInventory.AddCard(card);
|
||||
OnCardCollected?.Invoke(card);
|
||||
// Card already in pending - increment its copy count
|
||||
pendingCard.CopiesOwned++;
|
||||
|
||||
Logging.Debug($"[CardSystemManager] Added new card '{card.Name}' ({card.Rarity}) to collection.");
|
||||
Logging.Debug($"[CardSystemManager] Added duplicate card '{card.Name}' ({card.Rarity}) to PENDING. Now have {pendingCard.CopiesOwned} copies pending.");
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a NEW card (never owned at this rarity before)
|
||||
// Add to pending reveal list instead of inventory
|
||||
_pendingRevealCards.Add(card);
|
||||
OnPendingCardAdded?.Invoke(card);
|
||||
|
||||
Logging.Debug($"[CardSystemManager] Added new card '{card.Name}' ({card.Rarity}) to pending reveal queue.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -286,27 +326,33 @@ namespace Data.CardSystem
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all cards from the player's collection
|
||||
/// Returns all cards from the player's collection (both owned and pending)
|
||||
/// </summary>
|
||||
public List<CardData> GetAllCollectedCards()
|
||||
{
|
||||
return playerInventory.GetAllCards();
|
||||
List<CardData> allCards = new List<CardData>(playerInventory.GetAllCards());
|
||||
allCards.AddRange(_pendingRevealCards);
|
||||
return allCards;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns cards from a specific zone
|
||||
/// Returns cards from a specific zone (both owned and pending)
|
||||
/// </summary>
|
||||
public List<CardData> GetCardsByZone(CardZone zone)
|
||||
{
|
||||
return playerInventory.GetCardsByZone(zone);
|
||||
List<CardData> zoneCards = new List<CardData>(playerInventory.GetCardsByZone(zone));
|
||||
zoneCards.AddRange(_pendingRevealCards.Where(c => c.Zone == zone));
|
||||
return zoneCards;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns cards of a specific rarity
|
||||
/// Returns cards of a specific rarity (both owned and pending)
|
||||
/// </summary>
|
||||
public List<CardData> GetCardsByRarity(CardRarity rarity)
|
||||
{
|
||||
return playerInventory.GetCardsByRarity(rarity);
|
||||
List<CardData> rarityCards = new List<CardData>(playerInventory.GetCardsByRarity(rarity));
|
||||
rarityCards.AddRange(_pendingRevealCards.Where(c => c.Rarity == rarity));
|
||||
return rarityCards;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -318,25 +364,38 @@ namespace Data.CardSystem
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a specific card definition has been collected (at any rarity)
|
||||
/// Returns whether a specific card definition has been collected (at any rarity, in inventory or pending)
|
||||
/// </summary>
|
||||
public bool IsCardCollected(string definitionId)
|
||||
{
|
||||
// Check if the card exists at any rarity
|
||||
// Check inventory at any rarity
|
||||
foreach (CardRarity rarity in System.Enum.GetValues(typeof(CardRarity)))
|
||||
{
|
||||
if (playerInventory.HasCard(definitionId, rarity))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check pending reveal queue
|
||||
if (_pendingRevealCards.Any(c => c.DefinitionId == definitionId))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets total unique card count
|
||||
/// Gets total unique card count (both owned and pending)
|
||||
/// </summary>
|
||||
public int GetUniqueCardCount()
|
||||
{
|
||||
return playerInventory.GetUniqueCardCount();
|
||||
int inventoryCount = playerInventory.GetUniqueCardCount();
|
||||
|
||||
// Count unique cards in pending that aren't already in inventory
|
||||
int pendingUniqueCount = _pendingRevealCards
|
||||
.Select(c => new { c.DefinitionId, c.Rarity })
|
||||
.Distinct()
|
||||
.Count(pc => !playerInventory.HasCard(pc.DefinitionId, pc.Rarity));
|
||||
|
||||
return inventoryCount + pendingUniqueCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -381,19 +440,23 @@ namespace Data.CardSystem
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the count of cards by rarity
|
||||
/// Returns the count of cards by rarity (both owned and pending)
|
||||
/// </summary>
|
||||
public int GetCardCountByRarity(CardRarity rarity)
|
||||
{
|
||||
return playerInventory.GetCardsByRarity(rarity).Count;
|
||||
int inventoryCount = playerInventory.GetCardsByRarity(rarity).Count;
|
||||
int pendingCount = _pendingRevealCards.Count(c => c.Rarity == rarity);
|
||||
return inventoryCount + pendingCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the count of cards by zone
|
||||
/// Returns the count of cards by zone (both owned and pending)
|
||||
/// </summary>
|
||||
public int GetCardCountByZone(CardZone zone)
|
||||
{
|
||||
return playerInventory.GetCardsByZone(zone).Count;
|
||||
int inventoryCount = playerInventory.GetCardsByZone(zone).Count;
|
||||
int pendingCount = _pendingRevealCards.Count(c => c.Zone == zone);
|
||||
return inventoryCount + pendingCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -428,6 +491,121 @@ namespace Data.CardSystem
|
||||
return (float)collectedOfRarity / totalOfRarity * 100f;
|
||||
}
|
||||
|
||||
#region Album System
|
||||
|
||||
/// <summary>
|
||||
/// Returns all cards waiting to be placed in the album
|
||||
/// </summary>
|
||||
public List<CardData> GetPendingRevealCards()
|
||||
{
|
||||
return new List<CardData>(_pendingRevealCards);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a card by definition ID and rarity from either inventory or pending
|
||||
/// Returns the actual card reference so changes persist
|
||||
/// </summary>
|
||||
/// <param name="definitionId">Card definition ID</param>
|
||||
/// <param name="rarity">Card rarity</param>
|
||||
/// <param name="isFromPending">Out parameter - true if card is from pending, false if from inventory</param>
|
||||
/// <returns>The card data if found, null otherwise</returns>
|
||||
public CardData GetCard(string definitionId, CardRarity rarity, out bool isFromPending)
|
||||
{
|
||||
// Check inventory first
|
||||
if (playerInventory.HasCard(definitionId, rarity))
|
||||
{
|
||||
isFromPending = false;
|
||||
return playerInventory.GetCard(definitionId, rarity);
|
||||
}
|
||||
|
||||
// Check pending
|
||||
CardData pendingCard = _pendingRevealCards.FirstOrDefault(c =>
|
||||
c.DefinitionId == definitionId && c.Rarity == rarity);
|
||||
|
||||
if (pendingCard != null)
|
||||
{
|
||||
isFromPending = true;
|
||||
return pendingCard;
|
||||
}
|
||||
|
||||
isFromPending = false;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a card by definition ID and rarity from either inventory or pending (simplified overload)
|
||||
/// </summary>
|
||||
public CardData GetCard(string definitionId, CardRarity rarity)
|
||||
{
|
||||
return GetCard(definitionId, rarity, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update a card's data in whichever list it's in (inventory or pending)
|
||||
/// Useful for incrementing CopiesOwned, upgrading rarity, etc.
|
||||
/// </summary>
|
||||
/// <param name="definitionId">Card definition ID</param>
|
||||
/// <param name="rarity">Card rarity</param>
|
||||
/// <param name="updateAction">Action to perform on the card</param>
|
||||
/// <returns>True if card was found and updated, false otherwise</returns>
|
||||
public bool UpdateCard(string definitionId, CardRarity rarity, System.Action<CardData> updateAction)
|
||||
{
|
||||
CardData card = GetCard(definitionId, rarity, out bool isFromPending);
|
||||
|
||||
if (card != null)
|
||||
{
|
||||
updateAction?.Invoke(card);
|
||||
Logging.Debug($"[CardSystemManager] Updated card '{card.Name}' in {(isFromPending ? "pending" : "inventory")}");
|
||||
return true;
|
||||
}
|
||||
|
||||
Logging.Warning($"[CardSystemManager] Could not find card with ID '{definitionId}' and rarity '{rarity}' to update");
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks a card as placed in the album
|
||||
/// Moves it from pending reveal to owned inventory
|
||||
/// </summary>
|
||||
public void MarkCardAsPlaced(CardData card)
|
||||
{
|
||||
if (_pendingRevealCards.Remove(card))
|
||||
{
|
||||
// Add to owned inventory
|
||||
playerInventory.AddCard(card);
|
||||
|
||||
// Track as placed
|
||||
_placedInAlbumCardIds.Add(card.Id);
|
||||
|
||||
OnCardPlacedInAlbum?.Invoke(card);
|
||||
OnCardCollected?.Invoke(card);
|
||||
|
||||
Logging.Debug($"[CardSystemManager] Card '{card.Name}' placed in album and added to inventory.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Warning($"[CardSystemManager] Attempted to place card '{card.Name}' but it wasn't in pending reveal list.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a card has been placed in the album
|
||||
/// </summary>
|
||||
public bool IsCardPlacedInAlbum(string cardId)
|
||||
{
|
||||
return _placedInAlbumCardIds.Contains(cardId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets count of cards waiting to be revealed
|
||||
/// </summary>
|
||||
public int GetPendingRevealCount()
|
||||
{
|
||||
return _pendingRevealCards.Count;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Export current card collection to a serializable snapshot
|
||||
/// </summary>
|
||||
@@ -436,7 +614,9 @@ namespace Data.CardSystem
|
||||
var state = new CardCollectionState
|
||||
{
|
||||
boosterPackCount = playerInventory.BoosterPackCount,
|
||||
cards = new List<SavedCardEntry>()
|
||||
cards = new List<SavedCardEntry>(),
|
||||
pendingRevealCards = new List<SavedCardEntry>(),
|
||||
placedInAlbumCardIds = new List<string>(_placedInAlbumCardIds)
|
||||
};
|
||||
|
||||
foreach (var card in playerInventory.CollectedCards.Values)
|
||||
@@ -449,6 +629,18 @@ namespace Data.CardSystem
|
||||
copiesOwned = card.CopiesOwned
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var card in _pendingRevealCards)
|
||||
{
|
||||
if (string.IsNullOrEmpty(card.DefinitionId)) continue;
|
||||
state.pendingRevealCards.Add(new SavedCardEntry
|
||||
{
|
||||
definitionId = card.DefinitionId,
|
||||
rarity = card.Rarity,
|
||||
copiesOwned = card.CopiesOwned
|
||||
});
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -460,6 +652,9 @@ namespace Data.CardSystem
|
||||
if (state == null) return;
|
||||
|
||||
playerInventory.ClearAllCards();
|
||||
_pendingRevealCards.Clear();
|
||||
_placedInAlbumCardIds.Clear();
|
||||
|
||||
playerInventory.BoosterPackCount = state.boosterPackCount;
|
||||
OnBoosterCountChanged?.Invoke(playerInventory.BoosterPackCount);
|
||||
|
||||
@@ -479,6 +674,31 @@ namespace Data.CardSystem
|
||||
Logging.Warning($"[CardSystemManager] Saved card definition not found: {entry.definitionId}");
|
||||
}
|
||||
}
|
||||
|
||||
// Restore pending reveal cards
|
||||
if (state.pendingRevealCards != null)
|
||||
{
|
||||
foreach (var entry in state.pendingRevealCards)
|
||||
{
|
||||
if (string.IsNullOrEmpty(entry.definitionId)) continue;
|
||||
if (_definitionLookup.TryGetValue(entry.definitionId, out var def))
|
||||
{
|
||||
var cd = def.CreateCardData();
|
||||
cd.Rarity = entry.rarity;
|
||||
cd.CopiesOwned = entry.copiesOwned;
|
||||
_pendingRevealCards.Add(cd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore placed in album tracking
|
||||
if (state.placedInAlbumCardIds != null)
|
||||
{
|
||||
foreach (var cardId in state.placedInAlbumCardIds)
|
||||
{
|
||||
_placedInAlbumCardIds.Add(cardId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region ISaveParticipant Implementation
|
||||
|
||||
Reference in New Issue
Block a user