备份,准备做双端

This commit is contained in:
2026-07-30 23:15:58 +08:00
parent add675e45d
commit ec4ec53545
88 changed files with 4050 additions and 872 deletions
+46 -6
View File
@@ -19,10 +19,14 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
public float damageResistance = 0f;
public int attack = 0;
// Keep an unbuffed attack baseline so temporary Buff.attackMultiplier can be applied/reverted correctly.
// True (permanent) attack baseline. Timed buffs live in _attackModifiers instead of baking here,
// so percentages stay computed off the unbuffed base and re-triggers refresh rather than compound.
private int _attackBaseUnbuffed = 0;
private bool _attackBaseInitialized = false;
// Additive attack modifiers keyed by source (skillId); one entry per source, replaced on re-apply.
private readonly Dictionary<string, int> _attackModifiers = new Dictionary<string, int>();
private List<Buff> activeBuffs = new List<Buff>();
// Events to notify manager/UI
@@ -43,6 +47,7 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
// This enemy GameObject can be reused for multiple enemy entries in sequence.
// Clear any runtime buffs so they don't leak across enemy transitions.
activeBuffs.Clear();
_attackModifiers.Clear();
_attackBaseInitialized = false;
_attackBaseUnbuffed = 0;
_lastAttacker = null;
@@ -94,6 +99,12 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
TryTriggerConfiguredSkills(SkillDefinition.SkillTrigger.OnEnemyRevive);
}
// Reused only for the formula vars (safe: used synchronously in the leaf before any
// nested ExecuteSkill call). The `executed` set is intentionally NOT pooled: an enemy
// skill can restore the enemy's own mana and re-enter TryTriggerConfiguredSkills(OnManaFull)
// mid-loop, so a shared set could be cleared under the outer iteration.
private readonly Dictionary<string, float> _enemyFormulaVarsBuffer = new Dictionary<string, float>();
private void TryTriggerConfiguredSkills(SkillDefinition.SkillTrigger when)
{
if (sourceData == null) return;
@@ -131,11 +142,15 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
executed.Add(def);
float perTick = 0f;
var vars = new Dictionary<string, float>();
var vars = _enemyFormulaVarsBuffer;
vars.Clear();
vars["maxHP"] = maxHP;
vars["maxMana"] = maxMana;
vars["damageResistance"] = damageResistance;
vars["attack"] = attack;
// Attack-buff effects compute their percentage off the unbuffed base so repeated triggers
// add by source instead of compounding; output effects keep using current attack.
bool attackPercentOffBase = def.effectType == EffectType.IncreaseAttack || def.effectType == EffectType.DecreaseAttack;
vars["attack"] = attackPercentOffBase ? GetBaseAttack() : attack;
vars["enemy_currentHP"] = currentHP;
if (!string.IsNullOrWhiteSpace(def.formula))
@@ -269,7 +284,8 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
public void ApplyBuff(Buff buff, GameObject source)
{
if (buff == null) return;
Debug.LogWarning($"[EnemyCombatant] ApplyBuff: {buff.description} (id={buff.buffId}) to {name}. AtkMult={buff.attackMultiplier}, HealMult={buff.healReceivedMultiplier}, ScoreMult={buff.scoreMultiplier}");
if (GameConfig.verboseLogs)
Debug.LogWarning($"[EnemyCombatant] ApplyBuff: {buff.description} (id={buff.buffId}) to {name}. AtkMult={buff.attackMultiplier}, HealMult={buff.healReceivedMultiplier}, ScoreMult={buff.scoreMultiplier}");
activeBuffs.Add(buff);
// Apply reversible multipliers. attackMultiplier is applied via baseline+recalc to ensure it can be reverted.
if (buff.attackMultiplier != 1f) RecalculateAttackFromBuffs();
@@ -334,7 +350,30 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
{
EnsureAttackBaseInitialized();
float mult = GetTotalAttackMultiplier();
attack = Mathf.Max(0, Mathf.RoundToInt(_attackBaseUnbuffed * mult));
int modifierSum = 0;
foreach (var kv in _attackModifiers) modifierSum += kv.Value;
attack = Mathf.Max(0, Mathf.RoundToInt(_attackBaseUnbuffed * mult) + modifierSum);
}
public int GetBaseAttack()
{
EnsureAttackBaseInitialized();
return _attackBaseUnbuffed;
}
public void SetAttackModifier(string sourceKey, int delta)
{
if (string.IsNullOrEmpty(sourceKey)) { ModifyAttack(delta); return; }
EnsureAttackBaseInitialized();
if (delta == 0) _attackModifiers.Remove(sourceKey);
else _attackModifiers[sourceKey] = delta;
RecalculateAttackFromBuffs();
}
public void ClearAttackModifier(string sourceKey)
{
if (string.IsNullOrEmpty(sourceKey)) return;
if (_attackModifiers.Remove(sourceKey)) RecalculateAttackFromBuffs();
}
public void ModifyAttack(int delta)
@@ -414,7 +453,8 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
// If mana reached full, trigger configured skills and reset mana
if (currentMana >= maxMana && maxMana > 0 && Application.isPlaying)
{
Debug.Log($"[EnemyCombatant] Mana full for {gameObject.name} (slot) - triggering OnManaFull");
if (GameConfig.verboseLogs)
Debug.Log($"[EnemyCombatant] Mana full for {gameObject.name} (slot) - triggering OnManaFull");
try
{
TryTriggerConfiguredSkills(SkillDefinition.SkillTrigger.OnManaFull);