Files
Continentis/Assets/Scripts/MainGame/Character/CharacterMainFunctions.cs
2025-11-16 09:56:20 -05:00

414 lines
16 KiB
C#

using System.Collections.Generic;
using System.Linq;
using Continentis.MainGame.Card;
using Continentis.MainGame.Equipment;
using SLSFramework.General;
using SLSFramework.UModAssistance;
using UnityEngine;
namespace Continentis.MainGame.Character
{
public partial class CharacterBase
{
public virtual void InitializeCards()
{
string initialPile = this is PlayerHero ? "Draw" : "Pool";
foreach (string cardDataID in data.initialDeckRef)
{
CardInstance.GenerateCardInstance(ModManager.GetData<CardData>(cardDataID), this, initialPile);
}
foreach (EquipmentBase equipment in equipmentSubmodule.currentEquipments)
{
foreach (string cardDataID in equipment.equipmentData.belongingCardDataRefs)
{
CardInstance.GenerateCardInstance(ModManager.GetData<CardData>(cardDataID), this, initialPile);
}
}
}
}
public partial class CharacterBase
{
/// <summary>
/// 检查是否有足够的体力
/// </summary>
public bool CheckEnoughStamina(int staminaCost)
{
return GetAttribute("Stamina") >= staminaCost;
}
/// <summary>
/// 消耗体力
/// </summary>
public void ModifyStamina(int staminaValue)
{
ModifyAttribute("Stamina", staminaValue);
ClampAttribute("Stamina", 0, GetAttribute("MaximumStamina"));
}
/// <summary>
/// 检查是否有足够的魔法
/// </summary>
public bool CheckEnoughMana(int manaCost)
{
return GetAttribute("Mana") >= manaCost;
}
/// <summary>
/// 消耗魔法
/// </summary>
public void ModifyMana(int manaValue)
{
ModifyAttribute("Mana", manaValue);
ClampAttribute("Stamina", 0, GetAttribute("MaximumStamina"));
}
}
public partial class CharacterBase
{
/// <summary>
/// 攻击目标
/// </summary>
/// <param name="target">目标</param>
/// <param name="startDamage">初始伤害</param>
/// <param name="ignoreDodge">是否无视闪避</param>
/// <param name="ignoreBlock">是否无视格挡</param>
/// <param name="ignoreShield">是否无视护盾</param>
/// <returns>实际造成的伤害</returns>
public AttackResult Attack(CharacterBase target, int startDamage, CardInstance attackCard = null, bool triggerAttackEvent = true, bool ignoreDodge = false, bool ignoreBlock = false, bool ignoreShield = false)
{
if (triggerAttackEvent)
{
eventSubmodule.onStartAttack.Invoke(target);
}
//闪避检测:如果闪避成功,直接结束
int modifiedStartDamageForDodge = Mathf.RoundToInt(startDamage * GetRawAttribute("DodgeCheckStartDamageMultiplier", 1));
bool dodged = !ignoreDodge && target.CheckDodge(modifiedStartDamageForDodge);
int hurt = 0;
int blocked = 0;
int shielded = 0;
if (!dodged)
{
int remainingDamageAfterBlock = ignoreBlock ? startDamage : target.CheckBlock(startDamage);
if (remainingDamageAfterBlock > 0)
{
blocked = startDamage - remainingDamageAfterBlock;
int remainingDamageAfterShield = ignoreShield ? remainingDamageAfterBlock : target.CheckShield(remainingDamageAfterBlock);
if (remainingDamageAfterShield > 0)
{
shielded = remainingDamageAfterBlock - remainingDamageAfterShield;
hurt = remainingDamageAfterShield;
target.HealthRemoval(remainingDamageAfterShield);
}
}
}
target.characterView.hudContainer.enablingHUDs["MainAttributesBar"].UpdateHud();
AttackResult attackResult = new AttackResult(this, target, startDamage, attackCard, dodged, blocked, shielded, hurt);
if (triggerAttackEvent)
{
eventSubmodule.onFinishAttack.Invoke(target, attackResult);
combatBuffSubmodule.buffList.For(buff =>
{
buff?.eventSubmodule.onDealAttack.Invoke(attackResult);
});
}
return attackResult;
}
/// <summary>
/// 检查闪避(闪避失败后会清空闪避值)
/// </summary>
/// <param name="damage">即将受到的伤害</param>
/// <returns>是否闪避成功</returns>
public bool CheckDodge(int damage)
{
int dodge = attributeSubmodule.GetGeneralAttribute("Dodge");
if (dodge > 0)
{
bool success = damage <= dodge;
if (!success)
{
attributeSubmodule.generalAttributeGroup.current["Dodge"] = 0;
}
MainGameManager.Instance.basePrefabs.GenerateInfoText("Dodged!", characterView);
return success;
}
return false;
}
/// <summary>
/// 检查格挡(并且扣除格挡值)
/// </summary>
/// <param name="damage">即将受到的伤害</param>
/// <returns>格挡之后的剩余伤害</returns>
public int CheckBlock(int damage)
{
int block = attributeSubmodule.GetGeneralAttribute("Block");
if (block > 0)
{
bool success = damage <= block;
int remainingDamage = 0;
int blockedDamage = block;
if (!success)
{
attributeSubmodule.generalAttributeGroup.current["Block"] = 0;
remainingDamage = damage - block;
}
else
{
attributeSubmodule.generalAttributeGroup.current["Block"] = block - damage;
blockedDamage = damage;
}
MainGameManager.Instance.basePrefabs.GenerateBlockedText(blockedDamage, characterView);
return remainingDamage;
}
return damage;
}
/// <summary>
/// 检查护盾(并且扣除护盾值)
/// </summary>
/// <param name="damage">即将受到的伤害</param>
/// <returns>护盾之后的剩余伤害</returns>
public int CheckShield(int damage)
{
int shield = attributeSubmodule.GetGeneralAttribute("Shield");
if (shield > 0)
{
bool success = damage <= shield;
int remainingDamage = 0;
int blockedDamage = shield;
if (!success)
{
attributeSubmodule.generalAttributeGroup.current["Shield"] = 0;
remainingDamage = damage - shield;
}
else
{
attributeSubmodule.generalAttributeGroup.current["Shield"] = shield - damage;
blockedDamage = damage;
}
MainGameManager.Instance.basePrefabs.GenerateBlockedText(blockedDamage, characterView);
return remainingDamage;
}
return damage;
}
public void HealthRemoval(int damage)
{
ModifyAttribute("Health", -damage);
MainGameManager.Instance.basePrefabs.GenerateHurtText(damage, characterView);
}
public void Heal(int heal)
{
if (heal <= 0) return;
ModifyAttribute("Health", heal);
ClampAttribute("Health", 0, GetAttribute("MaximumHealth"));
MainGameManager.Instance.basePrefabs.GenerateHealText(heal, characterView);
characterView.hudContainer.UpdateAllHUD();
}
}
public partial class CharacterBase
{
/// <summary>
/// 添加格挡(格挡每回合结束后会清空)
/// </summary>
public void AddBlock(int baseBlock, bool applyOffsetAndModifier = true, CharacterBase target = null)
{
target ??= this;
if (!applyOffsetAndModifier)
{
target.ModifyAttribute("Block", baseBlock);
}
else
{
int baseBlockAfterOffset = baseBlock + GetAttribute("BlockGainOffset");
int finalBlock = Mathf.RoundToInt(baseBlockAfterOffset * GetRawAttribute("BlockGainMultiplier", 1));
target.ModifyAttribute("Block", finalBlock);
}
target.characterView.hudContainer.UpdateAllHUD();
}
/// <summary>
/// 添加闪避(闪避在回合结束后或被击中后清空)
/// </summary>
public void AddDodge(int dodge, CharacterBase target = null)
{
int baseDodgeAfterOffset = dodge + GetAttribute("DodgeGainOffset");
int finalDodge = Mathf.RoundToInt(baseDodgeAfterOffset * GetRawAttribute("DodgeGainMultiplier", 1));
target ??= this;
target.ModifyAttribute("Dodge", finalDodge);
target.characterView.hudContainer.UpdateAllHUD();
}
/// <summary>
/// 添加护盾(护盾不会自动清空)
/// </summary>
public void AddShield(int shield, CharacterBase target = null)
{
int baseShieldAfterOffset = shield + GetAttribute("ShieldGainOffset");
int finalShield = Mathf.RoundToInt(baseShieldAfterOffset * GetRawAttribute("ShieldGainMultiplier", 1));
target ??= this;
target.ModifyAttribute("Shield", finalShield);
target.characterView.hudContainer.UpdateAllHUD();
}
}
public partial class CharacterBase
{
public virtual void RegisterIntention(params IntentionBase[] intentions)
{
intentionSubmodule.allIntentions.AddRange(intentions);
}
public virtual void IntentionBrain()
{
List<IntentionBase> availableIntentions = intentionSubmodule.allIntentions.Where(intention => intention.Condition()).ToList();
availableIntentions.Sort();
intentionSubmodule.currentIntention = availableIntentions.FirstOrDefault() ?? new IntentionBase(intentionSubmodule);
intentionSubmodule.currentIntention.RefreshCardWeights();
intentionSubmodule.currentIntention.RefreshTargets();
}
public virtual void GetIntendedCards()
{
bool CanAfford(CardInstance card, int stamina, int mana)
{
return card.GetAttribute("StaminaCost") <= stamina &&
card.GetAttribute("ManaCost") <= mana;
}
bool CheckAvailabilityAndSetTargets(CardInstance card, out List<CharacterBase> targets)
{
card.DetectTargetsValidity(out List<CharacterBase> valid, out _, out _);
if (valid.Count == 0)
{
targets = null;
return false; // 无有效目标或无法使用则跳过
}
targets = card.SetRandomTargets(valid);
return true;
}
IntentionBase currentIntention = intentionSubmodule.currentIntention;
List<CardInstance> availableCards = deckSubmodule.PoolPile;
List<IntendedCard> intended = new List<IntendedCard>();
int predictedStamina = Mathf.Min(GetAttribute("MaximumStamina"), GetAttribute("Stamina") + GetAttribute("StaminaRecoverPerAction"));
int remainingStamina = predictedStamina - currentIntention.guaranteedStamina;
int predictedMana = Mathf.Min(GetAttribute("MaximumMana"), GetAttribute("Mana") + GetAttribute("ManaRecoverPerAction"));
int remainingMana = predictedMana - currentIntention.guaranteedMana;
List<CardInstance> forced = new List<CardInstance>();
List<CardInstance> normal = new List<CardInstance>();
foreach (CardInstance card in availableCards)
{
if (card.weightSubmodule.forceUse)
{
forced.Add(card);
}
else
{
normal.Add(card);
}
}
intentionSubmodule.intendedCards.Clear();
//(characterView.hudContainer.enablingHUDs["Intention"] as Intention)?.Clear();
// 1. 优先处理强制选择卡牌
foreach (CardInstance card in forced)
{
if (currentIntention.maxCardCount > 0 && intended.Count >= currentIntention.maxCardCount)
{
break; // 已达数量上限
}
if (CanAfford(card, remainingStamina, remainingMana))
{
if(!CheckAvailabilityAndSetTargets(card, out List<CharacterBase> targets))
{
continue; // 无有效目标或无法使用则跳过
}
intended.Add(new IntendedCard(card, targets));
remainingStamina -= card.GetAttribute("StaminaCost");
remainingMana -= card.GetAttribute("ManaCost");
}
// 行动力不足则跳过该卡
}
// 2. 在剩余普通卡牌中基于权重随机选取
while (intended.Count < currentIntention.maxCardCount)
{
// 筛选出当前资源下还能出的牌
List<CardInstance> affordableCards = normal.FindAll(card => CanAfford(card, remainingStamina, remainingMana));
if (affordableCards.Count == 0)
{
break;
}
float totalWeight = affordableCards.Sum(card => card.weightSubmodule.currentWeight);
if (totalWeight <= 0f) break;
float r = Random.value * totalWeight;
float accum = 0f;
CardInstance chosen = null;
foreach (CardInstance card in affordableCards)
{
accum += card.weightSubmodule.currentWeight;
if (r <= accum)
{
chosen = card;
break;
}
}
if (chosen != null)
{
if (!CheckAvailabilityAndSetTargets(chosen, out List<CharacterBase> targets))
{
normal.Remove(chosen);
continue; // 无有效目标或无法使用则跳过
}
intended.Add(new IntendedCard(chosen, targets));
normal.Remove(chosen);
remainingStamina -= chosen.GetAttribute("StaminaCost");
remainingMana -= chosen.GetAttribute("ManaCost");
}
}
intentionSubmodule.intendedCards.AddRange(intended);
}
}
}