技能主要更新,修复卡顿并加入动画,以及各种其他更新。

This commit is contained in:
2026-02-07 21:05:17 +08:00
parent abeca51be5
commit 1ac3cd0104
1349 changed files with 1526749 additions and 24850 deletions
+335 -67
View File
@@ -11,7 +11,7 @@ using TMPro;
/// ʵ ICombatant ӿԹ EffectSystem á
/// - teamUIController ȡ UI òͬʾѪ/
/// - ʱ TeamCharacterDataInfo AllyHero_SO /Ȼ
/// - ʼֵΪֵʼΪ 0
/// - ʼֵΪֵʼ?0
/// </summary>
public class AllyCombatant : MonoBehaviour, ICombatant
{
@@ -28,8 +28,12 @@ public class AllyCombatant : MonoBehaviour, ICombatant
private bool isDead = false; // new: dead flag
public BeatmapManager bmm;
// --- Damage redirect (next hit) ---
private static AllyCombatant s_nextDamageRedirector;
private static float s_redirectExpireTime = -1f;
// add attack stat to be available at runtime
[Tooltip("ʱʹã AllyHero_SO.levelStats[0].attack ڣ")]
[Tooltip("ʱʹã?AllyHero_SO.levelStats[0].attack ڣ")]
public int attack = 0;
// scoring fields
@@ -47,10 +51,10 @@ public class AllyCombatant : MonoBehaviour, ICombatant
[Tooltip("Score multiplier for Miss (e.g. 0)")]
public float missRatio = 0f;
[Tooltip("ɫǰ÷֣ۼӣʾ UI currentScore ı")]
[Tooltip("ɫǰ÷֣ۼӣʾ?UI currentScore ı")]
public int currentScore = 0;
[Tooltip("ޣΪ int.MaxValue - 1")]
[Tooltip("ޣ?int.MaxValue - 1")]
public int maxTrackScore = int.MaxValue - 1;
// When true, InitializeStatsFromData() will overwrite inspector values on Start.
@@ -78,6 +82,14 @@ public class AllyCombatant : MonoBehaviour, ICombatant
// Track applied reversible effects for HP-percent skills so we can revert them on leave
private Dictionary<string, AppliedEffect> _appliedHpPercentEffects = new Dictionary<string, AppliedEffect>();
// Track skills that are currently active because Attack == 0
private HashSet<string> _activeAttackZeroSkills = new HashSet<string>();
private Dictionary<string, AppliedEffect> _appliedAttackZeroEffects = new Dictionary<string, AppliedEffect>();
// Reusable buffers to reduce allocations during skill evaluation
private readonly List<SkillDefinition> _tmpSkillDefs = new List<SkillDefinition>(16);
private readonly Dictionary<string, float> _formulaVarsBuffer = new Dictionary<string, float>(16);
private class AppliedEffect
{
public EffectType effectType;
@@ -91,6 +103,13 @@ public class AllyCombatant : MonoBehaviour, ICombatant
gameObject.name = $"ally_0{Mathf.Clamp(slotIndex + 1, 1, 5)}";
if (_activeHpPercentSkills == null) _activeHpPercentSkills = new HashSet<string>();
if (_appliedHpPercentEffects == null) _appliedHpPercentEffects = new Dictionary<string, AppliedEffect>();
if (_activeAttackZeroSkills == null) _activeAttackZeroSkills = new HashSet<string>();
if (_appliedAttackZeroEffects == null) _appliedAttackZeroEffects = new Dictionary<string, AppliedEffect>();
}
private void LogVerbose(string message)
{
if (GameConfig.verboseLogs) Debug.Log(message);
}
private void Start()
@@ -166,6 +185,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
if (Application.isPlaying && SkillBuilder.Instance != null)
{
EvaluateHPPercentageTriggers(currentHP);
EvaluateAttackZeroTriggers();
TryCastOnFullMana();
}
}
@@ -173,7 +193,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
private void ResolveUIReferences()
{
// Try singleton first, fallback to scene search (works in editor)
var ui = teamUIController.Instance ?? FindObjectOfType<teamUIController>();
var ui = teamUIController.Instance != null ? teamUIController.Instance : UnityEngine.Object.FindAnyObjectByType<teamUIController>();
if (ui == null) return;
switch (slotIndex)
{
@@ -261,7 +281,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
case 3: ui.teammate04_current_scoreText = tmp; break;
case 4: ui.teammate05_current_scoreText = tmp; break;
}
Debug.Log($"[AllyCombatant] Resolved currentScoreText for slot {slotIndex+1} from parent {parent.name} -> {tmp.gameObject.name}");
LogVerbose($"[AllyCombatant] Resolved currentScoreText for slot {slotIndex+1} from parent {parent.name} -> {tmp.gameObject.name}");
}
else
{
@@ -325,8 +345,8 @@ public class AllyCombatant : MonoBehaviour, ICombatant
{
if (a != null && a.ally_heroID == id)
{
// ؼ޸ͬһ AllyHero_SO λʹʱֱ a.ally_currentEXP
// ԴҴ浵/PlayerPrefs ȡλľֵ
// ؼ޸ͬһ AllyHero_SO λʹʱֱ?a.ally_currentEXP
// ԴҴ?PlayerPrefs ȡλľֵ
// Լselected_heroSlot0{slotIndex+1}_exp selected_heroSlot01_exp
int expKeySlot = Mathf.Clamp(slotIndex + 1, 1, 5);
string expKey = $"selected_heroSlot0{expKeySlot}_exp";
@@ -344,7 +364,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
maxMana = eff.maxMana;
damageResistance = eff.damageResistance;
scoreEfficiency = eff.scoreEfficiency;
attack = eff.attack;
SetAttack(eff.attack);
}
else
{
@@ -353,7 +373,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
maxMana = lvl.maxMana;
damageResistance = lvl.damageResistance;
scoreEfficiency = lvl.scoreEfficiency;
attack = lvl.attack;
SetAttack(lvl.attack);
}
}
@@ -365,7 +385,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
}
}
// ݴ EXP ȼ޸ SO ϵ ally_currentEXPλ״̬
// ݴ EXP ȼ޸?SO ϵ ally_currentEXPλ״̬
private static AllyHero_SO.AllyLevelInfo GetEffectiveLevelForExp(AllyHero_SO so, int exp)
{
if (so == null || so.levelStats == null || so.levelStats.Count == 0) return null;
@@ -417,6 +437,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
UpdateScoreUI();
// update global total
ScoreManager.Instance?.RecalculateTotal();
EvaluateAttackZeroTriggers();
return actuallyAdded;
}
@@ -434,7 +455,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
if (currentScoreText != null)
{
currentScoreText.text = value;
Debug.Log($"[AllyCombatant] Updated slot {slotIndex+1} score UI -> {value} (target {currentScoreText.gameObject.name})");
LogVerbose($"[AllyCombatant] Updated slot {slotIndex+1} score UI -> {value} (target {currentScoreText.gameObject.name})");
return;
}
@@ -445,24 +466,33 @@ public class AllyCombatant : MonoBehaviour, ICombatant
switch (slotIndex)
{
case 0:
if (ui.teammate01_current_scoreText != null) { ui.teammate01_current_scoreText.text = value; Debug.Log($"[AllyCombatant] Fallback wrote to ui.teammate01_current_scoreText: {value}"); }
if (ui.teammate01_current_scoreText != null) { ui.teammate01_current_scoreText.text = value; LogVerbose($"[AllyCombatant] Fallback wrote to ui.teammate01_current_scoreText: {value}"); }
break;
case 1:
if (ui.teammate02_current_scoreText != null) { ui.teammate02_current_scoreText.text = value; Debug.Log($"[AllyCombatant] Fallback wrote to ui.teammate02_current_scoreText: {value}"); }
if (ui.teammate02_current_scoreText != null) { ui.teammate02_current_scoreText.text = value; LogVerbose($"[AllyCombatant] Fallback wrote to ui.teammate02_current_scoreText: {value}"); }
break;
case 2:
if (ui.teammate03_current_scoreText != null) { ui.teammate03_current_scoreText.text = value; Debug.Log($"[AllyCombatant] Fallback wrote to ui.teammate03_current_scoreText: {value}"); }
if (ui.teammate03_current_scoreText != null) { ui.teammate03_current_scoreText.text = value; LogVerbose($"[AllyCombatant] Fallback wrote to ui.teammate03_current_scoreText: {value}"); }
break;
case 3:
if (ui.teammate04_current_scoreText != null) { ui.teammate04_current_scoreText.text = value; Debug.Log($"[AllyCombatant] Fallback wrote to ui.teammate04_current_scoreText: {value}"); }
if (ui.teammate04_current_scoreText != null) { ui.teammate04_current_scoreText.text = value; LogVerbose($"[AllyCombatant] Fallback wrote to ui.teammate04_current_scoreText: {value}"); }
break;
case 4:
if (ui.teammate05_current_scoreText != null) { ui.teammate05_current_scoreText.text = value; Debug.Log($"[AllyCombatant] Fallback wrote to ui.teammate05_current_scoreText: {value}"); }
if (ui.teammate05_current_scoreText != null) { ui.teammate05_current_scoreText.text = value; LogVerbose($"[AllyCombatant] Fallback wrote to ui.teammate05_current_scoreText: {value}"); }
break;
}
}
}
// Set max score cap for this track and refresh UI
public void SetMaxTrackScore(int newMax, bool clampCurrent = true)
{
maxTrackScore = Mathf.Max(0, newMax);
if (clampCurrent)
currentScore = Mathf.Clamp(currentScore, 0, maxTrackScore);
UpdateScoreUI();
}
// Public setters that update UI and optionally animate fade bars
public void SetCurrentHP(int hp, bool animateFade = true)
{
@@ -562,6 +592,22 @@ public class AllyCombatant : MonoBehaviour, ICombatant
// EvaluateHPPercentageTriggers(currentHP); // Not needed for mana but keep in mind
}
public void ModifyAttack(int delta)
{
int old = attack;
attack = Mathf.Max(0, attack + delta);
if (old != attack)
EvaluateAttackZeroTriggers();
}
public void SetAttack(int value)
{
int old = attack;
attack = Mathf.Max(0, value);
if (old != attack)
EvaluateAttackZeroTriggers();
}
private void UpdateHealthVisuals(int oldHP, bool animateFade)
{
// main bar should snap quickly to new value, while fade bar lerps towards it
@@ -611,7 +657,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
var ui = teamUIController.Instance;
if (ui != null)
{
// 移除原有的红闪常亮逻辑,改为调用黑白渐变效
// 移除原有的红闪常亮逻辑,改为调用黑白渐变效?
StartCoroutine(ui.AllyDeathGrayscale(characterImage));
}
}
@@ -704,6 +750,23 @@ public class AllyCombatant : MonoBehaviour, ICombatant
public void ReceiveDamage(float amount, GameObject source)
{
ReceiveDamageInternal(amount, source, true);
}
private void ReceiveDamageInternal(float amount, GameObject source, bool allowRedirect)
{
if (allowRedirect && IsRedirectActive())
{
var redirector = s_nextDamageRedirector;
ClearRedirect();
if (redirector != null && redirector != this)
{
redirector.ReceiveDamageInternal(amount, source, false);
return;
}
// If redirector is self or invalid, consume redirect and continue to take damage normally.
}
float effective = amount * (1f - damageResistance);
int delta = Mathf.CeilToInt(effective);
ModifyHP(-delta, true);
@@ -720,7 +783,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
if (buff == null) return;
activeBuffs.Add(buff);
// simple immediate apply: multiply stats
if (buff.attackMultiplier != 1f) { attack = Mathf.RoundToInt(attack * buff.attackMultiplier); }
if (buff.attackMultiplier != 1f) { SetAttack(Mathf.RoundToInt(attack * buff.attackMultiplier)); }
if (buff.scoreMultiplier != 1f) scoreEfficiency *= buff.scoreMultiplier;
// UI/visual could be added
}
@@ -847,7 +910,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
if (skill == null) continue;
if (skill.triggerCondition != SkillDefinition.SkillTrigger.OnManaFull) continue;
SkillBuilder.Instance.UseSkillDefinition(skill, slotIndex, -1f, null);
Debug.Log($"[AllyCombatant] Slot {slotIndex + 1} cast skill from group: {skill.skillId} (OnManaFull)");
LogVerbose($"[AllyCombatant] Slot {slotIndex + 1} cast skill from group: {skill.skillId} (OnManaFull)");
anyTriggered = true;
}
}
@@ -864,7 +927,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
if (skill == null) continue;
if (skill.triggerCondition != SkillDefinition.SkillTrigger.OnManaFull) continue;
SkillBuilder.Instance.UseSkillDefinition(skill, slotIndex, -1f, null);
Debug.Log($"[AllyCombatant] Slot {slotIndex + 1} cast skill from primary group: {skill.skillId} (OnManaFull)");
LogVerbose($"[AllyCombatant] Slot {slotIndex + 1} cast skill from primary group: {skill.skillId} (OnManaFull)");
anyTriggered = true;
}
}
@@ -878,7 +941,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
if (def != null && def.triggerCondition == SkillDefinition.SkillTrigger.OnManaFull)
{
SkillBuilder.Instance.UseSkillDefinition(def, slotIndex, -1f, null);
Debug.Log($"[AllyCombatant] Slot {slotIndex + 1} cast primary skill '{def.skillId}' due to ManaFull.");
LogVerbose($"[AllyCombatant] Slot {slotIndex + 1} cast primary skill '{def.skillId}' due to ManaFull.");
anyTriggered = true;
}
else if (so.availableSkills != null)
@@ -888,7 +951,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
if (skill == null) continue;
if (skill.triggerCondition != SkillDefinition.SkillTrigger.OnManaFull) continue;
SkillBuilder.Instance.UseSkillDefinition(skill, slotIndex, -1f, null);
Debug.Log($"[AllyCombatant] Slot {slotIndex + 1} cast available skill: {skill.skillId} (OnManaFull)");
LogVerbose($"[AllyCombatant] Slot {slotIndex + 1} cast available skill: {skill.skillId} (OnManaFull)");
anyTriggered = true;
}
}
@@ -896,7 +959,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
if (!anyTriggered)
{
Debug.Log($"[AllyCombatant] Slot {slotIndex + 1}: no skills configured for OnManaFull.");
LogVerbose($"[AllyCombatant] Slot {slotIndex + 1}: no skills configured for OnManaFull.");
}
}
@@ -911,11 +974,11 @@ public class AllyCombatant : MonoBehaviour, ICombatant
// Only cast skills whose triggerCondition matches OnManaFull when this method is invoked from auto-cast path
if (skill.triggerCondition != SkillDefinition.SkillTrigger.OnManaFull)
{
Debug.Log($"[AllyCombatant] Slot {slotIndex + 1} skill '{skill.skillId}' skipped: triggerCondition={skill.triggerCondition}.");
LogVerbose($"[AllyCombatant] Slot {slotIndex + 1} skill '{skill.skillId}' skipped: triggerCondition={skill.triggerCondition}.");
continue;
}
SkillBuilder.Instance.UseSkillDefinition(skill, slotIndex, -1f, null);
Debug.Log($"[AllyCombatant] Slot {slotIndex + 1} cast skill from group: {skill.skillId}");
LogVerbose($"[AllyCombatant] Slot {slotIndex + 1} cast skill from group: {skill.skillId}");
}
}
@@ -933,7 +996,46 @@ public class AllyCombatant : MonoBehaviour, ICombatant
SetCurrentMana(maxMana, true);
}
// New: Evaluate HP-percent triggers and handle enter/leave transitions
private Dictionary<string, float> BuildFormulaVars(AllyHero_SO so)
{
var vars = _formulaVarsBuffer;
vars.Clear();
vars["slot"] = slotIndex;
vars["attack"] = attack;
if (so != null && so.levelStats != null && so.levelStats.Count > 0)
{
var eff = so.GetEffectiveLevelForCurrentEXP();
var lvl = eff ?? so.levelStats[0];
vars["maxHP"] = lvl.maxHP;
vars["maxMana"] = lvl.maxMana;
vars["damageResistance"] = lvl.damageResistance;
vars["scoreEfficiency"] = lvl.scoreEfficiency;
vars["attack"] = lvl.attack;
vars["level"] = lvl.levelID;
vars["levelID"] = lvl.levelID;
vars["currentLevel"] = lvl.levelID;
}
else
{
vars["maxHP"] = maxHP;
vars["maxMana"] = maxMana;
vars["damageResistance"] = damageResistance;
vars["scoreEfficiency"] = scoreEfficiency;
vars["level"] = 0f;
vars["levelID"] = 0f;
vars["currentLevel"] = 0f;
}
vars["ally_currentEXP"] = so != null ? so.ally_currentEXP : 0f;
vars["currentMana"] = currentMana;
vars["currentScore"] = currentScore;
vars["idolScore"] = currentScore;
vars["currentHP"] = currentHP;
return vars;
}
// New: Evaluate HP-percent triggers and handle enter/leave transitions
private void EvaluateHPPercentageTriggers(int oldHP)
{
if (!Application.isPlaying) return;
@@ -945,6 +1047,77 @@ public class AllyCombatant : MonoBehaviour, ICombatant
float oldPct = (maxHP > 0) ? (float)oldHP / (float)maxHP : 0f;
float currPct = (maxHP > 0) ? (float)currentHP / (float)maxHP : 0f;
// Collect candidate skills (same priority order as other triggers)
var defs = _tmpSkillDefs;
defs.Clear();
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
{
foreach (var gid in so.equippedSkillGroupIDs)
{
if (gid == 0) continue;
SkillGroup group = null;
for (int k = 0; k < so.skillGroups.Length; k++)
{
var g = so.skillGroups[k];
if (g != null && g.skillGroupID == gid) { group = g; break; }
}
if (group == null || group.skills == null) continue;
for (int i = 0; i < group.skills.Length; i++)
{
var def = group.skills[i];
if (def != null) defs.Add(def);
}
}
}
else
{
var fallbackGroup = so.GetPrimarySkillGroup();
if (fallbackGroup != null && fallbackGroup.skills != null)
{
for (int i = 0; i < fallbackGroup.skills.Length; i++)
{
var def = fallbackGroup.skills[i];
if (def != null) defs.Add(def);
}
}
else if (so.availableSkills != null)
{
for (int i = 0; i < so.availableSkills.Length; i++)
{
var def = so.availableSkills[i];
if (def != null) defs.Add(def);
}
}
}
// Select a single "best" Above/Below skill to avoid stacking when multiple thresholds are satisfied.
string selectedAbove = null;
float selectedAboveThreshold = float.MinValue;
string selectedBelow = null;
float selectedBelowThreshold = float.MaxValue;
for (int i = 0; i < defs.Count; i++)
{
var def = defs[i];
if (def == null) continue;
if (def.triggerCondition == SkillDefinition.SkillTrigger.OnHPAbovePercent)
{
if (currPct >= def.hpTriggerPercent && def.hpTriggerPercent >= selectedAboveThreshold)
{
selectedAboveThreshold = def.hpTriggerPercent;
selectedAbove = def.skillId;
}
}
else if (def.triggerCondition == SkillDefinition.SkillTrigger.OnHPBelowPercent)
{
if (currPct <= def.hpTriggerPercent && def.hpTriggerPercent <= selectedBelowThreshold)
{
selectedBelowThreshold = def.hpTriggerPercent;
selectedBelow = def.skillId;
}
}
}
var vars = BuildFormulaVars(so);
Action<SkillDefinition> processDef = (def) =>
{
if (def == null) return;
@@ -954,33 +1127,12 @@ public class AllyCombatant : MonoBehaviour, ICombatant
bool wasActive = _activeHpPercentSkills.Contains(def.skillId);
bool nowActive = false;
if (def.triggerCondition == SkillDefinition.SkillTrigger.OnHPAbovePercent)
nowActive = currPct >= def.hpTriggerPercent;
nowActive = (selectedAbove != null && def.skillId == selectedAbove) && currPct >= def.hpTriggerPercent;
else if (def.triggerCondition == SkillDefinition.SkillTrigger.OnHPBelowPercent)
nowActive = currPct <= def.hpTriggerPercent;
nowActive = (selectedBelow != null && def.skillId == selectedBelow) && currPct <= def.hpTriggerPercent;
// Evaluate formula into amount using similar variables as SkillBuilder
float amount = 0f;
var vars = new Dictionary<string, float>();
vars["slot"] = slotIndex;
vars["attack"] = attack;
if (so != null && so.levelStats != null && so.levelStats.Count > 0)
{
var eff = so.GetEffectiveLevelForCurrentEXP();
var lvl = eff ?? so.levelStats[0];
vars["maxHP"] = lvl.maxHP;
vars["maxMana"] = lvl.maxMana;
vars["damageResistance"] = lvl.damageResistance;
vars["scoreEfficiency"] = lvl.scoreEfficiency;
vars["attack"] = lvl.attack;
}
else
{
vars["maxHP"] = maxHP;
vars["maxMana"] = maxMana;
vars["damageResistance"] = damageResistance;
vars["scoreEfficiency"] = scoreEfficiency;
}
vars["ally_currentEXP"] = so != null ? so.ally_currentEXP : 0f;
if (!string.IsNullOrWhiteSpace(def.formula))
{
@@ -1028,7 +1180,22 @@ public class AllyCombatant : MonoBehaviour, ICombatant
}
};
// iterate equipped groups -> primary group -> availableSkills (same as other triggers)
for (int i = 0; i < defs.Count; i++)
processDef(defs[i]);
}
private void EvaluateAttackZeroTriggers()
{
if (!Application.isPlaying) return;
if (SkillBuilder.Instance == null) return;
var so = SkillBuilder.Instance.GetAllyHeroSOBySlot(slotIndex);
if (so == null) return;
bool nowActive = attack <= 0;
var defs = _tmpSkillDefs;
defs.Clear();
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
{
foreach (var gid in so.equippedSkillGroupIDs)
@@ -1040,32 +1207,119 @@ public class AllyCombatant : MonoBehaviour, ICombatant
var g = so.skillGroups[k];
if (g != null && g.skillGroupID == gid) { group = g; break; }
}
if (group == null) continue;
foreach (var def in group.skills)
if (group == null || group.skills == null) continue;
for (int i = 0; i < group.skills.Length; i++)
{
processDef(def);
var def = group.skills[i];
if (def != null) defs.Add(def);
}
}
return;
}
var fallbackGroup = so.GetPrimarySkillGroup();
if (fallbackGroup != null)
else
{
foreach (var def in fallbackGroup.skills)
var fallbackGroup = so.GetPrimarySkillGroup();
if (fallbackGroup != null && fallbackGroup.skills != null)
{
processDef(def);
for (int i = 0; i < fallbackGroup.skills.Length; i++)
{
var def = fallbackGroup.skills[i];
if (def != null) defs.Add(def);
}
}
return;
}
if (so.availableSkills != null)
{
foreach (var def in so.availableSkills)
else if (so.availableSkills != null)
{
processDef(def);
for (int i = 0; i < so.availableSkills.Length; i++)
{
var def = so.availableSkills[i];
if (def != null) defs.Add(def);
}
}
}
var vars = BuildFormulaVars(so);
for (int i = 0; i < defs.Count; i++)
{
var def = defs[i];
if (def == null) continue;
if (def.triggerCondition != SkillDefinition.SkillTrigger.OnAttackZero) continue;
bool wasActive = _activeAttackZeroSkills.Contains(def.skillId);
// Evaluate formula into amount using similar variables as SkillBuilder
float amount = 0f;
if (!string.IsNullOrWhiteSpace(def.formula))
{
if (!SkillDefinition.TryEvaluateFormula(def.formula, vars, out float fresult))
amount = 0f;
else
amount = fresult;
}
bool isReversible = IsEffectReversible(def.effectType);
if (!isReversible)
{
if (!wasActive && nowActive)
{
_activeAttackZeroSkills.Add(def.skillId);
EffectSystem.Instance.ApplyEffect(def.defaultSelector, def.effectType, amount, 0f, this.gameObject, null);
}
else if (wasActive && !nowActive)
{
_activeAttackZeroSkills.Remove(def.skillId);
}
continue;
}
if (!wasActive && nowActive)
{
_activeAttackZeroSkills.Add(def.skillId);
EffectSystem.Instance.ApplyEffect(def.defaultSelector, def.effectType, amount, 0f, this.gameObject, null);
_appliedAttackZeroEffects[def.skillId] = new AppliedEffect(def.effectType, amount);
}
else if (wasActive && !nowActive)
{
_activeAttackZeroSkills.Remove(def.skillId);
if (_appliedAttackZeroEffects.TryGetValue(def.skillId, out var applied))
{
ApplyInverseEffect(def.defaultSelector, applied.effectType, applied.amount);
_appliedAttackZeroEffects.Remove(def.skillId);
}
}
}
}
public static void ActivateNextDamageRedirect(AllyCombatant redirector, float duration = 0f)
{
if (redirector == null) return;
s_nextDamageRedirector = redirector;
if (duration > 0f && Application.isPlaying)
s_redirectExpireTime = Time.time + duration;
else
s_redirectExpireTime = -1f;
}
private static bool IsRedirectActive()
{
if (s_nextDamageRedirector == null) return false;
if (Application.isPlaying && s_redirectExpireTime > 0f && Time.time > s_redirectExpireTime)
{
ClearRedirect();
return false;
}
if (s_nextDamageRedirector != null && s_nextDamageRedirector.isDead)
{
ClearRedirect();
return false;
}
return true;
}
private static void ClearRedirect()
{
s_nextDamageRedirector = null;
s_redirectExpireTime = -1f;
}
private bool IsEffectReversible(EffectType type)
@@ -1140,3 +1394,17 @@ public class AllyCombatant : MonoBehaviour, ICombatant
}
}
}