修了很多bug和增加功能,优化不少问题

This commit is contained in:
FloatGaming
2026-02-28 06:59:22 +08:00
parent 508a40bba0
commit e11cc1da7a
345 changed files with 173803 additions and 69332 deletions
+197 -14
View File
@@ -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
}