Files
Continentis/Assets/Scripts/MainGame/Card/CardMainFunctions.cs
SoulliesOfficial ac98ec3aef 更新
2026-04-17 12:01:50 -04:00

357 lines
14 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using Continentis.MainGame.Character;
using Continentis.MainGame.Combat;
using Continentis.MainGame.Commands;
using SLSUtilities.General;
using SLSUtilities.UModAssistance;
using UniRx;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Continentis.MainGame.Card
{
public partial class CardInstance
{
/// <summary>
/// 选中目标时触发的效果效果在所有逻辑组件的Targeting之前执行在SetUp函数生成EventSubmodule的时候
/// 如果必须需要在逻辑组件之后执行请重写Initialize函数。
/// </summary>
public virtual void Targeting(CharacterBase target)
{
currentTextTarget = target;
eventSubmodule.onTargeting.Invoke(target);
}
/// <summary>
/// 取消选中目标时触发的效果效果在所有逻辑组件的Untargeting之前执行在SetUp函数生成EventSubmodule的时候
/// 如果必须需要在逻辑组件之后执行请重写Initialize函数。
/// </summary>
public virtual void Untargeting()
{
currentTextTarget = null;
eventSubmodule.onUntargeting.Invoke();
}
}
public partial class CardInstance
{
/// <summary>
/// 刷新卡牌属性
/// </summary>
public void RefreshCardAttributes()
{
if(user == null) return;
attributeSubmodule.RefreshAllAttributes();
Untargeting();
/*if ((handCardView == null && intentionCardView == null))
{
Untargeting();
}
else
{
if (handCardView != null && !handCardView.isSelecting)
{
Untargeting();
}
}*/
contentSubmodule.dirtyMark = true;
}
/// <summary>
/// 根据卡牌内容应用属性变化
/// </summary>
public void ApplyAttributeChangesByCard()
{
cardLogic.ApplyAttributeChangesByCard();
}
}
public partial class CardInstance
{
public virtual void DetectTargetsValidity(out List<CharacterBase> valid, out List<CharacterBase> notMet, out List<CharacterBase> invalid)
{
List<CharacterBase> characters = CombatMainManager.Instance.characterController.characters;
invalid = new List<CharacterBase>(characters);
notMet = new List<CharacterBase>();
valid = new List<CharacterBase>();
int targetCount = attributeSubmodule.targetCount;
if (targetCount <= -2)
{
Debug.LogError("Invalid target count setting on card: " + contentSubmodule.cardName);
return;
}
if (HasKeyword("TargetAll"))
{
valid.AddRange(characters);
}
else
{
if (HasKeyword("TargetAllies") || HasKeyword("Blessing"))
{
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);
}
if (HasKeyword("TargetSelf"))
{
valid.Add(user);
}
if (HasKeyword("TargetEnemies"))
{
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));
//处理保护,挑衅等(仅对非全体目标卡牌生效)
if (targetCount != -1)
{
// 保护:被保护的目标不可选
List<CharacterBase> protectedTargets = valid.Where(target => target.statusSubmodule.HasStatus(StatusType.Protected)).ToList();
notMet.AddRange(protectedTargets);
valid.RemoveRange(protectedTargets);
// 挑衅:若使用者处于被挑衅状态,则只能选择挑衅者
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);
}
}
}
}
foreach (CharacterBase validTarget in valid)
{
invalid.Remove(validTarget);
}
}
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
{
bool allowDuplicate = HasKeyword(CardKeywords.AllowDuplicateTargets);
if (allowDuplicate)
{
// 放回抽样:可重复选中同一目标
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);
}
}
}
return targets;
}
public virtual bool CheckBeforePlay()
{
if (!user.CheckEnoughStamina(GetAttribute(CardAttributes.StaminaCost)))
{
MainGameManager.Instance.basePrefabs.GenerateInfoText("Not Enough Stamina", user.characterView);
return false;
}
if (!user.CheckEnoughMana(GetAttribute(CardAttributes.ManaCost)))
{
MainGameManager.Instance.basePrefabs.GenerateInfoText("Not Enough Mana", user.characterView);
return false;
}
return true;
}
/// <summary>
/// 打出卡牌
/// 注意,这个函数内部包含了命令队列的调用
/// </summary>
/// <param name="targetList">目标列表</param>
/// <param name="user">使用者</param>
/// <param name="noConsumption">是否不消耗资源</param>
/// <param name="willCheckBeforePlay">打出之前是否进行可用性检测</param>
public bool Play(List<CharacterBase> targetList, CharacterBase user = null,
bool willCheckBeforePlay = true, bool noConsumption = false)
{
if (handCardView != null)
{
if (handCardView.isDuringPlaying)
{
return false;
}
handCardView.isDuringPlaying = true;
}
this.user = user ?? CombatMainManager.Instance.currentCharacter;
this.user.recordSubmodule.RecordCardPlay(this);
if (!willCheckBeforePlay || CheckBeforePlay())
{
if (!noConsumption)
{
this.user.ModifyStamina(-GetAttribute(CardAttributes.StaminaCost));
this.user.ModifyMana(-GetAttribute(CardAttributes.ManaCost));
}
Debug.Log($"Starting to play card: {contentSubmodule.cardName}");
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
{
playSubmodule.isDuringPlayEffect = true;
eventSubmodule.onBeforePlay.Invoke(targetList);
this.user.eventSubmodule?.onBeforePlayCard.Invoke(this, targetList);
this.user.combatBuffSubmodule.buffList.For(buff =>
{
buff.eventSubmodule?.onBeforePlayCard.Invoke(this, targetList);
});
}));
CommandQueueManager.Instance.AddCommand(PlayEffect(targetList));
CommandQueueManager.Instance.AddCommand(cardLogic.PlayEffect(targetList));
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
{
eventSubmodule.onAfterPlay.Invoke(targetList);
combatBuffSubmodule.buffList.For(buff => buff.usageSubmodule?.UpdateModule());
this.user.eventSubmodule.onAfterPlayCard.Invoke(this, targetList);
this.user.combatBuffSubmodule.buffList.For(buff =>
{
buff.eventSubmodule?.onAfterPlayCard.Invoke(this, targetList);
});
AfterPlayEffect(targetList);
cardLogic.AfterPlayEffect(targetList);
playSubmodule.isDuringPlayEffect = false;
if (handCardView != null)
{
handCardView.isDuringPlaying = false;
}
}));
return true;
}
else
{
if (handCardView != null)
{
handCardView.isDuringPlaying = false;
}
return false;
}
}
protected virtual CommandGroup PlayEffect(List<CharacterBase> targetList)
{
return new CommandGroup();
}
protected virtual void AfterPlayEffect(List<CharacterBase> targetList)
{
if (contentSubmodule.cardType == CardType.Power)
{
CommandQueueManager.Instance.AddCommand(user.deckSubmodule.UsePowerCard(this));
return;
}
if (HasKeyword("Exhaust"))
{
CommandQueueManager.Instance.AddCommand(user.deckSubmodule.ExhaustCard(this));
return;
}
if(HasKeyword("Exhaustible"))
{
if (!HasAttribute("ExhaustibleCount"))
{
Debug.LogError("Exhaustible card missing ExhaustibleCount attribute: " + contentSubmodule.cardName);
CommandQueueManager.Instance.AddCommand(user.deckSubmodule.ExhaustCard(this));
return;
}
ModifyAttribute("ExhaustibleCount", -1);
if(GetAttribute("ExhaustibleCount") <= 0)
{
CommandQueueManager.Instance.AddCommand(user.deckSubmodule.ExhaustCard(this));
return;
}
}
if (user is PlayerHero playerHero)
{
if(!HasKeyword("Reuseable"))
{
CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.DiscardCard(this, false));
CommandQueueManager.Instance.AddCommand(new Cmd_Function(() =>
{
if (handCardView != null)
{
handCardView.isDuringPlaying = false;
}
}));
}
}
else if (user is CombatNPC npc)
{
}
}
}
public partial class CardInstance
{
public void UpgradeCard()
{
if (owner is not CombatTeam)
{
KeyValuePair<string, List<CardInstance>> currentPile = deck.GetCardLocation(this, out int index);
if (!cardData.upgradeNode.isTerminalNode)
{
// 先 Dispose 旧 Logic再替换避免旧 Logic 的托管订阅泄漏
cardLogic?.Dispose();
DestroyHandCardView();
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
{
}
}
}
}