using DG.Tweening; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.Serialization; public class Skill : MonoBehaviour { public Character character; public Motion motion; public List items = new List();//장착 아이템이 스킬을 보유하기에 Skill.cs 에서 기록중 /// /// 착용중인 아이템중에 같은것이 있는지 확인합니다. /// /// 아이템 번호 /// public bool HoldingItemCheck(string idx) { return items.Find(a => a.idx.Equals(idx)) != null; } public System.Action> OnChangedInstall; /// /// 장비가 장착되어 이를 적용합니다. /// /// 아이템 번호 public void Install(ItemData item) { items.Add(item);//아이템 장착 for (int i = 0; i < item.skills.Count; i++) SkillAdd(item.skills[i]); if (OnChangedInstall != null) OnChangedInstall(items); } /// /// 장비가 해제되어 이를 적용합니다. /// /// 아이템 번호 public void UnInstall(ItemData item) { items.Remove(item);//아이템 해제 for (int i = 0; i < item.skills.Count; i++) SkillDelete(item.skills[i]); if (OnChangedInstall != null) OnChangedInstall(items); } public List skills = new List(); public void OnInitialized() { for (int i = 0; i < skills.Count; i++) skills[i].cntUse = 0;//스킬 사용 횟수 제한 초기화 } /// /// 스킬을 추가합니다. /// /// /// void SkillAdd(SkillData data, bool OVERLAP = false) { skills.Add(data); if (data.trigger.Equals("Install")) Motion_Start(data, null); } /// /// 스킬을 삭제합니다. /// /// void SkillDelete(SkillData data) { if (skills.Contains(data)) { skills.Remove(data); if (data.trigger.Equals("Install")) { data.value = -data.value; Motion_Start(data, null); data.value = -data.value; } } else Debug.LogError($"Skill.Add : {data.trigger}-{data.work}-{data.value} 이미 적용 되어 있지 않은 스킬"); } /// /// 해당 조건에 만족하는 스킬이 있는지 확인합니다. /// Skill.cs 가 아닌 다른 스크립트에서 적용해야 하는 경우 사용합니다. /// /// 발동 조건 /// 하는 일 /// public SkillData Active(string trigger, string work) { List checks = skills.FindAll(a => a.trigger.Equals(trigger) && a.work.Equals(work)); for (int i = 0; i < checks.Count; i++) { if (checks[i].Activate(trigger)) return checks[i]; } return null; } /// /// 연출이 필요한 스킬의 발동을 위해 사용 /// /// /// /// /// public bool Active(string trigger, object value, System.Action OnEnd) { for (int i = 0; i < skills.Count; i++) { if (skills[i].Activate(trigger)) { character.OnLocked(true); SkillData active = skills[i]; Motion_Start(active, value, OnEnd); if (skills[i].motion == null) { character.OnLocked(false); if (OnEnd != null) OnEnd(active); } else { motion.Play_Force(skills[i].motion, () => { Motion_End(active, value, OnEnd); }, data => { Motion_Event(active, value, data); }); } return true; } } return false; } public List SkillList_IDX(string idx) { return skills.FindAll(a => a.IDX.Equals(idx)); } public List SkillList_Trigger(string trigger) { return skills.FindAll(a => a.trigger.Equals(trigger)); } void Motion_Start(SkillData active, object value, System.Action OnEnd = null) { switch (active.work) { case "Resurrection": { if (character.CompareTag("Enemy")) character.map.blkCurrent.Monster_Resurrection(character);//부활 } break; case "RaiseShield": { character.OnDefense = delegate (Character attacker) { character.OnDefense = null; character.motion.Play_Force(active.motion2, () => { if (OnEnd != null) OnEnd(active); }, null); }; } break; case "HPRestore": { character.Restore((int)active.value); skills.Remove(active); } break; case "HPMax": { character.Restore((int)active.value); } break; case "AH": { if (-1 < active.value) character.OnChanged_ArmorHeart((int)active.value); } break; case "AHRestore": { character.OnAdded_ArmorHeart((int)active.value); skills.Remove(active); } break; case "ATK": { //character.ATK += (int)active.value; character.ATKChanged((int)active.value, true);//캐릭터의 공격력 상승 } break; case "ATKRate": { //character.ATK_PER += active.value; character.ATKRateChanged(active.value, true);//캐릭터의 공격력 % 상승 } break; case "RANGE"://사거리 { character.RangeChanged(active.value, true); } break; case "SPDMOVE"://이동속도 { character.SpeedMoveChanged(active.value); } break; case "SPDATK"://공격모션 속도 { character.SpeedAttackChanged(active.value, true); } break; case "DLAATKRate": { character.DelayAttackChanged(active.value, true); } break; case "DLAATK": { character.DelayAttackChanged(active.value, false); } break; case "DropItem": { for (int i = 0; i < active.value; i++) character.map.blkCurrent.OnDropItem_Create(value == null ? transform : ((Character)value).transform, active.work2); } break; } } void Motion_Event(SkillData active, object value, Spine.Event data) { //Debug.LogWarning($"{name} : {active.IDX} {data.Data.Name} 이벤트 발생"); switch (active.work) { case "Clone": { Character mob = character.map.blkCurrent.Monster_Create(character, transform.position);//복제 mob.OnWarp(transform.position); mob.OnLocked(true); mob.transform.DOMove(Util.PointCreate(mob.transform.position, 2f), 0.5f); mob.motion.Play_Force(active.motion2, () => { mob.OnInitialized(character.HP, character.HP_Max);//몬스터 생성 : 스킬-클론 mob.OnLocked(false); }, null); } break; case "GuidedProjectile": { Transform target = (Transform)value; List datas = new List(); datas.Add(target); Vector3 dir = target != null ? (target.position - transform.position).normalized : motion.LookDir().normalized; datas.Add(dir); motion.LookSet(dir.x < 0 ? 1 : -1); datas.Add(active.prefab); datas.Add(active.value2); datas.Add(active.value); active.onConnect.Invoke(0, datas); } break; case "RockProjectile": { Transform target = (Transform)value; List datas = new List(); datas.Add(target); Vector3 dir = target != null ? (target.position - transform.position) : motion.LookDir(); datas.Add(dir); motion.LookSet(dir.x < 0 ? 1 : -1); datas.Add(active.prefab); datas.Add(active.value2); datas.Add(active.value); active.onConnect.Invoke(0, datas); } break; case "GiantySkill1": { Debug.LogWarning($"{active.work} : {data.Data.Name}"); } break; } } void Motion_End(SkillData active, object value, System.Action OnEnd) { switch (active.work) { //case "Resurrection": // { // //character.Restore_MaxRate(active.value); // //character.OnInitialized(); // if (OnEnd != null) // OnEnd(active); // } // break; case "RaiseShield": { character.OnDefense = null; if (OnEnd != null) OnEnd(active); } break; case "RockProjectile": { character.motion.Play_Force(active.motion2, () => { if (OnEnd != null) OnEnd(active); }, data => { Motion_Event(active, value, data); }); } break; default: { if (OnEnd != null) OnEnd(active); } break; } } }