修了很多bug和增加功能,优化不少问题
This commit is contained in:
@@ -46,8 +46,19 @@ public class EffectSystem : MonoBehaviour
|
||||
/// Documentation text normalized.
|
||||
/// Documentation text normalized.
|
||||
/// </summary>
|
||||
public void ApplyEffect(Selector selector, EffectType effectType, float amount, float duration = 0f, GameObject source = null, GameObject specificTarget = null, float tickInterval = 1f)
|
||||
public void ApplyEffect(Selector selector, EffectType effectType, float amount, float duration = 0f, GameObject source = null, GameObject specificTarget = null, float tickInterval = 1f, bool skipVFX = false)
|
||||
{
|
||||
// --- Prevent empty ally slots (maxHP == 0) from being a source of any effect ---
|
||||
if (source != null)
|
||||
{
|
||||
var allySource = source.GetComponent<AllyCombatant>();
|
||||
if (allySource != null && allySource.maxHP == 0)
|
||||
{
|
||||
LogVerbose($"[EffectSystem] ApplyEffect: source is empty ally {source.name}, skipping.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If caller provided a specificTarget, prefer it as the single target regardless of selector.
|
||||
// Many callers pass specificTarget when they intend to hit a single unit (ally or enemy).
|
||||
List<GameObject> targets;
|
||||
@@ -66,9 +77,16 @@ public class EffectSystem : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
// For direct buff-like effects (not Buff object path), allow AllyCombatant redirect states
|
||||
// to reroute the receiver before the effect is applied.
|
||||
if (IsDirectRedirectableBuffEffectType(effectType))
|
||||
{
|
||||
targets = RedirectDirectBuffTargets(targets);
|
||||
}
|
||||
|
||||
// --- Projectile Logic ---
|
||||
// Trigger projectile if source exists and is targeting the opposite side
|
||||
if (GfxController.Instance != null && source != null)
|
||||
if (GfxController.Instance != null && source != null && !skipVFX)
|
||||
{
|
||||
foreach (var t in targets)
|
||||
{
|
||||
@@ -82,6 +100,42 @@ public class EffectSystem : MonoBehaviour
|
||||
|
||||
if ((sourceIsAlly && targetIsEnemy) || (sourceIsEnemy && targetIsAlly))
|
||||
{
|
||||
// --- Check if the specific ally slot is active before playing VFX ---
|
||||
if (sourceIsAlly)
|
||||
{
|
||||
var ally = source.GetComponent<AllyCombatant>();
|
||||
if (ally != null && teamUIController.Instance != null)
|
||||
{
|
||||
bool isActive = false;
|
||||
switch (ally.slotIndex)
|
||||
{
|
||||
case 0: isActive = teamUIController.Instance.isAlly01_active; break;
|
||||
case 1: isActive = teamUIController.Instance.isAlly02_active; break;
|
||||
case 2: isActive = teamUIController.Instance.isAlly03_active; break;
|
||||
case 3: isActive = teamUIController.Instance.isAlly04_active; break;
|
||||
case 4: isActive = teamUIController.Instance.isAlly05_active; break;
|
||||
}
|
||||
if (!isActive) continue; // Skip VFX for inactive ally
|
||||
}
|
||||
}
|
||||
else if (targetIsAlly)
|
||||
{
|
||||
var ally = t.GetComponent<AllyCombatant>();
|
||||
if (ally != null && teamUIController.Instance != null)
|
||||
{
|
||||
bool isActive = false;
|
||||
switch (ally.slotIndex)
|
||||
{
|
||||
case 0: isActive = teamUIController.Instance.isAlly01_active; break;
|
||||
case 1: isActive = teamUIController.Instance.isAlly02_active; break;
|
||||
case 2: isActive = teamUIController.Instance.isAlly03_active; break;
|
||||
case 3: isActive = teamUIController.Instance.isAlly04_active; break;
|
||||
case 4: isActive = teamUIController.Instance.isAlly05_active; break;
|
||||
}
|
||||
if (!isActive) continue; // Skip VFX for inactive ally
|
||||
}
|
||||
}
|
||||
|
||||
// Captured target for callback
|
||||
GameObject targetToHit = t;
|
||||
bool isEnemyTarget = targetIsEnemy;
|
||||
@@ -688,6 +742,20 @@ public class EffectSystem : MonoBehaviour
|
||||
}
|
||||
break;
|
||||
|
||||
case EffectType.RewriteNonMissToPerfect:
|
||||
foreach (var t in targets)
|
||||
{
|
||||
if (t == null) continue;
|
||||
var ally = t.GetComponent<AllyCombatant>() ?? t.GetComponentInChildren<AllyCombatant>(true);
|
||||
if (ally == null) continue;
|
||||
if (ally.IsDead) continue;
|
||||
|
||||
// Prefer configured duration; fallback to amount when designers authored duration in formula.
|
||||
float activeDuration = duration > 0f ? duration : amount;
|
||||
ally.ActivateNonMissToPerfectRewrite(activeDuration);
|
||||
}
|
||||
break;
|
||||
|
||||
case EffectType.RedirectSelfDamageToAdjacent:
|
||||
foreach (var t in targets)
|
||||
{
|
||||
@@ -855,13 +923,13 @@ public class EffectSystem : MonoBehaviour
|
||||
foreach (var g in list)
|
||||
if (!uniq.Contains(g)) uniq.Add(g);
|
||||
|
||||
// Filter out dead combatants so they won't receive further effects (damage/score/etc.).
|
||||
// Filter out dead or empty combatants so they won't receive further effects (damage/score/etc.).
|
||||
// This prevents "dead units still get hit / still gain score" edge cases.
|
||||
uniq.RemoveAll(go =>
|
||||
{
|
||||
if (go == null) return true;
|
||||
var ally = go.GetComponent<AllyCombatant>();
|
||||
if (ally != null) return ally.IsDead;
|
||||
if (ally != null) return ally.IsDead || ally.maxHP == 0; // Skip dead or empty allies
|
||||
var enemy = go.GetComponent<EnemyCombatant>();
|
||||
if (enemy != null) return enemy.IsDead || enemy.currentHP <= 0;
|
||||
return false;
|
||||
@@ -983,11 +1051,33 @@ public class EffectSystem : MonoBehaviour
|
||||
var targetEnemy = target.GetComponent<EnemyCombatant>();
|
||||
if (targetEnemy != null && (targetEnemy.IsDead || targetEnemy.currentHP <= 0)) return;
|
||||
|
||||
// If target is an enemy, check if all enemies are already dead
|
||||
if (targetEnemy != null && AreAllEnemiesDead())
|
||||
// If target is an enemy, check if all enemies are already dead or no allies are active
|
||||
if (targetEnemy != null)
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Skip ApplyInstantDamage to {target.name} because all enemies are dead.");
|
||||
return;
|
||||
if (AreAllEnemiesDead())
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Skip ApplyInstantDamage to {target.name} because all enemies are dead.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (teamUIController.Instance != null)
|
||||
{
|
||||
if (!teamUIController.Instance.IsAnyAllyActive())
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Skip ApplyInstantDamage to {target.name} because no allies are active.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (source != null)
|
||||
{
|
||||
var sourceAlly = source.GetComponent<AllyCombatant>();
|
||||
if (sourceAlly != null && !teamUIController.Instance.IsAllySlotActive(sourceAlly.slotIndex))
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Skip ApplyInstantDamage to {target.name} because source ally slot {sourceAlly.slotIndex} is not active.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var comp = target.GetComponent<ICombatant>();
|
||||
@@ -1090,10 +1180,32 @@ public class EffectSystem : MonoBehaviour
|
||||
|
||||
if (duration <= 0f)
|
||||
{
|
||||
if (targetEnemy != null && AreAllEnemiesDead())
|
||||
if (targetEnemy != null)
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Skip DOT (immediate) to {target.name} because all enemies are dead.");
|
||||
yield break;
|
||||
if (AreAllEnemiesDead())
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Skip DOT (immediate) to {target.name} because all enemies are dead.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (teamUIController.Instance != null)
|
||||
{
|
||||
if (!teamUIController.Instance.IsAnyAllyActive())
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Skip DOT (immediate) to {target.name} because no allies are active.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (source != null)
|
||||
{
|
||||
var sourceAlly = source.GetComponent<AllyCombatant>();
|
||||
if (sourceAlly != null && !teamUIController.Instance.IsAllySlotActive(sourceAlly.slotIndex))
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Skip DOT (immediate) to {target.name} because source ally slot {sourceAlly.slotIndex} is not active.");
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
comp.ReceiveDamage(totalAmount, source);
|
||||
@@ -1115,10 +1227,32 @@ public class EffectSystem : MonoBehaviour
|
||||
|
||||
if (targetAlly != null && targetAlly.IsDead) yield break;
|
||||
if (targetEnemy != null && (targetEnemy.IsDead || targetEnemy.currentHP <= 0)) yield break;
|
||||
if (targetEnemy != null && AreAllEnemiesDead())
|
||||
if (targetEnemy != null)
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Stopping DOT to {target.name} because all enemies are dead.");
|
||||
yield break;
|
||||
if (AreAllEnemiesDead())
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Stopping DOT to {target.name} because all enemies are dead.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (teamUIController.Instance != null)
|
||||
{
|
||||
if (!teamUIController.Instance.IsAnyAllyActive())
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Stopping DOT to {target.name} because no allies are active.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (source != null)
|
||||
{
|
||||
var sourceAlly = source.GetComponent<AllyCombatant>();
|
||||
if (sourceAlly != null && !teamUIController.Instance.IsAllySlotActive(sourceAlly.slotIndex))
|
||||
{
|
||||
LogVerbose($"[EffectSystem] Stopping DOT to {target.name} because source ally slot {sourceAlly.slotIndex} is not active.");
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int beforeHP = 0;
|
||||
@@ -1554,6 +1688,55 @@ public class EffectSystem : MonoBehaviour
|
||||
iBudeffPrefabController.Instance?.UnregisterEnemyTimedEffect(enemyInstanceId, iconId);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsDirectRedirectableBuffEffectType(EffectType effectType)
|
||||
{
|
||||
switch (effectType)
|
||||
{
|
||||
case EffectType.IncreaseMaxHP:
|
||||
case EffectType.DecreaseMaxHP:
|
||||
case EffectType.IncreaseMaxMana:
|
||||
case EffectType.DecreaseMaxMana:
|
||||
case EffectType.IncreaseScoreEfficiency:
|
||||
case EffectType.DecreaseScoreEfficiency:
|
||||
case EffectType.IncreaseDamageResistance:
|
||||
case EffectType.DecreaseDamageResistance:
|
||||
case EffectType.IncreaseAttack:
|
||||
case EffectType.DecreaseAttack:
|
||||
case EffectType.RewriteNonMissToPerfect:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<GameObject> RedirectDirectBuffTargets(List<GameObject> targets)
|
||||
{
|
||||
if (targets == null || targets.Count == 0) return targets;
|
||||
var redirectedTargets = new List<GameObject>(targets.Count);
|
||||
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
var t = targets[i];
|
||||
if (t == null)
|
||||
{
|
||||
redirectedTargets.Add(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
var ally = t.GetComponent<AllyCombatant>() ?? t.GetComponentInChildren<AllyCombatant>(true);
|
||||
if (ally != null && ally.TryRedirectIncomingGenericBuff(out var redirected) && redirected != null)
|
||||
{
|
||||
redirectedTargets.Add(redirected.gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
redirectedTargets.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
return redirectedTargets;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user