This commit is contained in:
SoulliesOfficial
2026-04-01 12:23:27 -04:00
parent aff7ac0e03
commit c3b1561375
933 changed files with 114333 additions and 119360 deletions

View File

@@ -79,22 +79,38 @@ namespace Continentis.MainGame.Character
public partial class CharacterBase
{
/// <summary>
/// 攻击目标
/// 攻击目标(新版本,使用 AttackContext 携带标签与来源信息)。
/// </summary>
/// <param name="target">目标</param>
/// <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)
/// <param name="context">攻击上下文(包含来源卡牌、标签等);传 null 等价于默认上下文</param>
/// <returns>攻击结果</returns>
public AttackResult Attack(CharacterBase target, int startDamage, AttackContext context)
{
if (triggerAttackEvent)
context ??= new AttackContext();
bool isSilent = context.HasTag(AttackTags.Silent);
bool isHpRemoval = context.HasTag(AttackTags.HpRemoval);
bool isReactive = context.HasTag(AttackTags.Reactive);
bool ignoreDodge = context.HasAnyTag(AttackTags.GuaranteedHit, AttackTags.HpRemoval);
bool ignoreBlock = context.HasAnyTag(AttackTags.Penetrating, AttackTags.HpRemoval);
bool ignoreShield = context.HasAnyTag(AttackTags.HpRemoval);
// 静默和生命移除均不触发 onStartAttack
if (!isSilent && !isHpRemoval)
{
eventSubmodule.onStartAttack.Invoke(target);
}
//闪避检测:如果闪避成功,直接结束
// 生命移除:直接扣血,跳过所有防御和事件
if (isHpRemoval)
{
target.HealthRemoval(startDamage, context);
target.characterView.hudContainer.enablingHUDs["MainAttributesBar"].UpdateHud();
return new AttackResult(this, target, startDamage, context, false, 0, 0, startDamage);
}
// 闪避检测
int modifiedStartDamageForDodge = Mathf.RoundToInt(startDamage * GetRawAttribute("DodgeCheckStartDamageMultiplier", 1));
bool dodged = !ignoreDodge && target.CheckDodge(modifiedStartDamageForDodge);
@@ -113,25 +129,51 @@ namespace Continentis.MainGame.Character
{
shielded = remainingDamageAfterBlock - remainingDamageAfterShield;
hurt = remainingDamageAfterShield;
target.HealthRemoval(remainingDamageAfterShield);
target.HealthRemoval(remainingDamageAfterShield, context);
}
}
}
target.characterView.hudContainer.enablingHUDs["MainAttributesBar"].UpdateHud();
AttackResult attackResult = new AttackResult(this, target, startDamage, attackCard, dodged, blocked, shielded, hurt);
if (triggerAttackEvent)
AttackResult attackResult = new AttackResult(this, target, startDamage, context, dodged, blocked, shielded, hurt);
if (!isSilent)
{
// 角色 EventSubmodule 级别事件(始终触发,用于日志等)
eventSubmodule.onFinishAttack.Invoke(target, attackResult);
combatBuffSubmodule.buffList.For(buff =>
target.eventSubmodule.onGetAttacked.Invoke(this, attackResult);
// Buff 层事件:响应式攻击不触发,防止无限递归
if (!isReactive)
{
buff.eventSubmodule?.onDealAttack.Invoke(attackResult);
});
combatBuffSubmodule.buffList.For(buff =>
{
buff.eventSubmodule?.onDealAttack.Invoke(attackResult);
});
target.combatBuffSubmodule.buffList.For(buff =>
{
buff.eventSubmodule?.onGetAttacked.Invoke(attackResult);
});
}
}
return attackResult;
}
/// <summary>
/// 攻击目标(兼容旧版 API内部转换为 AttackContext 调用)。
/// 新代码请优先使用 Attack(target, damage, AttackContext) 重载。
/// </summary>
public AttackResult Attack(CharacterBase target, int startDamage, CardInstance attackCard = null, bool triggerAttackEvent = true, bool ignoreDodge = false, bool ignoreBlock = false, bool ignoreShield = false)
{
var context = new AttackContext(attackCard);
if (!triggerAttackEvent) context.WithTag(AttackTags.Silent);
if (ignoreDodge) context.WithTag(AttackTags.GuaranteedHit);
if (ignoreBlock) context.WithTag(AttackTags.Penetrating);
return Attack(target, startDamage, context);
}
/// <summary>
/// 检查闪避(闪避失败后会清空闪避值)
/// </summary>
@@ -145,12 +187,16 @@ namespace Continentis.MainGame.Character
{
bool success = damage <= dodge;
if (!success)
if (success)
{
MainGameManager.Instance.basePrefabs.GenerateInfoText("Dodged!", characterView);
return true;
}
else
{
attributeSubmodule.generalAttributeGroup.current["Dodge"] = 0;
return false;
}
MainGameManager.Instance.basePrefabs.GenerateInfoText("Dodged!", characterView);
return success;
}
return false;
@@ -190,13 +236,13 @@ namespace Continentis.MainGame.Character
}
/// <summary>
/// 检查护盾(并且扣除护盾值)
/// 检查临时生命(并且扣除临时生命值)
/// </summary>
/// <param name="damage">即将受到的伤害</param>
/// <returns>护盾之后的剩余伤害</returns>
/// <returns>临时生命吸收后的剩余伤害</returns>
public int CheckShield(int damage)
{
int shield = attributeSubmodule.GetGeneralAttribute("Shield");
int shield = attributeSubmodule.GetGeneralAttribute("TemporaryHealth");
if (shield > 0)
{
@@ -206,12 +252,12 @@ namespace Continentis.MainGame.Character
if (!success)
{
attributeSubmodule.generalAttributeGroup.current["Shield"] = 0;
attributeSubmodule.generalAttributeGroup.current["TemporaryHealth"] = 0;
remainingDamage = damage - shield;
}
else
{
attributeSubmodule.generalAttributeGroup.current["Shield"] = shield - damage;
attributeSubmodule.generalAttributeGroup.current["TemporaryHealth"] = shield - damage;
blockedDamage = damage;
}
@@ -222,11 +268,68 @@ namespace Continentis.MainGame.Character
return damage;
}
public void HealthRemoval(int damage)
public void HealthRemoval(int damage, AttackContext context = null)
{
int healthBefore = GetAttribute("Health");
ModifyAttribute("Health", -damage);
MainGameManager.Instance.basePrefabs.GenerateHurtText(damage, characterView);
int healthAfter = GetAttribute("Health");
int maxHealth = GetAttribute("MaximumHealth");
Color dmgTextColor = Color.white;
if (context is { damageKeywords: { Count: > 0 } })
{
foreach (string elementTag in MainGameManager.Instance.elementTags)
{
if (context.damageKeywords.Contains(elementTag))
{
switch (elementTag)
{
case "Fire":
dmgTextColor = Color.red;
break;
case "Ice":
dmgTextColor = Color.cyan;
break;
case "Wind":
dmgTextColor = Color.lightGreen;
break;
case "Earth":
dmgTextColor = Color.darkGoldenRod;
break;
case "Storm":
dmgTextColor = Color.magenta;
break;
case "Light":
dmgTextColor = Color.yellowNice;
break;
case "Darkness":
dmgTextColor = Color.rebeccaPurple;
break;
default:
dmgTextColor = Color.white;
break;
}
}
}
}
MainGameManager.Instance.basePrefabs.GenerateHurtText(damage, characterView, dmgTextColor);
// 血量百分比阈值检查:穿越整十档时通知 LogicBase如 Boss 阶段切换)
if (maxHealth > 0 && logicBase != null)
{
float percentBefore = (float)healthBefore / maxHealth;
float percentAfter = (float)healthAfter / maxHealth;
// 找出所有被穿越的整十档(从高到低依次触发)
for (int threshold = 9; threshold >= 0; threshold--)
{
float t = threshold * 0.1f;
if (percentBefore > t && percentAfter <= t)
{
logicBase.OnHealthThreshold(t);
}
}
}
if (GetAttribute("Health") <= 0)
{
Die();
@@ -282,15 +385,15 @@ namespace Continentis.MainGame.Character
}
/// <summary>
/// 添加护盾(护盾不会自动清空)
/// 添加临时生命(不会自动清空)
/// </summary>
public void AddShield(int shield, CharacterBase target = null)
{
int baseShieldAfterOffset = shield + GetAttribute("ShieldGainOffset");
int finalShield = Mathf.RoundToInt(baseShieldAfterOffset * GetRawAttribute("ShieldGainMultiplier", 1));
int baseShieldAfterOffset = shield + GetAttribute("TemporaryHealthGainOffset");
int finalShield = Mathf.RoundToInt(baseShieldAfterOffset * GetRawAttribute("TemporaryHealthGainMultiplier", 1));
target ??= this;
target.ModifyAttribute("Shield", finalShield);
target.ModifyAttribute("TemporaryHealth", finalShield);
target.characterView.hudContainer.UpdateAllHUD();
}
}
@@ -355,8 +458,8 @@ namespace Continentis.MainGame.Character
}
intended.Add(new IntendedCard(card, targets));
remainingStamina -= card.GetAttribute("StaminaCost");
remainingMana -= card.GetAttribute("ManaCost");
remainingStamina -= card.GetAttribute(CardAttributes.StaminaCost);
remainingMana -= card.GetAttribute(CardAttributes.ManaCost);
}
// 行动力不足则跳过该卡
}
@@ -398,8 +501,8 @@ namespace Continentis.MainGame.Character
intended.Add(new IntendedCard(chosen, targets));
normal.Remove(chosen);
remainingStamina -= chosen.GetAttribute("StaminaCost");
remainingMana -= chosen.GetAttribute("ManaCost");
remainingStamina -= chosen.GetAttribute(CardAttributes.StaminaCost);
remainingMana -= chosen.GetAttribute(CardAttributes.ManaCost);
}
}
@@ -408,8 +511,8 @@ namespace Continentis.MainGame.Character
bool CanAfford(CardInstance card, int stamina, int mana)
{
return card.GetAttribute("StaminaCost") <= stamina &&
card.GetAttribute("ManaCost") <= mana;
return card.GetAttribute(CardAttributes.StaminaCost) <= stamina &&
card.GetAttribute(CardAttributes.ManaCost) <= mana;
}
public bool CheckAvailabilityAndSetTargets(CardInstance card, out List<CharacterBase> targets)