using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace TcgEngine.UI
{
///
/// CollectionPanel is the panel where players can see all the cards they own
/// Also the panel where they can use the deckbuilder
///
public class CollectionPanel : UIPanel
{
[Header("Cards")]
public ScrollRect scroll_rect;
public RectTransform scroll_content;
public CardGrid grid_content;
public GameObject card_prefab;
[Header("Left Side")]
public IconButton[] team_filters;
public Toggle toggle_owned;
public Toggle toggle_not_owned;
public Toggle toggle_character;
public Toggle toggle_spell;
public Toggle toggle_artifact;
public Toggle toggle_equipment;
public Toggle toggle_secret;
public Toggle toggle_common;
public Toggle toggle_uncommon;
public Toggle toggle_rare;
public Toggle toggle_mythic;
public Toggle toggle_foil;
public Dropdown sort_dropdown;
public InputField search;
[Header("Right Side")]
public UIPanel deck_list_panel;
public UIPanel card_list_panel;
public DeckLine[] deck_lines;
[Header("Deckbuilding")]
public InputField deck_title;
public Text deck_quantity;
public GameObject deck_cards_prefab;
public RectTransform deck_content;
public GridLayoutGroup deck_grid;
public IconButton[] hero_powers;
private TeamData filter_team = null;
private int filter_dropdown = 0;
private string filter_search = "";
private List card_list = new List();
private List all_list = new List();
private List deck_card_lines = new List();
private string current_deck_tid;
private bool editing_deck = false;
private bool saving = false;
private bool spawned = false;
private bool update_grid = false;
private float update_grid_timer = 0f;
private List deck_cards = new List();
// [SerializeField] private Text cardFragmentsText;
private static CollectionPanel instance;
protected override void Awake()
{
base.Awake();
instance = this;
//Delete grid content
for (int i = 0; i < grid_content.transform.childCount; i++)
Destroy(grid_content.transform.GetChild(i).gameObject);
for (int i = 0; i < deck_grid.transform.childCount; i++)
Destroy(deck_grid.transform.GetChild(i).gameObject);
foreach (DeckLine line in deck_lines)
line.onClick += OnClickDeckLine;
foreach (DeckLine line in deck_lines)
line.onClickDelete += OnClickDeckDelete;
foreach (IconButton button in team_filters)
button.onClick += OnClickTeam;
}
protected override void Start()
{
base.Start();
//Set power abilities hover text
foreach (IconButton btn in hero_powers)
{
CardData icard = CardData.Get(btn.GetValue());
HoverTargetUI hover = btn.GetComponent();
AbilityData iability = icard?.GetAbility(AbilityTrigger.Activate);
if (icard != null && hover != null && iability != null)
{
string color = ColorUtility.ToHtmlStringRGBA(icard.team.color);
hover.text = "Hero Power: ";
hover.text += icard.title + "\n " + iability.GetDesc(icard);
if (iability.mana_cost > 0)
hover.text += " Mana: " + iability.mana_cost + "";
}
}
}
protected override void Update()
{
base.Update();
if (ApiClient.Get() != null)
{
UserData udata = ApiClient.Get().UserData;
// cardFragmentsText.text = udata.cardfragments.ToString();
}
}
private void LateUpdate()
{
//Resize grid
update_grid_timer += Time.deltaTime;
if (update_grid && update_grid_timer > 0.2f)
{
grid_content.GetColumnAndRow(out int rows, out int cols);
if (cols > 0)
{
float row_height = grid_content.GetGrid().cellSize.y + grid_content.GetGrid().spacing.y;
float height = rows * row_height;
scroll_content.sizeDelta = new Vector2(scroll_content.sizeDelta.x, height + 100);
update_grid = false;
}
}
}
private void SpawnCards()
{
spawned = true;
foreach (CollectionCard card in all_list)
Destroy(card.gameObject);
all_list.Clear();
foreach (VariantData variant in VariantData.GetAll())
{
foreach (CardData card in CardData.GetAll())
{
GameObject nCard = Instantiate(card_prefab, grid_content.transform);
CollectionCard dCard = nCard.GetComponent();
dCard.SetCard(card, variant, 0);
dCard.onClick += OnClickCard;
dCard.onClickRight += OnClickCardRight;
all_list.Add(dCard);
nCard.SetActive(false);
}
}
}
//----- Reload User Data ---------------
public async void ReloadUser()
{
await Authenticator.Get().LoadUserData();
MainMenu.Get().RefreshDeckList();
RefreshCardsQuantities();
if (!editing_deck)
RefreshDeckList();
}
public async void ReloadUserCards()
{
await Authenticator.Get().LoadUserData();
RefreshCardsQuantities();
}
public async void ReloadUserDecks()
{
await Authenticator.Get().LoadUserData();
MainMenu.Get().RefreshDeckList();
RefreshDeckList();
}
//----- Refresh UI --------
private void RefreshAll()
{
RefreshFilters();
RefreshCards();
RefreshDeckList();
RefreshStarterDeck();
}
///
/// 筛选刷新
///
private void RefreshFilters()
{
search.text = "";
sort_dropdown.value = 0;
foreach (IconButton button in team_filters)
button.Deactivate();
filter_team = null;
filter_dropdown = 0;
filter_search = "";
}
private void ShowDeckList()
{
deck_list_panel.Show();
card_list_panel.Hide();
editing_deck = false;
}
private void ShowDeckCards()
{
deck_list_panel.Hide();
card_list_panel.Show();
}
public void RefreshCards()
{
if (!spawned)
SpawnCards();
card_list.Clear();
UserData udata = Authenticator.Get().UserData;
if (udata == null)
return;
VariantData variant = VariantData.GetDefault();
VariantData special = VariantData.GetSpecial();
if (toggle_foil.isOn && special != null)
variant = special;
List all_cards = new List();
List shown_cards = new List();
foreach (CardData icard in CardData.GetAll())
{
CardDataQ card = new CardDataQ();
card.card = icard;
card.variant = variant;
card.quantity = udata.GetCardQuantity(icard, variant);
all_cards.Add(card);
}
if (filter_dropdown == 0) //Name
all_cards.Sort((CardDataQ a, CardDataQ b) => { return a.card.title.CompareTo(b.card.title); });
if (filter_dropdown == 1) //Attack
all_cards.Sort((CardDataQ a, CardDataQ b) => { return b.card.attack == a.card.attack ? b.card.hp.CompareTo(a.card.hp) : b.card.attack.CompareTo(a.card.attack); });
if (filter_dropdown == 2) //hp
all_cards.Sort((CardDataQ a, CardDataQ b) => { return b.card.hp == a.card.hp ? b.card.attack.CompareTo(a.card.attack) : b.card.hp.CompareTo(a.card.hp); });
if (filter_dropdown == 3) //Cost
all_cards.Sort((CardDataQ a, CardDataQ b) => { return b.card.mana == a.card.mana ? a.card.title.CompareTo(b.card.title) : a.card.mana.CompareTo(b.card.mana); });
foreach (CardDataQ card in all_cards)
{
if (card.card.deckbuilding)
{
CardData icard = card.card;
if (filter_team == null || filter_team == icard.team)
{
bool owned = card.quantity > 0;
RarityData rarity = icard.rarity;
CardType type = icard.type;
bool owned_check = (owned && toggle_owned.isOn)
|| (!owned && toggle_not_owned.isOn)
|| toggle_owned.isOn == toggle_not_owned.isOn;
bool type_check = (type == CardType.Character && toggle_character.isOn)
|| (type == CardType.Spell && toggle_spell.isOn)
|| (type == CardType.Artifact && toggle_artifact.isOn)
|| (type == CardType.Equipment && toggle_equipment.isOn)
|| (type == CardType.Secret && toggle_secret.isOn)
|| (!toggle_character.isOn && !toggle_spell.isOn && !toggle_artifact.isOn && !toggle_equipment.isOn && !toggle_secret.isOn);
bool rarity_check = (rarity.rank == 1 && toggle_common.isOn)
|| (rarity.rank == 2 && toggle_uncommon.isOn)
|| (rarity.rank == 3 && toggle_rare.isOn)
|| (rarity.rank == 4 && toggle_mythic.isOn)
|| (!toggle_common.isOn && !toggle_uncommon.isOn && !toggle_rare.isOn && !toggle_mythic.isOn);
string search = filter_search.ToLower();
bool search_check = string.IsNullOrWhiteSpace(search)
|| icard.id.Contains(search)
|| icard.title.ToLower().Contains(search)
|| icard.GetText().ToLower().Contains(search);
if (owned_check && type_check && rarity_check && search_check)
{
shown_cards.Add(card);
}
}
}
}
int index = 0;
foreach (CardDataQ qcard in shown_cards)
{
if (index < all_list.Count)
{
CollectionCard dcard = all_list[index];
dcard.SetCard(qcard.card, qcard.variant, 0);
card_list.Add(dcard);
if (!dcard.gameObject.activeSelf)
dcard.gameObject.SetActive(true);
index++;
}
}
for (int i = index; i < all_list.Count; i++)
all_list[i].gameObject.SetActive(false);
update_grid = true;
update_grid_timer = 0f;
scroll_rect.verticalNormalizedPosition = 1f;
RefreshCardsQuantities();
}
private void RefreshCardsQuantities()
{
UserData udata = Authenticator.Get().UserData;
foreach (CollectionCard card in card_list)
{
CardData icard = card.GetCard();
VariantData ivariant = card.GetVariant();
bool owned = IsCardOwned(udata, icard, ivariant, 1);
int quantity = udata.GetCardQuantity(icard, ivariant);
card.SetQuantity(quantity);
card.SetGrayscale(!owned);
}
}
private void RefreshDeckList()
{
foreach (DeckLine line in deck_lines)
line.Hide();
deck_cards.Clear();
editing_deck = false;
saving = false;
UserData udata = Authenticator.Get().UserData;
if (udata == null)
return;
int index = 0;
foreach (UserDeckData deck in udata.decks)
{
if (index < deck_lines.Length)
{
DeckLine line = deck_lines[index];
line.SetLine(udata, deck);
}
index++;
}
if (index < deck_lines.Length)
{
DeckLine line = deck_lines[index];
line.SetLine("+");
}
RefreshCardsQuantities();
}
private void RefreshDeck(UserDeckData deck)
{
deck_title.text = "Deck Name";
current_deck_tid = GameTool.GenerateRandomID(7);
deck_cards.Clear();
saving = false;
editing_deck = true;
foreach (IconButton btn in hero_powers)
btn.Deactivate();
if (deck != null)
{
deck_title.text = deck.title;
current_deck_tid = deck.tid;
foreach (IconButton btn in hero_powers)
{
if (deck.hero != null && btn.GetValue() == deck.hero.tid)
btn.Activate();
}
for (int i = 0; i < deck.cards.Length; i++)
{
CardData card = CardData.Get(deck.cards[i].tid);
VariantData variant = VariantData.Get(deck.cards[i].variant);
if (card != null && variant != null)
{
AddDeckCard(card, variant, deck.cards[i].quantity);
}
}
}
RefreshDeckCards();
}
private void RefreshDeckCards()
{
foreach (DeckLine line in deck_card_lines)
line.Hide();
List list = new List();
foreach (UserCardData card in deck_cards)
{
CardDataQ acard = new CardDataQ();
acard.card = CardData.Get(card.tid);
acard.variant = VariantData.Get(card.variant);
acard.quantity = card.quantity;
list.Add(acard);
}
list.Sort((CardDataQ a, CardDataQ b) => { return a.card.title.CompareTo(b.card.title); });
UserData udata = Authenticator.Get().UserData;
int index = 0;
int count = 0;
foreach (CardDataQ card in list)
{
if (index >= deck_card_lines.Count)
CreateDeckCard();
if (index < deck_card_lines.Count)
{
DeckLine line = deck_card_lines[index];
if (line != null)
{
line.SetLine(card.card, card.variant, card.quantity, !IsCardOwned(udata, card.card, card.variant, card.quantity));
count += card.quantity;
}
}
index++;
}
deck_quantity.text = count + "/" + GameplayData.Get().deck_size;
deck_quantity.color = count >= GameplayData.Get().deck_size ? Color.white : Color.red;
RefreshCardsQuantities();
}
// 刷新新手卡组
private void RefreshStarterDeck()
{
UserData udata = Authenticator.Get().UserData;
if (udata != null && (udata.cards.Length == 0 || udata.rewards.Length == 0))
{
if (GameplayData.Get().starter_decks.Length > 0)
{
StarterDeckPanel.Get().Show();
}
}
}
//-------- Deck editing actions
private void CreateDeckCard()
{
GameObject deck_line = Instantiate(deck_cards_prefab, deck_grid.transform);
DeckLine line = deck_line.GetComponent();
deck_card_lines.Add(line);
float height = deck_card_lines.Count * 70f + 20f;
deck_content.sizeDelta = new Vector2(deck_content.sizeDelta.x, height);
line.onClick += OnClickCardLine;
line.onClickRight += OnRightClickCardLine;
}
private void AddDeckCard(CardData card, VariantData variant, int quantity = 1)
{
AddDeckCard(card.id, variant.id, quantity);
}
private void RemoveDeckCard(CardData card, VariantData variant)
{
RemoveDeckCard(card.id, variant.id);
}
private void AddDeckCard(string tid, string variant, int quantity = 1)
{
UserCardData ucard = GetDeckCard(tid, variant);
if (ucard != null)
{
ucard.quantity += quantity;
}
else
{
ucard = new UserCardData(tid, variant);
ucard.quantity = quantity;
deck_cards.Add(ucard);
}
}
private void RemoveDeckCard(string tid, string variant)
{
for (int i = deck_cards.Count - 1; i >= 0; i--)
{
UserCardData ucard = deck_cards[i];
if (ucard.tid == tid && ucard.variant == variant)
{
ucard.quantity--;
if(ucard.quantity <= 0)
deck_cards.RemoveAt(i);
}
}
}
private UserCardData GetDeckCard(string tid, string variant)
{
foreach (UserCardData ucard in deck_cards)
{
if (ucard.tid == tid && ucard.variant == variant)
return ucard;
}
return null;
}
// 保存卡组
private void SaveDeck()
{
int totalCardCount = 0;
foreach (UserCardData card in deck_cards)
{
totalCardCount += card.quantity;
}
if (totalCardCount == 0)
{
ShowNotification("卡组为空,无法保存");
return;
}
if (totalCardCount != GameplayData.Get().deck_size)
{
ShowNotification("卡组数量错误,无法保存。当前总数: " + totalCardCount + ", 需要: " + GameplayData.Get().deck_size);
return;
}
UserData udata = Authenticator.Get().UserData;
UserDeckData udeck = new UserDeckData();
udeck.tid = current_deck_tid;
udeck.title = deck_title.text;
udeck.hero = new UserCardData();
udeck.hero.tid = GetSelectedHeroId();
udeck.hero.variant = VariantData.GetDefault().id;
udeck.cards = deck_cards.ToArray();
saving = true;
if (Authenticator.Get().IsTest())
SaveDeckTest(udata, udeck);
if (Authenticator.Get().IsApi())
SaveDeckAPI(udata, udeck);
ShowDeckList();
}
private async void SaveDeckTest(UserData udata, UserDeckData udeck)
{
udata.SetDeck(udeck);
await Authenticator.Get().SaveUserData();
ReloadUserDecks();
}
private async void SaveDeckAPI(UserData udata, UserDeckData udeck)
{
string url = ApiClient.ServerURL + "/users/deck/" + udeck.tid;
string jdata = ApiTool.ToJson(udeck);
WebResponse res = await ApiClient.Get().SendPostRequest(url, jdata);
UserDeckData[] decks = ApiTool.JsonToArray(res.data);
saving = res.success;
if (res.success && decks != null)
{
udata.decks = decks;
await Authenticator.Get().SaveUserData();
ReloadUserDecks();
}
}
private async void DeleteDeck(string deck_tid)
{
UserData udata = Authenticator.Get().UserData;
UserDeckData udeck = udata.GetDeck(deck_tid);
List decks = new List(udata.decks);
decks.Remove(udeck);
udata.decks = decks.ToArray();
if (Authenticator.Get().IsApi())
{
string url = ApiClient.ServerURL + "/users/deck/" + deck_tid;
await ApiClient.Get().SendRequest(url, "DELETE", "");
}
await Authenticator.Get().SaveUserData();
ReloadUserDecks();
}
//---- Left Panel Filters Clicks -----------
public void OnClickTeam(IconButton button)
{
filter_team = null;
if (button.IsActive())
{
foreach (TeamData team in TeamData.GetAll())
{
if (button.GetValue() == TeamTitleData.Team(team.id))
filter_team = team;
}
}
RefreshCards();
}
public void OnChangeToggle()
{
RefreshCards();
}
public void OnChangeDropdown()
{
filter_dropdown = sort_dropdown.value;
RefreshCards();
}
public void OnChangeSearch()
{
filter_search = search.text;
RefreshCards();
}
//---- Card grid clicks ----------
public void OnClickCard(CardUI card)
{
if (!editing_deck)
{
CardZoomPanel.Get().ShowCard(card.GetCard(), card.GetVariant());
return;
}
CardData icard = card.GetCard();
VariantData variant = card.GetVariant();
if (icard != null)
{
int in_deck = CountDeckCards(icard, variant);
int in_deck_same = CountDeckCards(icard);
UserData udata = Authenticator.Get().UserData;
bool owner = IsCardOwned(udata, card.GetCard(), card.GetVariant(), in_deck + 1);
bool deck_limit = in_deck_same < GameplayData.Get().deck_duplicate_max;
bool ssr_limit = CheckSSRLimit(icard);
if (owner && deck_limit && ssr_limit)
{
AddDeckCard(icard, variant);
RefreshDeckCards();
}
else
{
if (!owner)
ShowNotification("卡牌数量不足");
else if (!deck_limit)
ShowNotification("相同卡牌最多只能添加 " + GameplayData.Get().deck_duplicate_max + " 张");
else if (!ssr_limit)
ShowNotification("SSR以上卡牌最多只能添加 " + GameplayData.Get().deck_ssr_max + " 张");
}
}
}
public void OnClickCardRight(CardUI card)
{
CardZoomPanel.Get().ShowCard(card.GetCard(), card.GetVariant());
}
//---- Right Panel Click -------
public void OnClickDeckLine(DeckLine line)
{
if (line.IsHidden() || saving)
return;
UserDeckData deck = line.GetUserDeck();
RefreshDeck(deck);
ShowDeckCards();
}
private void OnClickCardLine(DeckLine line)
{
CardData card = line.GetCard();
VariantData variant = line.GetVariant();
if (card != null)
{
RemoveDeckCard(card, variant);
}
RefreshDeckCards();
}
private void OnRightClickCardLine(DeckLine line)
{
CardData icard = line.GetCard();
if (icard != null)
CardZoomPanel.Get().ShowCard(icard, line.GetVariant());
}
// ---- Deck editing Click -----
public void OnClickSaveDeck()
{
if (!saving)
{
SaveDeck();
}
}
public void OnClickDeckBack()
{
ShowDeckList();
}
public void OnClickDeleteDeck()
{
if (editing_deck && !string.IsNullOrEmpty(current_deck_tid))
{
DeleteDeck(current_deck_tid);
}
}
public void OnClickDeckDelete(DeckLine line)
{
if (line.IsHidden())
return;
UserDeckData deck = line.GetUserDeck();
if (deck != null)
{
DeleteDeck(deck.tid);
}
}
// ---- Getters -----
public int CountDeckCards(CardData card, VariantData cvariant)
{
int count = 0;
foreach (UserCardData ucard in deck_cards)
{
if (ucard.tid == card.id && ucard.variant == cvariant.id)
count += ucard.quantity;
}
return count;
}
public int CountDeckCards(CardData card)
{
int count = 0;
foreach (UserCardData ucard in deck_cards)
{
if (ucard.tid == card.id)
count += ucard.quantity;
}
return count;
}
private bool IsCardOwned(UserData udata, CardData card, VariantData variant, int quantity)
{
return udata.GetCardQuantity(card, variant) >= quantity;
}
private bool CheckSSRLimit(CardData card)
{
// 检查卡牌稀有度是否 >= 4 (SSR级别)
if (card.rarity.rank >= 4)
{
int ssr_count = CountSSRCards();
return ssr_count < GameplayData.Get().deck_ssr_max;
}
return true;
}
private int CountSSRCards()
{
int count = 0;
foreach (UserCardData ucard in deck_cards)
{
CardData card = CardData.Get(ucard.tid);
if (card != null && card.rarity.rank >= 4)
{
count += ucard.quantity;
}
}
return count;
}
private string GetSelectedHeroId()
{
foreach (IconButton btn in hero_powers)
{
if (btn.IsActive())
return btn.GetValue();
}
return "";
}
private void ShowNotification(string message)
{
WarningText.ShowText(message);
}
public override void Show(bool instant = false)
{
base.Show(instant);
Debug.Log("11111");
RefreshAll();
ShowDeckList();
}
public static CollectionPanel Get()
{
return instance;
}
}
public struct CardDataQ
{
public CardData card;
public VariantData variant;
public int quantity;
}
}