Files
Continentis/Assets/Scripts/MainGame/Card/CardMainFunctions.cs

357 lines
14 KiB
C#
Raw Normal View History

2025-10-03 00:02:43 -04:00
using System;
using System.Collections.Generic;
using System.Linq;
using Continentis.MainGame.Character;
2025-10-23 00:49:44 -04:00
using Continentis.MainGame.Combat;
2025-10-03 00:02:43 -04:00
using Continentis.MainGame.Commands;
2026-04-17 12:01:50 -04:00
using SLSUtilities.General;
using SLSUtilities.UModAssistance;
2025-10-03 00:02:43 -04:00
using UniRx;
2025-10-23 00:49:44 -04:00
using UnityEngine;
using Random = UnityEngine.Random;
2025-10-03 00:02:43 -04:00
namespace Continentis.MainGame.Card
{
2025-11-15 12:17:34 -05:00
public partial class CardInstance
2025-10-03 00:02:43 -04:00
{
2025-10-23 00:49:44 -04:00
/// <summary>
/// 选中目标时触发的效果效果在所有逻辑组件的Targeting之前执行在SetUp函数生成EventSubmodule的时候
/// 如果必须需要在逻辑组件之后执行请重写Initialize函数。
/// </summary>
2025-11-15 12:17:34 -05:00
public virtual void Targeting(CharacterBase target)
2025-10-03 00:02:43 -04:00
{
2026-04-01 12:23:27 -04:00
currentTextTarget = target;
2025-11-15 12:17:34 -05:00
eventSubmodule.onTargeting.Invoke(target);
2025-10-03 00:02:43 -04:00
}
2025-10-23 00:49:44 -04:00
/// <summary>
/// 取消选中目标时触发的效果效果在所有逻辑组件的Untargeting之前执行在SetUp函数生成EventSubmodule的时候
/// 如果必须需要在逻辑组件之后执行请重写Initialize函数。
/// </summary>
2025-11-15 12:17:34 -05:00
public virtual void Untargeting()
2025-10-03 00:02:43 -04:00
{
2026-04-01 12:23:27 -04:00
currentTextTarget = null;
2025-11-15 12:17:34 -05:00
eventSubmodule.onUntargeting.Invoke();
2025-10-03 00:02:43 -04:00
}
}
2025-11-15 12:17:34 -05:00
public partial class CardInstance
2025-10-03 00:02:43 -04:00
{
2025-10-23 00:49:44 -04:00
/// <summary>
/// 刷新卡牌属性
/// </summary>
2025-10-03 00:02:43 -04:00
public void RefreshCardAttributes()
{
if(user == null) return;
attributeSubmodule.RefreshAllAttributes();
2025-12-10 18:22:26 -05:00
Untargeting();
/*if ((handCardView == null && intentionCardView == null))
2025-10-23 00:49:44 -04:00
{
2025-12-10 18:22:26 -05:00
Untargeting();
2025-10-23 00:49:44 -04:00
}
2025-12-10 18:22:26 -05:00
else
{
if (handCardView != null && !handCardView.isSelecting)
{
Untargeting();
}
}*/
2025-11-08 09:50:55 -05:00
contentSubmodule.dirtyMark = true;
2025-10-03 00:02:43 -04:00
}
2025-10-23 00:49:44 -04:00
/// <summary>
/// 根据卡牌内容应用属性变化
/// </summary>
2025-11-15 12:17:34 -05:00
public void ApplyAttributeChangesByCard()
2025-10-03 00:02:43 -04:00
{
2025-11-15 12:17:34 -05:00
cardLogic.ApplyAttributeChangesByCard();
2025-10-03 00:02:43 -04:00
}
}
2025-11-15 12:17:34 -05:00
public partial class CardInstance
2025-10-03 00:02:43 -04:00
{
2025-10-23 00:49:44 -04:00
public virtual void DetectTargetsValidity(out List<CharacterBase> valid, out List<CharacterBase> notMet, out List<CharacterBase> invalid)
2025-10-03 00:02:43 -04:00
{
2025-10-23 00:49:44 -04:00
List<CharacterBase> characters = CombatMainManager.Instance.characterController.characters;
2025-10-30 12:07:59 -04:00
invalid = new List<CharacterBase>(characters);
2025-10-23 00:49:44 -04:00
notMet = new List<CharacterBase>();
2025-10-03 00:02:43 -04:00
valid = new List<CharacterBase>();
int targetCount = attributeSubmodule.targetCount;
if (targetCount <= -2)
{
2025-10-30 12:07:59 -04:00
Debug.LogError("Invalid target count setting on card: " + contentSubmodule.cardName);
2025-10-23 00:49:44 -04:00
return;
2025-10-03 00:02:43 -04:00
}
2025-10-30 12:07:59 -04:00
if (HasKeyword("TargetAll"))
2025-10-03 00:02:43 -04:00
{
2025-10-30 12:07:59 -04:00
valid.AddRange(characters);
2025-10-03 00:02:43 -04:00
}
2025-10-30 12:07:59 -04:00
else
2025-10-03 00:02:43 -04:00
{
2025-11-12 01:20:19 -06:00
if (HasKeyword("TargetAllies") || HasKeyword("Blessing"))
2025-10-03 00:02:43 -04:00
{
2025-10-30 12:07:59 -04:00
valid.AddRange(user.fraction is Fraction.Ally or Fraction.Player
? characters.Where(character => character.fraction is Fraction.Ally or Fraction.Player)
: characters.Where(character => character.fraction == user.fraction));
valid.Remove(user);
2025-10-03 00:02:43 -04:00
}
2025-10-30 12:07:59 -04:00
if (HasKeyword("TargetSelf"))
2025-10-03 00:02:43 -04:00
{
2025-10-30 12:07:59 -04:00
valid.Add(user);
2025-10-03 00:02:43 -04:00
}
2025-10-30 12:07:59 -04:00
if (HasKeyword("TargetEnemies"))
2025-10-03 00:02:43 -04:00
{
2025-10-30 12:07:59 -04:00
valid.AddRange(user.fraction is Fraction.Ally or Fraction.Player
? characters.Where(character => character.fraction is Fraction.Enemy or Fraction.Neutral)
: characters.Where(character => character.fraction != user.fraction));
2026-04-17 12:01:50 -04:00
//处理保护,挑衅等(仅对非全体目标卡牌生效)
2025-10-30 12:07:59 -04:00
if (targetCount != -1)
2025-10-03 00:02:43 -04:00
{
2026-04-17 12:01:50 -04:00
// 保护:被保护的目标不可选
2025-10-30 12:07:59 -04:00
List<CharacterBase> protectedTargets = valid.Where(target => target.statusSubmodule.HasStatus(StatusType.Protected)).ToList();
2025-10-23 00:49:44 -04:00
notMet.AddRange(protectedTargets);
2025-10-30 12:07:59 -04:00
valid.RemoveRange(protectedTargets);
2026-04-17 12:01:50 -04:00
// 挑衅:若使用者处于被挑衅状态,则只能选择挑衅者
if (user.statusSubmodule.HasStatus(StatusType.Provoked) && user.statusSubmodule.provokers.Count > 0)
{
List<CharacterBase> provokers = user.statusSubmodule.provokers;
List<CharacterBase> nonProvokerTargets = valid.Where(target => !provokers.Contains(target)).ToList();
notMet.AddRange(nonProvokerTargets);
valid.RemoveRange(nonProvokerTargets);
}
2025-10-03 00:02:43 -04:00
}
}
}
2025-10-30 12:07:59 -04:00
foreach (CharacterBase validTarget in valid)
2025-10-03 00:02:43 -04:00
{
2025-10-30 12:07:59 -04:00
invalid.Remove(validTarget);
2025-10-03 00:02:43 -04:00
}
}
2025-10-23 00:49:44 -04:00
public virtual List<CharacterBase> SetRandomTargets(List<CharacterBase> valid)
{
List<CharacterBase> targets = new List<CharacterBase>();
int maximumTargets = attributeSubmodule.targetCount;
if (maximumTargets == -1 || maximumTargets >= valid.Count)
{
targets.AddRange(valid);
}
else
{
2026-04-01 12:23:27 -04:00
bool allowDuplicate = HasKeyword(CardKeywords.AllowDuplicateTargets);
if (allowDuplicate)
2025-10-23 00:49:44 -04:00
{
2026-04-01 12:23:27 -04:00
// 放回抽样:可重复选中同一目标
for (int i = 0; i < maximumTargets; i++)
{
targets.Add(valid[Random.Range(0, valid.Count)]);
}
}
else
{
// 不放回抽样(原逻辑)
List<CharacterBase> pool = new List<CharacterBase>(valid);
while (targets.Count < maximumTargets && pool.Count > 0)
{
CharacterBase target = pool[Random.Range(0, pool.Count)];
pool.Remove(target);
targets.Add(target);
}
2025-10-23 00:49:44 -04:00
}
}
return targets;
}
2025-10-03 00:02:43 -04:00
public virtual bool CheckBeforePlay()
{
2026-04-01 12:23:27 -04:00
if (!user.CheckEnoughStamina(GetAttribute(CardAttributes.StaminaCost)))
2025-10-03 00:02:43 -04:00
{
2025-10-23 00:49:44 -04:00
MainGameManager.Instance.basePrefabs.GenerateInfoText("Not Enough Stamina", user.characterView);
2025-10-03 00:02:43 -04:00
return false;
}
2026-04-01 12:23:27 -04:00
if (!user.CheckEnoughMana(GetAttribute(CardAttributes.ManaCost)))
2025-10-03 00:02:43 -04:00
{
2025-10-23 00:49:44 -04:00
MainGameManager.Instance.basePrefabs.GenerateInfoText("Not Enough Mana", user.characterView);
2025-10-03 00:02:43 -04:00
return false;
}
return true;
}
/// <summary>
/// 打出卡牌
/// 注意,这个函数内部包含了命令队列的调用
/// </summary>
/// <param name="targetList">目标列表</param>
/// <param name="user">使用者</param>
2025-12-13 23:28:23 -05:00
/// <param name="noConsumption">是否不消耗资源</param>
2025-10-03 00:02:43 -04:00
/// <param name="willCheckBeforePlay">打出之前是否进行可用性检测</param>
2025-12-13 23:28:23 -05:00
public bool Play(List<CharacterBase> targetList, CharacterBase user = null,
bool willCheckBeforePlay = true, bool noConsumption = false)
2025-10-03 00:02:43 -04:00
{
if (handCardView != null)
{
if (handCardView.isDuringPlaying)
{
return false;
}
handCardView.isDuringPlaying = true;
}
2025-10-23 00:49:44 -04:00
2025-11-15 12:17:34 -05:00
this.user = user ?? CombatMainManager.Instance.currentCharacter;
this.user.recordSubmodule.RecordCardPlay(this);
2025-10-03 00:02:43 -04:00
if (!willCheckBeforePlay || CheckBeforePlay())
{
2025-12-13 23:28:23 -05:00
if (!noConsumption)
{
2026-04-01 12:23:27 -04:00
this.user.ModifyStamina(-GetAttribute(CardAttributes.StaminaCost));
this.user.ModifyMana(-GetAttribute(CardAttributes.ManaCost));
2025-12-13 23:28:23 -05:00
}
2025-10-23 00:49:44 -04:00
Debug.Log($"Starting to play card: {contentSubmodule.cardName}");
2025-10-03 00:02:43 -04:00
2026-04-01 12:23:27 -04:00
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
2025-10-23 00:49:44 -04:00
{
playSubmodule.isDuringPlayEffect = true;
eventSubmodule.onBeforePlay.Invoke(targetList);
2025-11-15 12:17:34 -05:00
this.user.eventSubmodule?.onBeforePlayCard.Invoke(this, targetList);
this.user.combatBuffSubmodule.buffList.For(buff =>
2025-10-23 00:49:44 -04:00
{
2025-11-15 12:17:34 -05:00
buff.eventSubmodule?.onBeforePlayCard.Invoke(this, targetList);
2025-10-23 00:49:44 -04:00
});
}));
2026-03-20 11:56:50 -04:00
CommandQueueManager.Instance.AddCommand(PlayEffect(targetList));
CommandQueueManager.Instance.AddCommand(cardLogic.PlayEffect(targetList));
2026-04-01 12:23:27 -04:00
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
2025-10-23 00:49:44 -04:00
{
eventSubmodule.onAfterPlay.Invoke(targetList);
combatBuffSubmodule.buffList.For(buff => buff.usageSubmodule?.UpdateModule());
2025-11-15 12:17:34 -05:00
this.user.eventSubmodule.onAfterPlayCard.Invoke(this, targetList);
this.user.combatBuffSubmodule.buffList.For(buff =>
2025-10-23 00:49:44 -04:00
{
2025-11-15 12:17:34 -05:00
buff.eventSubmodule?.onAfterPlayCard.Invoke(this, targetList);
2025-10-23 00:49:44 -04:00
});
AfterPlayEffect(targetList);
2025-11-15 12:17:34 -05:00
cardLogic.AfterPlayEffect(targetList);
2025-10-23 00:49:44 -04:00
playSubmodule.isDuringPlayEffect = false;
2025-11-15 09:08:36 -05:00
if (handCardView != null)
{
handCardView.isDuringPlaying = false;
}
2025-10-23 00:49:44 -04:00
}));
2025-10-03 00:02:43 -04:00
return true;
}
else
{
if (handCardView != null)
{
handCardView.isDuringPlaying = false;
}
return false;
}
}
2026-03-20 11:56:50 -04:00
protected virtual CommandGroup PlayEffect(List<CharacterBase> targetList)
2025-10-03 00:02:43 -04:00
{
2026-03-20 11:56:50 -04:00
return new CommandGroup();
2025-10-03 00:02:43 -04:00
}
protected virtual void AfterPlayEffect(List<CharacterBase> targetList)
{
2025-10-30 23:31:29 -04:00
if (contentSubmodule.cardType == CardType.Power)
{
2025-11-15 12:17:34 -05:00
CommandQueueManager.Instance.AddCommand(user.deckSubmodule.UsePowerCard(this));
2025-10-30 23:31:29 -04:00
return;
}
2025-11-01 06:13:58 -04:00
if (HasKeyword("Exhaust"))
{
2025-11-15 12:17:34 -05:00
CommandQueueManager.Instance.AddCommand(user.deckSubmodule.ExhaustCard(this));
2025-11-01 06:13:58 -04:00
return;
}
if(HasKeyword("Exhaustible"))
2025-10-03 00:02:43 -04:00
{
2025-11-15 12:17:34 -05:00
if (!HasAttribute("ExhaustibleCount"))
2025-11-01 06:13:58 -04:00
{
Debug.LogError("Exhaustible card missing ExhaustibleCount attribute: " + contentSubmodule.cardName);
2025-11-15 12:17:34 -05:00
CommandQueueManager.Instance.AddCommand(user.deckSubmodule.ExhaustCard(this));
2025-11-01 06:13:58 -04:00
return;
}
2025-11-15 12:17:34 -05:00
ModifyAttribute("ExhaustibleCount", -1);
2025-11-01 06:13:58 -04:00
2025-11-15 12:17:34 -05:00
if(GetAttribute("ExhaustibleCount") <= 0)
2025-10-03 00:02:43 -04:00
{
2025-11-15 12:17:34 -05:00
CommandQueueManager.Instance.AddCommand(user.deckSubmodule.ExhaustCard(this));
2025-11-01 06:13:58 -04:00
return;
2025-10-03 00:02:43 -04:00
}
2025-11-01 06:13:58 -04:00
}
if (user is PlayerHero playerHero)
{
2025-11-12 00:17:30 -06:00
if(!HasKeyword("Reuseable"))
2025-10-03 00:02:43 -04:00
{
2025-11-15 12:17:34 -05:00
CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.DiscardCard(this, false));
2025-10-23 00:49:44 -04:00
CommandQueueManager.Instance.AddCommand(new Cmd_Function(() =>
2025-10-03 00:02:43 -04:00
{
if (handCardView != null)
{
handCardView.isDuringPlaying = false;
}
}));
}
}
else if (user is CombatNPC npc)
{
2025-11-01 06:13:58 -04:00
2025-10-03 00:02:43 -04:00
}
}
}
2025-11-15 12:17:34 -05:00
public partial class CardInstance
2025-10-03 00:02:43 -04:00
{
2025-11-15 12:17:34 -05:00
public void UpgradeCard()
{
if (owner is not CombatTeam)
{
KeyValuePair<string, List<CardInstance>> currentPile = deck.GetCardLocation(this, out int index);
if (!cardData.upgradeNode.isTerminalNode)
{
2026-04-01 12:23:27 -04:00
// 先 Dispose 旧 Logic再替换避免旧 Logic 的托管订阅泄漏
cardLogic?.Dispose();
2025-11-15 12:17:34 -05:00
DestroyHandCardView();
2025-10-23 00:49:44 -04:00
2025-11-15 12:17:34 -05:00
CardData newData = cardData.upgradeNode.upgradeCards[0]; //后续可改为选择升级方向
CardLogicBase newLogic = CardLogicBase.GenerateCardLogic(newData);
this.cardLogic = newLogic;
newLogic.card = this;
this.cardLogic.Initialize(this);
if (user is PlayerHero)
GenerateHandCardView(CombatUIManager.Instance.combatMainPage.Pile(currentPile.Key), index);
}
}
else
{
}
}
2025-10-03 00:02:43 -04:00
}
}