备份,准备做双端
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user