除了充盈都做完了

This commit is contained in:
SoulliesOfficial
2025-10-31 10:02:30 -04:00
parent 5d09ef7b53
commit ee1d3d9c0a
179 changed files with 3239 additions and 200 deletions

View File

@@ -28,6 +28,7 @@ namespace Continentis.MainGame
TextInterpreter.SetFunction("ParameterPercent", new Func<string, string>((paramName) => GetParameterPercent(buff, paramName)));
TextInterpreter.SetFunction("ParameterFloat", new Func<string, string>((paramName) => GetParameterFloat(buff, paramName)));
TextInterpreter.SetFunction("ParameterString", new Func<string, string>((paramName) => GetParameterString(buff, paramName)));
string descriptionToParse = buff.contentSubmodule.originalFunctionText;
string result = DynamicTextInterpreter.Parse(TextInterpreter, descriptionToParse);
buff.contentSubmodule.interpretedFunctionText = result;

View File

@@ -48,20 +48,20 @@ namespace Continentis.MainGame
protected bool FindExistingSameBuff<T1, T2>(out T2 existingBuff, List<T1> buffList) where T1 : BuffBase<T> where T2 : BuffBase<T>
{
existingBuff = null;
Debug.Log($"Searching for existing buff of type: {this.GetType()} in buff list of count: {buffList.Count}");
//Debug.Log($"Searching for existing buff of type: {this.GetType()} in buff list of count: {buffList.Count}");
foreach (T1 buff in buffList)
{
Debug.Log($"existing buff type: {buff.GetType().AssemblyQualifiedName}, this buff type: {this.GetType().AssemblyQualifiedName}");
//Debug.Log($"existing buff type: {buff.GetType().AssemblyQualifiedName}, this buff type: {this.GetType().AssemblyQualifiedName}");
if (buff.GetType() == this.GetType())
{
Debug.Log("Found existing buff of the same type.");
//Debug.Log("Found existing buff of the same type.");
existingBuff = buff as T2;
Debug.Log(existingBuff == null);
//Debug.Log(existingBuff == null);
return true;
}
else
{
Debug.Log("Buff types do not match.");
//Debug.Log("Buff types do not match.");
}
}

View File

@@ -117,44 +117,44 @@ namespace Continentis.MainGame
public class EventSubmodule : BuffSubmodule
{
public OrderedDictionary<string, EventUnit> onCombatStart; //战斗开始时
public OrderedDictionary<string, EventUnit> onCombatEnd; //战斗结束时
public OrderedDictionary<string, PrioritizedAction> onCombatStart; //战斗开始时
public OrderedDictionary<string, PrioritizedAction> onCombatEnd; //战斗结束时
public OrderedDictionary<string, EventUnit> onRoundStart; //每回合开始时
public OrderedDictionary<string, EventUnit> onRoundEnd; //每回合结束时
public OrderedDictionary<string, PrioritizedAction> onRoundStart; //每回合开始时
public OrderedDictionary<string, PrioritizedAction> onRoundEnd; //每回合结束时
public OrderedDictionary<string, EventUnit> onActionStart; //每次行动开始时
public OrderedDictionary<string, EventUnit> onActionEnd; //每次行动结束时
public OrderedDictionary<string, PrioritizedAction> onActionStart; //每次行动开始时
public OrderedDictionary<string, PrioritizedAction> onActionEnd; //每次行动结束时
public OrderedDictionary<string, EventUnit<CharacterBase, IntendedCard, CharacterBase>> onOpponentDecideAction; //对手AI决定行动时参数为对手和原定的目标角色
public OrderedDictionary<string, PrioritizedAction<CharacterBase, IntendedCard, CharacterBase>> onOpponentDecideAction; //对手AI决定行动时参数为对手和原定的目标角色
public OrderedDictionary<string, EventUnit<AttackResult>> onGetAttacked; //被攻击后,参数为伤害结果
public OrderedDictionary<string, PrioritizedAction<AttackResult>> onGetAttacked; //被攻击后,参数为伤害结果
public OrderedDictionary<string, EventUnit<CardInstance>> onDrawCard; //抽到卡牌时
public OrderedDictionary<string, EventUnit<CardInstance, List<CharacterBase>>> onBeforePlayCard; //使用卡牌前,参数为目标列表
public OrderedDictionary<string, EventUnit<CardInstance, List<CharacterBase>>> onAfterPlayCard; //使用卡牌后,参数为目标列表
public OrderedDictionary<string, EventUnit<CardInstance>> onDiscardCard; //卡牌被弃牌时
public OrderedDictionary<string, EventUnit<CardInstance>> onExhaustCard; //卡牌被消耗时
public OrderedDictionary<string, PrioritizedAction<CardInstance>> onDrawCard; //抽到卡牌时
public OrderedDictionary<string, PrioritizedAction<CardInstance, List<CharacterBase>>> onBeforePlayCard; //使用卡牌前,参数为目标列表
public OrderedDictionary<string, PrioritizedAction<CardInstance, List<CharacterBase>>> onAfterPlayCard; //使用卡牌后,参数为目标列表
public OrderedDictionary<string, PrioritizedAction<CardInstance>> onDiscardCard; //卡牌被弃牌时
public OrderedDictionary<string, PrioritizedAction<CardInstance>> onExhaustCard; //卡牌被消耗时
public EventSubmodule(BuffBase<T> buff) : base(buff)
{
onCombatStart = new OrderedDictionary<string, EventUnit>();
onCombatEnd = new OrderedDictionary<string, EventUnit>();
onCombatStart = new OrderedDictionary<string, PrioritizedAction>();
onCombatEnd = new OrderedDictionary<string, PrioritizedAction>();
onRoundStart = new OrderedDictionary<string, EventUnit>();
onRoundEnd = new OrderedDictionary<string, EventUnit>();
onRoundStart = new OrderedDictionary<string, PrioritizedAction>();
onRoundEnd = new OrderedDictionary<string, PrioritizedAction>();
onActionStart = new OrderedDictionary<string, EventUnit>();
onActionEnd = new OrderedDictionary<string, EventUnit>();
onActionStart = new OrderedDictionary<string, PrioritizedAction>();
onActionEnd = new OrderedDictionary<string, PrioritizedAction>();
onGetAttacked = new OrderedDictionary<string, EventUnit<AttackResult>>();
onOpponentDecideAction = new OrderedDictionary<string, EventUnit<CharacterBase, IntendedCard, CharacterBase>>();
onGetAttacked = new OrderedDictionary<string, PrioritizedAction<AttackResult>>();
onOpponentDecideAction = new OrderedDictionary<string, PrioritizedAction<CharacterBase, IntendedCard, CharacterBase>>();
onDrawCard = new OrderedDictionary<string, EventUnit<CardInstance>>();
onBeforePlayCard = new OrderedDictionary<string, EventUnit<CardInstance, List<CharacterBase>>>();
onAfterPlayCard = new OrderedDictionary<string, EventUnit<CardInstance, List<CharacterBase>>>();
onDiscardCard = new OrderedDictionary<string, EventUnit<CardInstance>>();
onExhaustCard = new OrderedDictionary<string, EventUnit<CardInstance>>();
onDrawCard = new OrderedDictionary<string, PrioritizedAction<CardInstance>>();
onBeforePlayCard = new OrderedDictionary<string, PrioritizedAction<CardInstance, List<CharacterBase>>>();
onAfterPlayCard = new OrderedDictionary<string, PrioritizedAction<CardInstance, List<CharacterBase>>>();
onDiscardCard = new OrderedDictionary<string, PrioritizedAction<CardInstance>>();
onExhaustCard = new OrderedDictionary<string, PrioritizedAction<CardInstance>>();
}
}
@@ -252,6 +252,19 @@ namespace Continentis.MainGame
remainingCount = Mathf.Min(remainingCount, maximumCount);
onCountChanged?.Invoke(remainingCount);
}
/// <summary>
/// 选择更高的持续时间和剩余时间。
/// </summary>
public void PickHigherCount(CountSubmodule other)
{
if (isInfinite)
{
return;
}
maximumCount = Mathf.Max(maximumCount, other.maximumCount);
remainingCount = Mathf.Max(remainingCount, other.remainingCount);
}
}
@@ -289,9 +302,9 @@ namespace Continentis.MainGame
stackUpperLimit = keepMaximal ? Mathf.Max(stackUpperLimit, upperLimit) : upperLimit;
}
public void PickHigherStack(int newAmount)
public void PickHigherStack(UnitedStackSubmodule other)
{
stackAmount = Mathf.Max(stackAmount, newAmount);
stackAmount = Mathf.Max(stackAmount, other.stackAmount);
if (stackUpperLimit > 0)
{
stackAmount = Mathf.Min(stackAmount, stackUpperLimit);
@@ -339,6 +352,11 @@ namespace Continentis.MainGame
IntegerRange.OnBecomeZero();
}
}
if(buff is CharacterBuffBase characterBuff)
{
characterBuff.iconSubmodule?.Update();
}
}
public void ClearAllStacks()

View File

@@ -58,7 +58,7 @@ namespace Continentis.MainGame.Card
public static CardInstance GenerateCardInstance(CardLogicBase logic, ICardOwner owner, string pileName, int index = -1)
{
CardInstance cardInstance = new CardInstance(logic, owner, pileName, index);
cardInstance.cardLogic.Initialize();
//cardInstance.cardLogic.Initialize();
return cardInstance;
}

View File

@@ -86,7 +86,7 @@ namespace Continentis.MainGame.Card
if (HasKeyword("Instant")) //如果是“瞬发”牌,添加抽牌后立刻打出的事件
{
eventSubmodule.onDraw.InsertByPriority("Instant", new EventUnit(() =>
eventSubmodule.onDraw.InsertByPriority("Instant", new PrioritizedAction(() =>
{
DetectTargetsValidity(out List<CharacterBase> valid, out _, out _);
Play(SetRandomTargets(valid), user);

View File

@@ -246,7 +246,7 @@ namespace Continentis.MainGame.Card
}
else if(!HasKeyword("Reuse"))
{
CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.DiscardCard(cardInstance));
CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.DiscardCard(cardInstance, false));
CommandQueueManager.Instance.AddCommand(new Cmd_Function(() =>
{
if (handCardView != null)

View File

@@ -12,40 +12,40 @@ namespace Continentis.MainGame.Card
public UnityAction<CharacterBase> onTargeting; //选中目标时
public UnityAction onUntargeting; //取消选中目标时
public OrderedDictionary<string, EventUnit> onCombatStart; //战斗开始时
public OrderedDictionary<string, EventUnit> onCombatEnd; //战斗结束时
public OrderedDictionary<string, PrioritizedAction> onCombatStart; //战斗开始时
public OrderedDictionary<string, PrioritizedAction> onCombatEnd; //战斗结束时
public OrderedDictionary<string, EventUnit> onRoundStart; //每回合开始时
public OrderedDictionary<string, EventUnit> onRoundEnd; //每回合结束时
public OrderedDictionary<string, PrioritizedAction> onRoundStart; //每回合开始时
public OrderedDictionary<string, PrioritizedAction> onRoundEnd; //每回合结束时
public OrderedDictionary<string, EventUnit> onActionStart; //每次行动开始时
public OrderedDictionary<string, EventUnit> onActionEnd; //每次行动结束时
public OrderedDictionary<string, PrioritizedAction> onActionStart; //每次行动开始时
public OrderedDictionary<string, PrioritizedAction> onActionEnd; //每次行动结束时
public OrderedDictionary<string, EventUnit> onDraw; //抽到此卡牌时
public OrderedDictionary<string, EventUnit<List<CharacterBase>>> onBeforePlay; //使用此卡牌前,参数为目标列表
public OrderedDictionary<string, EventUnit<List<CharacterBase>>> onAfterPlay; //使用此卡牌后,参数为目标列表
public OrderedDictionary<string, EventUnit> onDiscard; //此卡牌被弃牌时
public OrderedDictionary<string, EventUnit> onExhaust; //此卡牌被消耗时
public OrderedDictionary<string, PrioritizedAction> onDraw; //抽到此卡牌时
public OrderedDictionary<string, PrioritizedAction<List<CharacterBase>>> onBeforePlay; //使用此卡牌前,参数为目标列表
public OrderedDictionary<string, PrioritizedAction<List<CharacterBase>>> onAfterPlay; //使用此卡牌后,参数为目标列表
public OrderedDictionary<string, PrioritizedCheckAndEffect> onInitiativeDiscard; //此卡牌被主动弃牌时如果读到任意一个true打断弃牌行为执行所有对应效果
public OrderedDictionary<string, PrioritizedAction> onExhaust; //此卡牌被消耗时
public EventSubmodule(CardLogicBase card) : base(card)
{
onTargeting += card.TargetingEffect;
onUntargeting = card.UntargetingEffect;
onCombatStart = new OrderedDictionary<string, EventUnit>();
onCombatEnd = new OrderedDictionary<string, EventUnit>();
onCombatStart = new OrderedDictionary<string, PrioritizedAction>();
onCombatEnd = new OrderedDictionary<string, PrioritizedAction>();
onRoundStart = new OrderedDictionary<string, EventUnit>();
onRoundEnd = new OrderedDictionary<string, EventUnit>();
onRoundStart = new OrderedDictionary<string, PrioritizedAction>();
onRoundEnd = new OrderedDictionary<string, PrioritizedAction>();
onActionStart = new OrderedDictionary<string, EventUnit>();
onActionEnd = new OrderedDictionary<string, EventUnit>();
onActionStart = new OrderedDictionary<string, PrioritizedAction>();
onActionEnd = new OrderedDictionary<string, PrioritizedAction>();
onDraw = new OrderedDictionary<string, EventUnit>();
onBeforePlay = new OrderedDictionary<string, EventUnit<List<CharacterBase>>>();
onAfterPlay = new OrderedDictionary<string, EventUnit<List<CharacterBase>>>();
onDiscard = new OrderedDictionary<string, EventUnit>();
onExhaust = new OrderedDictionary<string, EventUnit>();
onDraw = new OrderedDictionary<string, PrioritizedAction>();
onBeforePlay = new OrderedDictionary<string, PrioritizedAction<List<CharacterBase>>>();
onAfterPlay = new OrderedDictionary<string, PrioritizedAction<List<CharacterBase>>>();
onInitiativeDiscard = new OrderedDictionary<string, PrioritizedCheckAndEffect>();
onExhaust = new OrderedDictionary<string, PrioritizedAction>();
}
}

View File

@@ -51,5 +51,19 @@ namespace Continentis.MainGame.Card
selectedCards.ForEach(selectEffect);
}));
}
/// <summary>
/// 添加选择手牌的指令无UI直接选择符合条件的卡牌
/// </summary>
/// <param name="commandGroup">目标指令组</param>
public void AddSelectionCommands(ref CommandGroup commandGroup)
{
selectedCards = user.deckSubmodule.HandPile.Filtered(selectCondition).ToList();
commandGroup.AddCommand(new Cmd_Function(() =>
{
selectedCards.ForEach(selectEffect);
}));
}
}
}

View File

@@ -1,3 +1,4 @@
using SLSFramework.UModAssistance;
using UnityEngine;
namespace Continentis.MainGame.Character
@@ -20,4 +21,36 @@ namespace Continentis.MainGame.Character
public abstract void Apply(CharacterBase attachedCharacter, CharacterBase sourceCharacter = null);
}
public partial class CharacterBuffBase
{
/// <summary>
/// 创建一个角色战斗Buff实例
/// 注意此函数依赖ModManager的类型注册功能请确保在Mod加载时已注册对应Buff类型
/// 此函数中的T并不是原型参数而是获取Mod中注册的类型用的
/// </summary>
public T CreateCharacterBuff<T>(params object[] parameters) where T :CharacterCombatBuffBase
{
string buffTypeID = ModManager.GetTypeID(typeof(T));
if (string.IsNullOrEmpty(buffTypeID))
{
Debug.LogError($"Failed to get buff name for type {typeof(T).FullName}");
return null;
}
return ModManager.CreateInstance<T>(buffTypeID, parameters);
}
public T CreateCharacterBuff<T>(string buffTypeID, params object[] parameters) where T :CharacterCombatBuffBase
{
if (string.IsNullOrEmpty(buffTypeID))
{
Debug.LogError($"Failed to get buff name for type {typeof(T).FullName}");
return null;
}
return ModManager.CreateInstance<T>(buffTypeID, parameters);
}
}
}

View File

@@ -115,6 +115,13 @@ namespace Continentis.MainGame.Character
/// <returns></returns>
public bool FocusingCheck(out CharacterCombatBuffBase existingBuff)
{
if (buffType != BuffType.Focusing)
{
Debug.LogError("FocusingCheck只能用于专注类Buff");
existingBuff = null;
return false;
}
// 移除超出上限的专注类Buff
List<CharacterCombatBuffBase> focusingBuffs =
attachedCharacter.combatBuffSubmodule.buffList.Where(buff => buff.buffType == BuffType.Focusing).ToList();

View File

@@ -76,7 +76,7 @@ namespace Continentis.MainGame.Character
/// <param name="ignoreBlock">是否无视格挡</param>
/// <param name="ignoreShield">是否无视护盾</param>
/// <returns>实际造成的伤害</returns>
public int Attack(CharacterBase target, int startDamage, bool ignoreDodge = false, bool ignoreBlock = false, bool ignoreShield = false)
public AttackResult Attack(CharacterBase target, int startDamage, bool triggerAttackEvent = true, bool ignoreDodge = false, bool ignoreBlock = false, bool ignoreShield = false)
{
eventSubmodule.onStartAttack.Invoke(new List<CharacterBase> { target });
@@ -106,9 +106,12 @@ namespace Continentis.MainGame.Character
target.characterView.hudContainer.enablingHUDs["MainAttributesBar"].UpdateHud();
AttackResult attackResult = new AttackResult(this, startDamage, dodged, blocked, shielded, hurt);
eventSubmodule.onFinishAttack.Invoke(new List<CharacterBase> { target }, new List<AttackResult> { attackResult });
return hurt;
if (triggerAttackEvent)
{
eventSubmodule.onFinishAttack.Invoke(new List<CharacterBase> { target }, new List<AttackResult> { attackResult });
}
return attackResult;
}
/// <summary>

View File

@@ -27,6 +27,19 @@ namespace Continentis.MainGame.Character
{
return (T)buffList.FindAll(x => x.GetType() == typeof(T)).Find(x => x.identification == identification);
}
public bool TryGetBuff<T>(out T buff) where T : CharacterCombatBuffBase
{
buff = GetBuff<T>();
return buff != null;
}
public bool TryGetBuffs<T>(out List<T> buffs) where T : CharacterCombatBuffBase
{
List<CharacterCombatBuffBase> foundBuffs = buffList.FindAll(x => x.GetType() == typeof(T));
buffs = foundBuffs.Cast<T>().ToList();
return buffs.Count > 0;
}
public bool HasBuff<T>() where T : CharacterCombatBuffBase
{

View File

@@ -86,11 +86,11 @@ namespace Continentis.MainGame.Character
card.cardLogic.Play(targetList, owner);
}
public CommandGroup DiscardCard(CardInstance card, float interval = 0.1f)
public CommandGroup DiscardCard(CardInstance card, bool initiative, float interval = 0.1f)
{
CommandContext context = new CommandContext();
CommandGroup discardCardGroup = new CommandGroup(ExecutionMode.Sequential, context,
new Cmd_DiscardCards(card.deck, new List<CardInstance>() { card }, interval),
new Cmd_DiscardCards(card.deck, new List<CardInstance>() { card }, initiative, interval),
new Cmd_Function(0, () =>
{
//Debug.Log((context.sharedInfo["DrawnCards"] as List<CardInstance>).Count); //TODO: 弃牌后的处理
@@ -99,7 +99,7 @@ namespace Continentis.MainGame.Character
return discardCardGroup;
}
public CommandGroup DiscardCards(List<CardInstance> cards, float interval = 0.1f)
public CommandGroup DiscardCards(List<CardInstance> cards,bool initiative, float interval = 0.1f)
{
Dictionary<DeckSubmodule, List<CardInstance>> groupedCards = cards.GroupBy(card => card.deck)
.ToDictionary(group => group.Key, group => group.ToList());
@@ -107,7 +107,7 @@ namespace Continentis.MainGame.Character
CommandGroup discardCardGroup = new CommandGroup(ExecutionMode.Sequential, context);
foreach (var kvp in groupedCards)
{
discardCardGroup.AddCommand(new Cmd_DiscardCards(kvp.Key, kvp.Value, interval));
discardCardGroup.AddCommand(new Cmd_DiscardCards(kvp.Key, kvp.Value, initiative, interval));
}
discardCardGroup.AddCommand(new Cmd_Function(0, () =>
{

View File

@@ -8,52 +8,52 @@ namespace Continentis.MainGame.Character
{
public partial class EventSubmodule : SubmoduleBase<CharacterBase>
{
public OrderedDictionary<string, EventUnit> onCombatStart; //战斗开始时
public OrderedDictionary<string, EventUnit> onCombatEnd; //战斗结束时
public OrderedDictionary<string, PrioritizedAction> onCombatStart; //战斗开始时
public OrderedDictionary<string, PrioritizedAction> onCombatEnd; //战斗结束时
public OrderedDictionary<string, EventUnit> onRoundStart; //每回合开始时
public OrderedDictionary<string, EventUnit> onRoundEnd; //每回合结束时
public OrderedDictionary<string, PrioritizedAction> onRoundStart; //每回合开始时
public OrderedDictionary<string, PrioritizedAction> onRoundEnd; //每回合结束时
public OrderedDictionary<string, EventUnit<List<CharacterBase>>> onStartAttack; //开始攻击时,参数为被攻击目标列表
public OrderedDictionary<string, EventUnit<List<CharacterBase>, List<AttackResult>>> onFinishAttack; //完成攻击时,参数为被攻击目标列表和对应的攻击结果列表
public OrderedDictionary<string, EventUnit<CharacterBase, AttackResult>> onGetAttacked; //被攻击时,参数为攻击者和攻击结果
public OrderedDictionary<string, PrioritizedAction<List<CharacterBase>>> onStartAttack; //开始攻击时,参数为被攻击目标列表
public OrderedDictionary<string, PrioritizedAction<List<CharacterBase>, List<AttackResult>>> onFinishAttack; //完成攻击时,参数为被攻击目标列表和对应的攻击结果列表
public OrderedDictionary<string, PrioritizedAction<CharacterBase, AttackResult>> onGetAttacked; //被攻击时,参数为攻击者和攻击结果
public OrderedDictionary<string, EventUnit> onActionStart; //每次行动开始时
public OrderedDictionary<string, EventUnit> onActionEnd; //每次行动结束时
public OrderedDictionary<string, PrioritizedAction> onActionStart; //每次行动开始时
public OrderedDictionary<string, PrioritizedAction> onActionEnd; //每次行动结束时
public OrderedDictionary<string, EventUnit<CardInstance, List<CharacterBase>>> onBeforePlayCard; //使用卡牌前,参数为使用的卡牌
public OrderedDictionary<string, EventUnit<CardInstance, List<CharacterBase>>> onAfterPlayCard; //使用卡牌后,参数为使用的卡牌
public OrderedDictionary<string, PrioritizedAction<CardInstance, List<CharacterBase>>> onBeforePlayCard; //使用卡牌前,参数为使用的卡牌
public OrderedDictionary<string, PrioritizedAction<CardInstance, List<CharacterBase>>> onAfterPlayCard; //使用卡牌后,参数为使用的卡牌
public EventSubmodule(CharacterBase character) : base(character)
{
onCombatStart = new OrderedDictionary<string, EventUnit>();
onCombatEnd = new OrderedDictionary<string, EventUnit>();
onCombatStart = new OrderedDictionary<string, PrioritizedAction>();
onCombatEnd = new OrderedDictionary<string, PrioritizedAction>();
onRoundStart = new OrderedDictionary<string, EventUnit>();
onRoundEnd = new OrderedDictionary<string, EventUnit>();
onRoundStart = new OrderedDictionary<string, PrioritizedAction>();
onRoundEnd = new OrderedDictionary<string, PrioritizedAction>();
onActionStart = new OrderedDictionary<string, EventUnit>();
onActionEnd = new OrderedDictionary<string, EventUnit>();
onActionStart = new OrderedDictionary<string, PrioritizedAction>();
onActionEnd = new OrderedDictionary<string, PrioritizedAction>();
onStartAttack = new OrderedDictionary<string, EventUnit<List<CharacterBase>>>();
onFinishAttack = new OrderedDictionary<string, EventUnit<List<CharacterBase>, List<AttackResult>>>();
onGetAttacked = new OrderedDictionary<string, EventUnit<CharacterBase, AttackResult>>();
onStartAttack = new OrderedDictionary<string, PrioritizedAction<List<CharacterBase>>>();
onFinishAttack = new OrderedDictionary<string, PrioritizedAction<List<CharacterBase>, List<AttackResult>>>();
onGetAttacked = new OrderedDictionary<string, PrioritizedAction<CharacterBase, AttackResult>>();
onBeforePlayCard = new OrderedDictionary<string, EventUnit<CardInstance, List<CharacterBase>>>();
onAfterPlayCard = new OrderedDictionary<string, EventUnit<CardInstance, List<CharacterBase>>>();
onBeforePlayCard = new OrderedDictionary<string, PrioritizedAction<CardInstance, List<CharacterBase>>>();
onAfterPlayCard = new OrderedDictionary<string, PrioritizedAction<CardInstance, List<CharacterBase>>>();
onActionStart.InsertByPriority("StaminaRecover", new EventUnit(() =>
onActionStart.InsertByPriority("StaminaRecover", new PrioritizedAction(() =>
{
owner.ModifyAttribute("Stamina", owner.GetAttribute("StaminaRecoverPerAction"));
owner.ClampAttribute("Stamina", 0, owner.GetAttribute("MaximumStamina"));
}, 999));
onActionStart.InsertByPriority("ManaRecover", new EventUnit(() =>
onActionStart.InsertByPriority("ManaRecover", new PrioritizedAction(() =>
{
owner.ModifyAttribute("Mana", owner.GetAttribute("ManaRecoverPerAction"));
owner.ClampAttribute("Mana", 0, owner.GetAttribute("MaximumMana"));
}, 999));
onActionStart.InsertByPriority("DefenseReset", new EventUnit(() =>
onActionStart.InsertByPriority("DefenseReset", new PrioritizedAction(() =>
{
if (owner.GetAttribute("KeepBlockOnActionStart") <= 0)
{

View File

@@ -169,4 +169,49 @@ namespace Continentis.MainGame.Combat
}
}
}
public partial class CombatCharacterController
{
public List<CharacterBase> GetAllAllies(CharacterBase character, bool includeSelf = false)
{
if (character.fraction is Fraction.Player or Fraction.Ally)
{
List<CharacterBase> alliesList = new List<CharacterBase>(playerHeroes);
alliesList.AddRange(npcs[Fraction.Ally]);
if (!includeSelf)
{
alliesList.Remove(character);
}
return alliesList;
}
else
{
return npcs[character.fraction].Cast<CharacterBase>().ToList();
}
}
public List<CharacterBase> GetAllEnemies(CharacterBase character)
{
if (character.fraction is Fraction.Player or Fraction.Ally)
{
return npcs[Fraction.Enemy].Cast<CharacterBase>().ToList();
}
else if (character.fraction is Fraction.Enemy)
{
List<CharacterBase> enemiesList = new List<CharacterBase>(playerHeroes);
enemiesList.AddRange(npcs[Fraction.Ally]);
return enemiesList;
}
else // Neutral
{
List<CharacterBase> enemiesList = new List<CharacterBase>();
enemiesList.AddRange(npcs[Fraction.Player]);
enemiesList.AddRange(npcs[Fraction.Ally]);
enemiesList.AddRange(npcs[Fraction.Enemy]);
return enemiesList;
}
}
}
}

View File

@@ -11,29 +11,29 @@ namespace Continentis.MainGame.Combat
/// <summary>
/// 战斗开始
/// </summary>
public OrderedDictionary<string, EventUnit> onCombatStart;
public OrderedDictionary<string, PrioritizedAction> onCombatStart;
/// <summary>
/// 战斗结束
/// </summary>
public OrderedDictionary<string, EventUnit> onCombatEnd;
public OrderedDictionary<string, PrioritizedAction> onCombatEnd;
/// <summary>
/// 回合开始
/// </summary>
public OrderedDictionary<string, EventUnit> onRoundStart;
public OrderedDictionary<string, PrioritizedAction> onRoundStart;
/// <summary>
/// 回合结束
/// </summary>
public OrderedDictionary<string, EventUnit> onRoundEnd;
public OrderedDictionary<string, PrioritizedAction> onRoundEnd;
public CombatEventCollection()
{
onCombatStart = new OrderedDictionary<string, EventUnit>();
onCombatEnd = new OrderedDictionary<string, EventUnit>();
onRoundStart = new OrderedDictionary<string, EventUnit>();
onRoundEnd = new OrderedDictionary<string, EventUnit>();
onCombatStart = new OrderedDictionary<string, PrioritizedAction>();
onCombatEnd = new OrderedDictionary<string, PrioritizedAction>();
onRoundStart = new OrderedDictionary<string, PrioritizedAction>();
onRoundEnd = new OrderedDictionary<string, PrioritizedAction>();
}
}
}

View File

@@ -220,7 +220,7 @@ namespace Continentis.MainGame.Combat
List<CardInstance> cardToExhaust = handPile.Where(card => card.cardLogic.HasKeyword("Ethereal")).ToList(); //含有“虚无”关键词的卡牌
List<CardInstance> cardsToDiscard = handPile.Except(cardToRetain).Except(cardToExhaust).ToList(); //其他卡牌,默认丢弃
CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.ExhaustCards(cardToExhaust));
CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.DiscardCards(cardsToDiscard));
CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.DiscardCards(cardsToDiscard, false));
}
characterController.actionOrderList.Remove(currentCharacter);

View File

@@ -17,11 +17,14 @@ namespace Continentis.MainGame.Commands
private readonly List<CardInstance> cardsToDiscard;
private readonly float interval;
private readonly float singleCardAnimationDuration = 0.5f; // 单张卡牌的动画时长
private readonly bool isInitiative;
public Cmd_DiscardCards(DeckSubmodule deck, List<CardInstance> cards, float interval)
public Cmd_DiscardCards(DeckSubmodule deck, List<CardInstance> cards, bool isInitiative, float interval)
{
this.deck = deck;
this.cardsToDiscard = cards;
this.isInitiative = isInitiative;
this.interval = interval;
}
@@ -67,9 +70,19 @@ namespace Continentis.MainGame.Commands
private IObservable<Unit> DiscardCard(CardInstance card)
{
deck.TransferCard(deck.Pile(card.cardLocation.pileName), deck.DiscardPile, card);
card.cardLogic.eventSubmodule.onDiscard.Invoke();
if (isInitiative)
{
if (card.cardLogic.eventSubmodule.onInitiativeDiscard.GetChecks().Any()) // 如果主动弃牌后,有触发条件,则打断弃牌,直接触发效果
{
CommandQueueManager.Instance.AddCommand(new Cmd_Function(() =>
{
card.cardLogic.eventSubmodule.onInitiativeDiscard.GetEffects().ForEach(effect => effect.Invoke());
}));
return Observable.Return(Unit.Default);
}
}
deck.TransferCard(deck.Pile(card.cardLocation.pileName), deck.DiscardPile, card);
card.handCardView.TransferCardView(CombatUIManager.Instance.combatMainPage.discardPile);
RectTransform cardTransform = card.handCardView.cardTransform;

View File

@@ -68,7 +68,7 @@ namespace Continentis.MainGame.Commands
private IObservable<Unit> DiscardCard(CardInstance card)
{
deck.TransferCard(deck.Pile(card.cardLocation.pileName), deck.DrawPile, card);
card.cardLogic.eventSubmodule.onDiscard.Invoke();
//card.cardLogic.eventSubmodule.onInitiativeDiscard.Invoke();
card.handCardView.TransferCardView(CombatUIManager.Instance.combatMainPage.drawPile);

View File

@@ -39,7 +39,7 @@ namespace Continentis.MainGame.Commands
private IObservable<Unit> MoveCardToDrawPile(CardInstance card)
{
deck.TransferCard(deck.DiscardPile, deck.DrawPile, card);
card.cardLogic.eventSubmodule.onDiscard.Invoke();
//card.cardLogic.eventSubmodule.onInitiativeDiscard.Invoke();
card.handCardView.TransferCardView(CombatUIManager.Instance.combatMainPage.drawPile);

View File

@@ -8,33 +8,33 @@ namespace Continentis.MainGame.Equipment
{
public class EventSubmodule : SubmoduleBase<EquipmentBase>
{
public OrderedDictionary<string, EventUnit> onCombatStart; //战斗开始时
public OrderedDictionary<string, EventUnit> onCombatEnd; //战斗结束时
public OrderedDictionary<string, PrioritizedAction> onCombatStart; //战斗开始时
public OrderedDictionary<string, PrioritizedAction> onCombatEnd; //战斗结束时
public OrderedDictionary<string, EventUnit> onRoundStart; //每回合开始时
public OrderedDictionary<string, EventUnit> onRoundEnd; //每回合结束时
public OrderedDictionary<string, PrioritizedAction> onRoundStart; //每回合开始时
public OrderedDictionary<string, PrioritizedAction> onRoundEnd; //每回合结束时
public OrderedDictionary<string, EventUnit<List<CharacterBase>>> onStartAttack; //开始攻击时,参数为被攻击目标列表
public OrderedDictionary<string, EventUnit<List<CharacterBase>, List<AttackResult>>> onFinishAttack; //完成攻击时,参数为被攻击目标列表和对应的攻击结果列表
public OrderedDictionary<string, EventUnit<CharacterBase, AttackResult>> onGetAttacked; //被攻击时,参数为攻击者和攻击结果
public OrderedDictionary<string, PrioritizedAction<List<CharacterBase>>> onStartAttack; //开始攻击时,参数为被攻击目标列表
public OrderedDictionary<string, PrioritizedAction<List<CharacterBase>, List<AttackResult>>> onFinishAttack; //完成攻击时,参数为被攻击目标列表和对应的攻击结果列表
public OrderedDictionary<string, PrioritizedAction<CharacterBase, AttackResult>> onGetAttacked; //被攻击时,参数为攻击者和攻击结果
public OrderedDictionary<string, EventUnit> onActionStart; //每次行动开始时
public OrderedDictionary<string, EventUnit> onActionEnd; //每次行动结束时
public OrderedDictionary<string, PrioritizedAction> onActionStart; //每次行动开始时
public OrderedDictionary<string, PrioritizedAction> onActionEnd; //每次行动结束时
public EventSubmodule(EquipmentBase equipment) : base(equipment)
{
onCombatStart = new OrderedDictionary<string, EventUnit>();
onCombatEnd = new OrderedDictionary<string, EventUnit>();
onCombatStart = new OrderedDictionary<string, PrioritizedAction>();
onCombatEnd = new OrderedDictionary<string, PrioritizedAction>();
onRoundStart = new OrderedDictionary<string, EventUnit>();
onRoundEnd = new OrderedDictionary<string, EventUnit>();
onRoundStart = new OrderedDictionary<string, PrioritizedAction>();
onRoundEnd = new OrderedDictionary<string, PrioritizedAction>();
onActionStart = new OrderedDictionary<string, EventUnit>();
onActionEnd = new OrderedDictionary<string, EventUnit>();
onActionStart = new OrderedDictionary<string, PrioritizedAction>();
onActionEnd = new OrderedDictionary<string, PrioritizedAction>();
onStartAttack = new OrderedDictionary<string, EventUnit<List<CharacterBase>>>();
onFinishAttack = new OrderedDictionary<string, EventUnit<List<CharacterBase>, List<AttackResult>>>();
onGetAttacked = new OrderedDictionary<string, EventUnit<CharacterBase, AttackResult>>();
onStartAttack = new OrderedDictionary<string, PrioritizedAction<List<CharacterBase>>>();
onFinishAttack = new OrderedDictionary<string, PrioritizedAction<List<CharacterBase>, List<AttackResult>>>();
onGetAttacked = new OrderedDictionary<string, PrioritizedAction<CharacterBase, AttackResult>>();
}
}
}

View File

@@ -31,6 +31,7 @@ namespace Continentis.MainGame.UI
this.Priority = buff.Priority;
buff.iconSubmodule.buffIcon = this;
icon.sprite = buff.iconSubmodule.icon;
this.infoBox = null;
PlayApplyAnimation();
UpdateIcon();
}
@@ -43,6 +44,7 @@ namespace Continentis.MainGame.UI
spreadImage.rectTransform.localScale = Vector3.zero;
spreadImage.color = Color.white;
spreadImage.DOColor(new Color(1f, 1f, 1f, 0f), 1.1f).SetEase(Ease.Linear).Play();
spreadImage.maskable = false;
spreadImage.rectTransform.DOScale(4f, 1.2f).SetEase(Ease.OutQuad).OnComplete(() =>
{
LeanPool.Despawn(spreadImage.gameObject);
@@ -63,6 +65,7 @@ namespace Continentis.MainGame.UI
{
string paramKey = synchronizedParameters[index];
Func<string> func = buff.contentSubmodule.parameterGetters[paramKey];
Debug.Log($"Updating buff icon text for parameter {paramKey} with func is {func == null}");
SetText(index, func);
}
@@ -94,8 +97,12 @@ namespace Continentis.MainGame.UI
{
GameObject infoBoxPrefab = MainGameManager.Instance.basePrefabs.informationBox;
RectTransform canvasTransform = CombatUIManager.Instance.hudPage.rectTransform;
infoBox = LeanPool.Spawn(infoBoxPrefab, canvasTransform).GetComponent<InformationBox>();
if (infoBox == null)
{
infoBox = LeanPool.Spawn(infoBoxPrefab, canvasTransform).GetComponent<InformationBox>();
}
BuffTextInterpreter.InterpretText(buff);
string dispelThreshold = buff.dispelThreshold switch
{
@@ -106,7 +113,7 @@ namespace Continentis.MainGame.UI
_ => throw new ArgumentOutOfRangeException()
};
dispelThreshold = dispelThreshold.Localize();
string finalDescription = buff.contentSubmodule.interpretedFunctionText + "\n" + dispelThreshold;
infoBox.Initialize(buff.contentSubmodule.displayName, finalDescription, canvasTransform.InverseTransformPoint(rectTransform.position));
@@ -122,6 +129,20 @@ namespace Continentis.MainGame.UI
LeanPool.Despawn(infoBox.gameObject);
infoBox = null;
}
else
{
Debug.LogWarning("InfoBox is already null on pointer exit.");
}
}
private void OnDisable()
{
if (infoBox != null)
{
Debug.Log("Cleaning up InfoBox from OnDisable.");
LeanPool.Despawn(infoBox.gameObject);
infoBox = null;
}
}
}
}