feat: 젬 테스트 경로 및 보스 기절 디버그 추가
- 다중 젬 슬롯용 타입을 별도 스크립트로 분리하고 테스트 젬/로드아웃 자산 생성 경로를 정리 - 젬 테스트 전용 공격 스킬과 분리된 애니메이션 자산을 추가해 베이스 스킬 검증 경로를 마련 - PlayerSkillDebugMenu와 MPP 디버그 메뉴를 보강해 젬 프리셋 적용, 원격 테스트, 보스 기절 디버그 메뉴를 추가 - BossCombatBehaviorContext와 공통 BT 액션이 기절 상태를 존중하도록 수정해 보스 추적과 패턴 실행을 중단 - Unity 리프레시와 외부 빌드 통과를 확인하고 드로그전 및 MPP 기준 젬 프리셋 적용 흐름을 검증
This commit is contained in:
69
Assets/_Game/Scripts/Skills/PlayerLoadoutPreset.cs
Normal file
69
Assets/_Game/Scripts/Skills/PlayerLoadoutPreset.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Colosseum.Skills
|
||||
{
|
||||
/// <summary>
|
||||
/// 플레이어가 슬롯별로 사용할 스킬/젬 조합 프리셋입니다.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "NewPlayerLoadoutPreset", menuName = "Colosseum/Player Loadout Preset")]
|
||||
public class PlayerLoadoutPreset : ScriptableObject
|
||||
{
|
||||
private const int DefaultSlotCount = 7;
|
||||
|
||||
[Header("기본 정보")]
|
||||
[SerializeField] private string presetName;
|
||||
[TextArea(2, 4)]
|
||||
[SerializeField] private string description;
|
||||
|
||||
[Header("슬롯 구성")]
|
||||
[SerializeField] private SkillLoadoutEntry[] slots = new SkillLoadoutEntry[DefaultSlotCount];
|
||||
|
||||
public string PresetName => presetName;
|
||||
public string Description => description;
|
||||
public IReadOnlyList<SkillLoadoutEntry> Slots => slots;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
EnsureSlotCapacity();
|
||||
}
|
||||
|
||||
public void EnsureSlotCapacity(int slotCount = DefaultSlotCount)
|
||||
{
|
||||
slotCount = Mathf.Max(0, slotCount);
|
||||
if (slots != null && slots.Length == slotCount)
|
||||
{
|
||||
EnsureGemSlots();
|
||||
return;
|
||||
}
|
||||
|
||||
SkillLoadoutEntry[] resized = new SkillLoadoutEntry[slotCount];
|
||||
if (slots != null)
|
||||
{
|
||||
int copyCount = Mathf.Min(slots.Length, resized.Length);
|
||||
for (int i = 0; i < copyCount; i++)
|
||||
{
|
||||
resized[i] = slots[i];
|
||||
}
|
||||
}
|
||||
|
||||
slots = resized;
|
||||
EnsureGemSlots();
|
||||
}
|
||||
|
||||
private void EnsureGemSlots()
|
||||
{
|
||||
if (slots == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
{
|
||||
if (slots[i] == null)
|
||||
slots[i] = new SkillLoadoutEntry();
|
||||
|
||||
slots[i].EnsureGemSlotCapacity();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/_Game/Scripts/Skills/PlayerLoadoutPreset.cs.meta
Normal file
2
Assets/_Game/Scripts/Skills/PlayerLoadoutPreset.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26d5895a89de4f24aade1ea4b5f7644e
|
||||
@@ -53,6 +53,9 @@ namespace Colosseum.Skills
|
||||
|
||||
// 현재 실행 중인 스킬
|
||||
private SkillData currentSkill;
|
||||
private SkillLoadoutEntry currentLoadoutEntry;
|
||||
private readonly List<SkillEffect> currentCastStartEffects = new();
|
||||
private readonly Dictionary<int, List<SkillEffect>> currentTriggeredEffects = new();
|
||||
private bool skillEndRequested; // OnSkillEnd 이벤트 호출 여부
|
||||
private bool waitingForEndAnimation; // EndAnimation 종료 대기 중
|
||||
|
||||
@@ -66,6 +69,7 @@ namespace Colosseum.Skills
|
||||
public bool UsesRootMotion => currentSkill != null && currentSkill.UseRootMotion;
|
||||
public bool IgnoreRootMotionY => currentSkill != null && currentSkill.IgnoreRootMotionY;
|
||||
public SkillData CurrentSkill => currentSkill;
|
||||
public SkillLoadoutEntry CurrentLoadoutEntry => currentLoadoutEntry;
|
||||
public Animator Animator => animator;
|
||||
public SkillCancelReason LastCancelReason => lastCancelReason;
|
||||
public string LastCancelledSkillName => lastCancelledSkillName;
|
||||
@@ -131,6 +135,15 @@ namespace Colosseum.Skills
|
||||
/// </summary>
|
||||
public bool ExecuteSkill(SkillData skill)
|
||||
{
|
||||
return ExecuteSkill(SkillLoadoutEntry.CreateTemporary(skill));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 슬롯 엔트리 기준으로 스킬 시전
|
||||
/// </summary>
|
||||
public bool ExecuteSkill(SkillLoadoutEntry loadoutEntry)
|
||||
{
|
||||
SkillData skill = loadoutEntry != null ? loadoutEntry.BaseSkill : null;
|
||||
if (skill == null)
|
||||
{
|
||||
Debug.LogWarning("Skill is null!");
|
||||
@@ -157,17 +170,19 @@ namespace Colosseum.Skills
|
||||
return false;
|
||||
}
|
||||
|
||||
currentLoadoutEntry = loadoutEntry != null ? loadoutEntry.CreateCopy() : SkillLoadoutEntry.CreateTemporary(skill);
|
||||
currentSkill = skill;
|
||||
skillEndRequested = false;
|
||||
waitingForEndAnimation = false;
|
||||
lastCancelReason = SkillCancelReason.None;
|
||||
BuildResolvedEffects(currentLoadoutEntry);
|
||||
|
||||
if (debugMode) Debug.Log($"[Skill] Cast: {skill.SkillName}");
|
||||
|
||||
// 쿨타임 시작
|
||||
StartCooldown(skill);
|
||||
StartCooldown(skill, currentLoadoutEntry.GetResolvedCooldown());
|
||||
|
||||
TriggerCastStartEffects(skill);
|
||||
TriggerCastStartEffects();
|
||||
|
||||
// 스킬 애니메이션 재생
|
||||
if (skill.SkillClip != null && animator != null)
|
||||
@@ -176,7 +191,7 @@ namespace Colosseum.Skills
|
||||
PlaySkillClip(skill.SkillClip);
|
||||
}
|
||||
|
||||
TriggerImmediateSelfEffectsIfNeeded(skill);
|
||||
TriggerImmediateSelfEffectsIfNeeded();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -185,17 +200,17 @@ namespace Colosseum.Skills
|
||||
/// 시전 시작 즉시 발동하는 효과를 실행합니다.
|
||||
/// 서버 권한으로만 처리해 실제 게임플레이 효과가 한 번만 적용되게 합니다.
|
||||
/// </summary>
|
||||
private void TriggerCastStartEffects(SkillData skill)
|
||||
private void TriggerCastStartEffects()
|
||||
{
|
||||
if (skill == null || skill.CastStartEffects == null || skill.CastStartEffects.Count == 0)
|
||||
if (currentSkill == null || currentCastStartEffects.Count == 0)
|
||||
return;
|
||||
|
||||
if (NetworkManager.Singleton != null && !NetworkManager.Singleton.IsServer)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < skill.CastStartEffects.Count; i++)
|
||||
for (int i = 0; i < currentCastStartEffects.Count; i++)
|
||||
{
|
||||
SkillEffect effect = skill.CastStartEffects[i];
|
||||
SkillEffect effect = currentCastStartEffects[i];
|
||||
if (effect == null)
|
||||
continue;
|
||||
|
||||
@@ -208,20 +223,23 @@ namespace Colosseum.Skills
|
||||
/// 애니메이션 이벤트가 없는 자기 자신 대상 효과는 시전 즉시 발동합니다.
|
||||
/// 버프/무적 같은 자기 강화 스킬이 이벤트 누락으로 동작하지 않는 상황을 막기 위한 보정입니다.
|
||||
/// </summary>
|
||||
private void TriggerImmediateSelfEffectsIfNeeded(SkillData skill)
|
||||
private void TriggerImmediateSelfEffectsIfNeeded()
|
||||
{
|
||||
if (skill == null || skill.Effects == null || skill.Effects.Count == 0)
|
||||
if (currentSkill == null || currentTriggeredEffects.Count == 0)
|
||||
return;
|
||||
|
||||
if (NetworkManager.Singleton != null && !NetworkManager.Singleton.IsServer)
|
||||
return;
|
||||
|
||||
if (skill.SkillClip != null && skill.SkillClip.events != null && skill.SkillClip.events.Length > 0)
|
||||
if (currentSkill.SkillClip != null && currentSkill.SkillClip.events != null && currentSkill.SkillClip.events.Length > 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < skill.Effects.Count; i++)
|
||||
if (!currentTriggeredEffects.TryGetValue(0, out List<SkillEffect> effectsAtZero))
|
||||
return;
|
||||
|
||||
for (int i = 0; i < effectsAtZero.Count; i++)
|
||||
{
|
||||
SkillEffect effect = skill.Effects[i];
|
||||
SkillEffect effect = effectsAtZero[i];
|
||||
if (effect == null || effect.TargetType != TargetType.Self)
|
||||
continue;
|
||||
|
||||
@@ -230,6 +248,21 @@ namespace Colosseum.Skills
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 슬롯 엔트리 기준으로 시전 시작/트리거 효과를 합성합니다.
|
||||
/// </summary>
|
||||
private void BuildResolvedEffects(SkillLoadoutEntry loadoutEntry)
|
||||
{
|
||||
currentCastStartEffects.Clear();
|
||||
currentTriggeredEffects.Clear();
|
||||
|
||||
if (loadoutEntry == null)
|
||||
return;
|
||||
|
||||
loadoutEntry.CollectCastStartEffects(currentCastStartEffects);
|
||||
loadoutEntry.CollectTriggeredEffects(currentTriggeredEffects);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 스킬 클립으로 Override Controller 생성 후 재생
|
||||
/// </summary>
|
||||
@@ -354,23 +387,28 @@ namespace Colosseum.Skills
|
||||
return;
|
||||
}
|
||||
|
||||
var effects = currentSkill.Effects;
|
||||
if (index < 0 || index >= effects.Count)
|
||||
if (!currentTriggeredEffects.TryGetValue(index, out List<SkillEffect> effects) || effects == null || effects.Count == 0)
|
||||
{
|
||||
if (debugMode) Debug.LogWarning($"[Effect] Invalid index: {index}");
|
||||
return;
|
||||
}
|
||||
|
||||
var effect = effects[index];
|
||||
if (debugMode) Debug.Log($"[Effect] {effect.name} (index {index})");
|
||||
|
||||
// 공격 범위 시각화
|
||||
if (showAreaDebug)
|
||||
for (int i = 0; i < effects.Count; i++)
|
||||
{
|
||||
effect.DrawDebugRange(gameObject, debugDrawDuration);
|
||||
}
|
||||
SkillEffect effect = effects[i];
|
||||
if (effect == null)
|
||||
continue;
|
||||
|
||||
effect.ExecuteOnCast(gameObject);
|
||||
if (debugMode) Debug.Log($"[Effect] {effect.name} (index {index})");
|
||||
|
||||
// 공격 범위 시각화
|
||||
if (showAreaDebug)
|
||||
{
|
||||
effect.DrawDebugRange(gameObject, debugDrawDuration);
|
||||
}
|
||||
|
||||
effect.ExecuteOnCast(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -408,6 +446,9 @@ namespace Colosseum.Skills
|
||||
|
||||
RestoreBaseController();
|
||||
currentSkill = null;
|
||||
currentLoadoutEntry = null;
|
||||
currentCastStartEffects.Clear();
|
||||
currentTriggeredEffects.Clear();
|
||||
skillEndRequested = false;
|
||||
waitingForEndAnimation = false;
|
||||
return true;
|
||||
@@ -430,9 +471,9 @@ namespace Colosseum.Skills
|
||||
return Mathf.Max(0f, remaining);
|
||||
}
|
||||
|
||||
private void StartCooldown(SkillData skill)
|
||||
private void StartCooldown(SkillData skill, float cooldownDuration)
|
||||
{
|
||||
cooldownTracker[skill] = Time.time + skill.Cooldown;
|
||||
cooldownTracker[skill] = Time.time + cooldownDuration;
|
||||
}
|
||||
|
||||
public void ResetCooldown(SkillData skill)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Colosseum.Skills
|
||||
{
|
||||
/// <summary>
|
||||
@@ -43,6 +45,10 @@ namespace Colosseum.Skills
|
||||
[Min(0f)] [SerializeField] private float cooldown = 1f;
|
||||
[Min(0f)] [SerializeField] private float manaCost = 0f;
|
||||
|
||||
[Header("젬 슬롯")]
|
||||
[Tooltip("이 스킬에 장착 가능한 젬 슬롯 수")]
|
||||
[Min(0)] [SerializeField] private int maxGemSlotCount = 2;
|
||||
|
||||
[Header("효과 목록")]
|
||||
[Tooltip("시전 시작 즉시 발동하는 효과 목록. 시전 보호 버프 등에 사용됩니다.")]
|
||||
[SerializeField] private List<SkillEffect> castStartEffects = new List<SkillEffect>();
|
||||
@@ -60,6 +66,7 @@ namespace Colosseum.Skills
|
||||
public float AnimationSpeed => animationSpeed;
|
||||
public float Cooldown => cooldown;
|
||||
public float ManaCost => manaCost;
|
||||
public int MaxGemSlotCount => maxGemSlotCount;
|
||||
public bool UseRootMotion => useRootMotion;
|
||||
public bool IgnoreRootMotionY => ignoreRootMotionY;
|
||||
public bool JumpToTarget => jumpToTarget;
|
||||
|
||||
55
Assets/_Game/Scripts/Skills/SkillGemData.cs
Normal file
55
Assets/_Game/Scripts/Skills/SkillGemData.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Colosseum.Skills
|
||||
{
|
||||
/// <summary>
|
||||
/// 젬 효과가 발동될 애니메이션 이벤트 인덱스와 효과 목록입니다.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SkillGemTriggeredEffectEntry
|
||||
{
|
||||
[Tooltip("OnEffect(index)와 매칭되는 애니메이션 이벤트 인덱스")]
|
||||
[Min(0)] [SerializeField] private int triggerIndex = 0;
|
||||
[Tooltip("해당 인덱스에서 함께 실행할 추가 효과")]
|
||||
[SerializeField] private List<SkillEffect> effects = new();
|
||||
|
||||
public int TriggerIndex => triggerIndex;
|
||||
public IReadOnlyList<SkillEffect> Effects => effects;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 스킬의 기반 효과 위에 추가 동작을 덧붙이는 젬 데이터입니다.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "NewSkillGem", menuName = "Colosseum/Skill Gem")]
|
||||
public class SkillGemData : ScriptableObject
|
||||
{
|
||||
[Header("기본 정보")]
|
||||
[SerializeField] private string gemName;
|
||||
[TextArea(2, 4)]
|
||||
[SerializeField] private string description;
|
||||
[SerializeField] private Sprite icon;
|
||||
|
||||
[Header("기본 수치 보정")]
|
||||
[Tooltip("장착 시 마나 비용 배율")]
|
||||
[Min(0f)] [SerializeField] private float manaCostMultiplier = 1f;
|
||||
[Tooltip("장착 시 쿨타임 배율")]
|
||||
[Min(0f)] [SerializeField] private float cooldownMultiplier = 1f;
|
||||
|
||||
[Header("추가 효과")]
|
||||
[Tooltip("시전 시작 시 즉시 발동하는 추가 효과")]
|
||||
[SerializeField] private List<SkillEffect> castStartEffects = new();
|
||||
[Tooltip("애니메이션 이벤트 인덱스별로 발동하는 추가 효과")]
|
||||
[SerializeField] private List<SkillGemTriggeredEffectEntry> triggeredEffects = new();
|
||||
|
||||
public string GemName => gemName;
|
||||
public string Description => description;
|
||||
public Sprite Icon => icon;
|
||||
public float ManaCostMultiplier => manaCostMultiplier;
|
||||
public float CooldownMultiplier => cooldownMultiplier;
|
||||
public IReadOnlyList<SkillEffect> CastStartEffects => castStartEffects;
|
||||
public IReadOnlyList<SkillGemTriggeredEffectEntry> TriggeredEffects => triggeredEffects;
|
||||
}
|
||||
}
|
||||
2
Assets/_Game/Scripts/Skills/SkillGemData.cs.meta
Normal file
2
Assets/_Game/Scripts/Skills/SkillGemData.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e81a62ae7c7624847ab572ff37789bb8
|
||||
226
Assets/_Game/Scripts/Skills/SkillLoadoutEntry.cs
Normal file
226
Assets/_Game/Scripts/Skills/SkillLoadoutEntry.cs
Normal file
@@ -0,0 +1,226 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Colosseum.Skills
|
||||
{
|
||||
/// <summary>
|
||||
/// 단일 슬롯에서 사용할 스킬과 장착된 젬 조합입니다.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class SkillLoadoutEntry
|
||||
{
|
||||
private const int DefaultGemSlotCount = 2;
|
||||
|
||||
[Tooltip("이 슬롯의 기반 스킬")]
|
||||
[SerializeField] private SkillData baseSkill;
|
||||
[Tooltip("기반 스킬에 장착된 젬")]
|
||||
[SerializeField] private SkillGemData[] socketedGems = new SkillGemData[DefaultGemSlotCount];
|
||||
|
||||
public SkillData BaseSkill => baseSkill;
|
||||
public IReadOnlyList<SkillGemData> SocketedGems => socketedGems;
|
||||
|
||||
public static SkillLoadoutEntry CreateTemporary(SkillData skill)
|
||||
{
|
||||
SkillLoadoutEntry entry = new SkillLoadoutEntry();
|
||||
entry.SetBaseSkill(skill);
|
||||
entry.EnsureGemSlotCapacity();
|
||||
return entry;
|
||||
}
|
||||
|
||||
public SkillLoadoutEntry CreateCopy()
|
||||
{
|
||||
SkillLoadoutEntry copy = new SkillLoadoutEntry();
|
||||
copy.baseSkill = baseSkill;
|
||||
copy.socketedGems = new SkillGemData[socketedGems != null ? socketedGems.Length : DefaultGemSlotCount];
|
||||
|
||||
if (socketedGems != null)
|
||||
{
|
||||
for (int i = 0; i < socketedGems.Length; i++)
|
||||
{
|
||||
copy.socketedGems[i] = socketedGems[i];
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
public void EnsureGemSlotCapacity(int slotCount = -1)
|
||||
{
|
||||
if (slotCount < 0)
|
||||
{
|
||||
slotCount = baseSkill != null ? baseSkill.MaxGemSlotCount : DefaultGemSlotCount;
|
||||
}
|
||||
|
||||
slotCount = Mathf.Max(0, slotCount);
|
||||
if (socketedGems != null && socketedGems.Length == slotCount)
|
||||
return;
|
||||
|
||||
SkillGemData[] resized = new SkillGemData[slotCount];
|
||||
if (socketedGems != null)
|
||||
{
|
||||
int copyCount = Mathf.Min(socketedGems.Length, resized.Length);
|
||||
for (int i = 0; i < copyCount; i++)
|
||||
{
|
||||
resized[i] = socketedGems[i];
|
||||
}
|
||||
}
|
||||
|
||||
socketedGems = resized;
|
||||
}
|
||||
|
||||
public void SetBaseSkill(SkillData skill)
|
||||
{
|
||||
baseSkill = skill;
|
||||
EnsureGemSlotCapacity();
|
||||
}
|
||||
|
||||
public void SetGem(int slotIndex, SkillGemData gem)
|
||||
{
|
||||
EnsureGemSlotCapacity();
|
||||
if (slotIndex < 0 || slotIndex >= socketedGems.Length)
|
||||
return;
|
||||
|
||||
socketedGems[slotIndex] = gem;
|
||||
}
|
||||
|
||||
public SkillGemData GetGem(int slotIndex)
|
||||
{
|
||||
EnsureGemSlotCapacity();
|
||||
if (slotIndex < 0 || slotIndex >= socketedGems.Length)
|
||||
return null;
|
||||
|
||||
return socketedGems[slotIndex];
|
||||
}
|
||||
|
||||
public float GetResolvedManaCost()
|
||||
{
|
||||
if (baseSkill == null)
|
||||
return 0f;
|
||||
|
||||
float resolved = baseSkill.ManaCost;
|
||||
if (socketedGems == null)
|
||||
return resolved;
|
||||
|
||||
for (int i = 0; i < socketedGems.Length; i++)
|
||||
{
|
||||
SkillGemData gem = socketedGems[i];
|
||||
if (gem == null)
|
||||
continue;
|
||||
|
||||
resolved *= gem.ManaCostMultiplier;
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
public float GetResolvedCooldown()
|
||||
{
|
||||
if (baseSkill == null)
|
||||
return 0f;
|
||||
|
||||
float resolved = baseSkill.Cooldown;
|
||||
if (socketedGems == null)
|
||||
return resolved;
|
||||
|
||||
for (int i = 0; i < socketedGems.Length; i++)
|
||||
{
|
||||
SkillGemData gem = socketedGems[i];
|
||||
if (gem == null)
|
||||
continue;
|
||||
|
||||
resolved *= gem.CooldownMultiplier;
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
public void CollectCastStartEffects(List<SkillEffect> destination)
|
||||
{
|
||||
if (destination == null)
|
||||
return;
|
||||
|
||||
if (baseSkill != null && baseSkill.CastStartEffects != null)
|
||||
{
|
||||
for (int i = 0; i < baseSkill.CastStartEffects.Count; i++)
|
||||
{
|
||||
SkillEffect effect = baseSkill.CastStartEffects[i];
|
||||
if (effect != null)
|
||||
destination.Add(effect);
|
||||
}
|
||||
}
|
||||
|
||||
if (socketedGems == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < socketedGems.Length; i++)
|
||||
{
|
||||
SkillGemData gem = socketedGems[i];
|
||||
if (gem == null || gem.CastStartEffects == null)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < gem.CastStartEffects.Count; j++)
|
||||
{
|
||||
SkillEffect effect = gem.CastStartEffects[j];
|
||||
if (effect != null)
|
||||
destination.Add(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CollectTriggeredEffects(Dictionary<int, List<SkillEffect>> destination)
|
||||
{
|
||||
if (destination == null)
|
||||
return;
|
||||
|
||||
if (baseSkill != null && baseSkill.Effects != null)
|
||||
{
|
||||
for (int i = 0; i < baseSkill.Effects.Count; i++)
|
||||
{
|
||||
SkillEffect effect = baseSkill.Effects[i];
|
||||
if (effect == null)
|
||||
continue;
|
||||
|
||||
AddTriggeredEffect(destination, i, effect);
|
||||
}
|
||||
}
|
||||
|
||||
if (socketedGems == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < socketedGems.Length; i++)
|
||||
{
|
||||
SkillGemData gem = socketedGems[i];
|
||||
if (gem == null || gem.TriggeredEffects == null)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < gem.TriggeredEffects.Count; j++)
|
||||
{
|
||||
SkillGemTriggeredEffectEntry entry = gem.TriggeredEffects[j];
|
||||
if (entry == null || entry.Effects == null)
|
||||
continue;
|
||||
|
||||
for (int k = 0; k < entry.Effects.Count; k++)
|
||||
{
|
||||
SkillEffect effect = entry.Effects[k];
|
||||
if (effect == null)
|
||||
continue;
|
||||
|
||||
AddTriggeredEffect(destination, entry.TriggerIndex, effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddTriggeredEffect(Dictionary<int, List<SkillEffect>> destination, int triggerIndex, SkillEffect effect)
|
||||
{
|
||||
if (!destination.TryGetValue(triggerIndex, out List<SkillEffect> effectList))
|
||||
{
|
||||
effectList = new List<SkillEffect>();
|
||||
destination.Add(triggerIndex, effectList);
|
||||
}
|
||||
|
||||
effectList.Add(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/_Game/Scripts/Skills/SkillLoadoutEntry.cs.meta
Normal file
2
Assets/_Game/Scripts/Skills/SkillLoadoutEntry.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d06556806f8c370429a54ca7af7e2a34
|
||||
Reference in New Issue
Block a user