|
|
|
|
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<ItemData> items = new List<ItemData>();//장착 아이템이 스킬을 보유하기에 Skill.cs 에서 기록중
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 착용중인 아이템중에 같은것이 있는지 확인합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="idx">아이템 번호</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool HoldingItemCheck(string idx)
|
|
|
|
|
{
|
|
|
|
|
return items.Find(a => a.idx.Equals(idx)) != null;
|
|
|
|
|
}
|
|
|
|
|
public System.Action<List<ItemData>> OnChangedInstall;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 장비가 장착되어 이를 적용합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="item">아이템 번호</param>
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 장비가 해제되어 이를 적용합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="item">아이템 번호</param>
|
|
|
|
|
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<SkillData> skills = new List<SkillData>();
|
|
|
|
|
public void OnInitialized()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < skills.Count; i++)
|
|
|
|
|
skills[i].cntUse = 0;//스킬 사용 횟수 제한 초기화
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 스킬을 추가합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data"></param>
|
|
|
|
|
/// <param name="OVERLAP"></param>
|
|
|
|
|
void SkillAdd(SkillData data, bool OVERLAP = false)
|
|
|
|
|
{
|
|
|
|
|
skills.Add(data);
|
|
|
|
|
if (data.trigger.Equals("Install"))
|
|
|
|
|
Motion_Start(data, null);
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 스킬을 삭제합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data"></param>
|
|
|
|
|
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} 이미 적용 되어 있지 않은 스킬");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 해당 조건에 만족하는 스킬이 있는지 확인합니다.
|
|
|
|
|
/// Skill.cs 가 아닌 다른 스크립트에서 적용해야 하는 경우 사용합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="trigger">발동 조건</param>
|
|
|
|
|
/// <param name="work">하는 일</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public SkillData Active(string trigger, string work)
|
|
|
|
|
{
|
|
|
|
|
List<SkillData> 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;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 연출이 필요한 스킬의 발동을 위해 사용
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="trigger"></param>
|
|
|
|
|
/// <param name="owner"></param>
|
|
|
|
|
/// <param name="OnEnd"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool Active(string trigger, object value, System.Action<SkillData> 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<SkillData> SkillList_IDX(string idx)
|
|
|
|
|
{
|
|
|
|
|
return skills.FindAll(a => a.IDX.Equals(idx));
|
|
|
|
|
}
|
|
|
|
|
public List<SkillData> SkillList_Trigger(string trigger)
|
|
|
|
|
{
|
|
|
|
|
return skills.FindAll(a => a.trigger.Equals(trigger));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Motion_Start(SkillData active, object value, System.Action<SkillData> 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<object> datas = new List<object>();
|
|
|
|
|
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<object> datas = new List<object>();
|
|
|
|
|
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<SkillData> 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|