using System.Collections; using System.Collections.Generic; using UnityEngine; namespace TcgEngine { //Represent the current state of a player during the game (data only) [System.Serializable] public class Player { public int player_id; public string username; public string avatar; public string cardback; public string deck; public bool is_ai = false; public int ai_level; public bool connected = false; //Connected to server and game public bool ready = false; //Sent all player data, ready to play public int hp; public int hp_max; public int mana = 0; public int mana_max = 0; public int kill_count = 0; public int cards_played_this_turn = 0; // 本回合已上场的卡牌数量 public Dictionary cards_all = new Dictionary(); //Dictionnary for quick access to any card by UID public Card hero = null; public List cards_deck = new List(); //Cards in the player's deck public List cards_hand = new List(); //Cards in the player's hand public List cards_board = new List(); //Cards on the board public List cards_equip = new List(); //Cards equipped by characters public List cards_discard = new List(); //Cards in the player's discard public List cards_secret = new List(); //Cards in the player's secret area public List cards_temp = new List(); //Temporary cards that have just been created, not assigned to any zone yet public List traits = new List(); //Current persistant traits the cards has public List ongoing_traits = new List(); //Current ongoing traits the cards has public List status = new List(); //Current persistant (or with duration) traits the cards has public List ongoing_status = new List(); //Current ongoing traits the cards has public List history_list = new List(); //History of actions performed by the player public Player(int id) { this.player_id = id; } public bool IsReady() { return ready && cards_all.Count > 0; } public bool IsConnected() { return connected || is_ai; } public virtual void ClearOngoing() { ongoing_status.Clear(); ongoing_traits.Clear(); } //---- Cards --------- public void AddCard(List card_list, Card card) { card_list.Add(card); } public void RemoveCard(List card_list, Card card) { card_list.Remove(card); } public virtual void RemoveCardFromAllGroups(Card card) { cards_deck.Remove(card); cards_hand.Remove(card); cards_board.Remove(card); cards_equip.Remove(card); cards_discard.Remove(card); cards_secret.Remove(card); cards_temp.Remove(card); UnequipFromAllCards(card); } public virtual void UnequipFromAllCards(Card equip) { foreach (Card card in cards_board) { if (card.equipped_uid == equip.uid) card.equipped_uid = null; } } public virtual Card GetRandomCard(List card_list, System.Random rand) { if (card_list.Count > 0) return card_list[rand.Next(0, card_list.Count)]; return null; } public bool HasCard(List card_list, Card card) { return card_list.Contains(card); } public Card GetHandCard(string uid) { foreach (Card card in cards_hand) { if (card.uid == uid) return card; } return null; } public Card GetBoardCard(string uid) { foreach (Card card in cards_board) { if (card.uid == uid) return card; } return null; } public Card GetEquipCard(string uid) { foreach (Card card in cards_equip) { if (card.uid == uid) return card; } return null; } public Card GetDeckCard(string uid) { foreach (Card card in cards_deck) { if (card.uid == uid) return card; } return null; } public Card GetDiscardCard(string uid) { foreach (Card card in cards_discard) { if (card.uid == uid) return card; } return null; } public Card GetBearerCard(Card equipment) { foreach (Card card in cards_board) { if (card != null && card.equipped_uid == equipment.uid) return card; } return null; } public Card GetSlotCard(Slot slot) { foreach (Card card in cards_board) { if (card != null && card.slot == slot) return card; } return null; } public Card GetCard(string uid) { if (uid != null) { bool valid = cards_all.TryGetValue(uid, out Card card); if (valid) return card; } return null; } public bool IsOnBoard(Card card) { return card != null && GetBoardCard(card.uid) != null; } //---- Slots --------- public Slot GetRandomSlot(System.Random rand) { return Slot.GetRandom(player_id, rand); } public virtual Slot GetRandomEmptySlot(System.Random rand, List list_mem = null) { List valid = GetEmptySlots(list_mem); if (valid.Count > 0) return valid[rand.Next(0, valid.Count)]; return Slot.None; } public virtual Slot GetRandomOccupiedSlot(System.Random rand, List list_mem = null) { List valid = GetOccupiedSlots(list_mem); if (valid.Count > 0) return valid[rand.Next(0, valid.Count)]; return Slot.None; } public List GetEmptySlots(List list_mem = null) { List valid = list_mem != null ? list_mem : new List(); foreach (Slot slot in Slot.GetAll(player_id)) { Card slot_card = GetSlotCard(slot); if (slot_card == null) valid.Add(slot); } return valid; } public List GetOccupiedSlots(List list_mem = null) { List valid = list_mem != null ? list_mem : new List(); foreach (Slot slot in Slot.GetAll(player_id)) { Card slot_card = GetSlotCard(slot); if (slot_card != null) valid.Add(slot); } return valid; } //------ Custom Traits/Stats --------- public void SetTrait(string id, int value) { CardTrait trait = GetTrait(id); if (trait != null) { trait.value = value; } else { trait = new CardTrait(id, value); traits.Add(trait); } } public void AddTrait(string id, int value) { CardTrait trait = GetTrait(id); if (trait != null) trait.value += value; else SetTrait(id, value); } public void AddOngoingTrait(string id, int value) { CardTrait trait = GetOngoingTrait(id); if (trait != null) { trait.value += value; } else { trait = new CardTrait(id, value); ongoing_traits.Add(trait); } } public void RemoveTrait(string id) { for (int i = traits.Count - 1; i >= 0; i--) { if (traits[i].id == id) traits.RemoveAt(i); } } public CardTrait GetTrait(string id) { foreach (CardTrait trait in traits) { if (trait.id == id) return trait; } return null; } public CardTrait GetOngoingTrait(string id) { foreach (CardTrait trait in ongoing_traits) { if (trait.id == id) return trait; } return null; } public List GetAllTraits() { List all_traits = new List(); all_traits.AddRange(traits); all_traits.AddRange(ongoing_traits); return all_traits; } public int GetTraitValue(TraitData trait) { if (trait != null) return GetTraitValue(trait.id); return 0; } public virtual int GetTraitValue(string id) { int val = 0; CardTrait stat1 = GetTrait(id); CardTrait stat2 = GetOngoingTrait(id); if (stat1 != null) val += stat1.value; if (stat2 != null) val += stat2.value; return val; } public bool HasTrait(TraitData trait) { if (trait != null) return HasTrait(trait.id); return false; } public bool HasTrait(string id) { foreach (CardTrait trait in traits) { if (trait.id == id) return true; } return false; } //---- Status --------- public void AddStatus(StatusData status, int value, int duration) { if (status != null) AddStatus(status.effect, value, duration); } public void AddOngoingStatus(StatusData status, int value) { if (status != null) AddOngoingStatus(status.effect, value); } public void AddStatus(StatusType effect, int value, int duration) { if (effect != StatusType.None) { CardStatus status = GetStatus(effect); if (status == null) { status = new CardStatus(effect, value, duration); this.status.Add(status); } else { status.value += value; status.duration = Mathf.Max(status.duration, duration); status.permanent = status.permanent || duration == 0; } } } public void AddOngoingStatus(StatusType effect, int value) { if (effect != StatusType.None) { CardStatus status = GetOngoingStatus(effect); if (status == null) { status = new CardStatus(effect, value, 0); ongoing_status.Add(status); } else { status.value += value; } } } public void RemoveStatus(StatusType effect) { for (int i = status.Count - 1; i >= 0; i--) { if (status[i].type == effect) status.RemoveAt(i); } } public CardStatus GetStatus(StatusType effect) { foreach (CardStatus status in status) { if (status.type == effect) return status; } return null; } public CardStatus GetOngoingStatus(StatusType effect) { foreach (CardStatus status in ongoing_status) { if (status.type == effect) return status; } return null; } public List GetAllStatus() { List all_status = new List(); all_status.AddRange(status); all_status.AddRange(ongoing_status); return all_status; } public bool HasStatus(StatusType effect) { return GetStatus(effect) != null || GetOngoingStatus(effect) != null; } public virtual int GetStatusValue(StatusType type) { CardStatus status1 = GetStatus(type); CardStatus status2 = GetOngoingStatus(type); int v1 = status1 != null ? status1.value : 0; int v2 = status2 != null ? status2.value : 0; return v1 + v2; } public virtual void ReduceStatusDurations() { for (int i = status.Count - 1; i >= 0; i--) { if (!status[i].permanent) { status[i].duration -= 1; if (status[i].duration <= 0) status.RemoveAt(i); } } } //---- History --------- public void AddHistory(ushort type, Card card) { ActionHistory order = new ActionHistory(); order.type = type; order.card_id = card.card_id; order.card_uid = card.uid; history_list.Add(order); } public void AddHistory(ushort type, Card card, Card target) { ActionHistory order = new ActionHistory(); order.type = type; order.card_id = card.card_id; order.card_uid = card.uid; order.target_uid = target.uid; history_list.Add(order); } public void AddHistory(ushort type, Card card, Player target) { ActionHistory order = new ActionHistory(); order.type = type; order.card_id = card.card_id; order.card_uid = card.uid; order.target_id = target.player_id; history_list.Add(order); } public void AddHistory(ushort type, Card card, AbilityData ability) { ActionHistory order = new ActionHistory(); order.type = type; order.card_id = card.card_id; order.card_uid = card.uid; order.ability_id = ability.id; history_list.Add(order); } public void AddHistory(ushort type, Card card, AbilityData ability, Card target) { ActionHistory order = new ActionHistory(); order.type = type; order.card_id = card.card_id; order.card_uid = card.uid; order.ability_id = ability.id; order.target_uid = target.uid; history_list.Add(order); } public void AddHistory(ushort type, Card card, AbilityData ability, Player target) { ActionHistory order = new ActionHistory(); order.type = type; order.card_id = card.card_id; order.card_uid = card.uid; order.ability_id = ability.id; order.target_id = target.player_id; history_list.Add(order); } public void AddHistory(ushort type, Card card, AbilityData ability, Slot target) { ActionHistory order = new ActionHistory(); order.type = type; order.card_id = card.card_id; order.card_uid = card.uid; order.ability_id = ability.id; order.slot = target; history_list.Add(order); } //---- Action Check --------- public virtual bool CanPayMana(Card card) { if (card.CardData.IsDynamicManaCost()) return true; return mana >= card.GetMana(); } public virtual void PayMana(Card card) { if (!card.CardData.IsDynamicManaCost()) mana -= card.GetMana(); } public virtual bool CanPayAbility(Card card, AbilityData ability) { bool exhaust = !card.exhausted || !ability.exhaust; return exhaust && mana >= ability.mana_cost; } public virtual bool IsDead() { // 原有的死亡判定:血量为0 if (hp <= 0) return true; // 新增的死亡判定:无手牌、无场上卡牌,且卡组中还有牌 if (cards_hand.Count == 0 && cards_board.Count == 0 && cards_deck.Count > 0) return true; // 原有的死亡判定:所有牌都没有了 if (cards_hand.Count == 0 && cards_board.Count == 0 && cards_deck.Count == 0) return true; return false; } //-------------------- //Clone all player variables into another var, used mostly by the AI when building a prediction tree public static void Clone(Player source, Player dest) { dest.player_id = source.player_id; dest.is_ai = source.is_ai; dest.ai_level = source.ai_level; //Commented variables are not needed for ai predictions //dest.username = source.username; //dest.avatar = source.avatar; //dest.deck = source.deck; //dest.connected = source.connected; //dest.ready = source.ready; dest.hp = source.hp; dest.hp_max = source.hp_max; dest.mana = source.mana; dest.mana_max = source.mana_max; Card.CloneNull(source.hero, ref dest.hero); Card.CloneDict(source.cards_all, dest.cards_all); Card.CloneListRef(dest.cards_all, source.cards_board, dest.cards_board); Card.CloneListRef(dest.cards_all, source.cards_equip, dest.cards_equip); Card.CloneListRef(dest.cards_all, source.cards_hand, dest.cards_hand); Card.CloneListRef(dest.cards_all, source.cards_deck, dest.cards_deck); Card.CloneListRef(dest.cards_all, source.cards_discard, dest.cards_discard); Card.CloneListRef(dest.cards_all, source.cards_secret, dest.cards_secret); Card.CloneListRef(dest.cards_all, source.cards_temp, dest.cards_temp); CardStatus.CloneList(source.status, dest.status); CardStatus.CloneList(source.ongoing_status, dest.ongoing_status); } } [System.Serializable] public class ActionHistory { public ushort type; public string card_id; public string card_uid; public string target_uid; public string ability_id; public int target_id; public Slot slot; } }