using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Unity.VisualScripting; using UnityEngine; using UnityEngine.AI; using UnityEngine.SceneManagement; public class Actor : MyCoroutine { public GameObject[] gos_Effect; public eRole m_Role; // 프리팹 설정 public eSubRol m_SubRole; // 프리팹 설정 public eAttackType m_AttackType; // 프리팹 설정 protected NavMeshAgent m_NavMeshAgent; protected BoxCollider m_BoxCollider; eAnim _curanim; protected eAnim CurAnim { get { return _curanim; } set { _curanim = value; //if (IsRole(eRole.PC)) Debug.Log("애님 변경 " + value); } } public Animator m_animation; protected ActorStatInfo m_Stat; protected double receiveaccumulateDmg, m_Damage, m_attackCoolTime; // 내가 받은 피해, 내가 준 피해, 공격 쿨타임 protected Transform tf_HUD_HP, tf_HUD_Dmg; protected Vector3 ObjSize; [SerializeField] protected Actor m_Target, m_MyPet; protected Dictionary dic_MagicData = new Dictionary(); protected UseMagicInfo m_Magic; protected float m_NavSpeed, m_NavStopDistance, m_HitTime, FindOtherTargetTime = 7.5f, GoToTargetTime = 10f, OriginalAnimSpeed, m_fAttackMoveTime, m_DamageRate = 1f; protected bool m_Enemy, IsPlaySkill, IsChargeAttack, m_Auto, DeadStatus, hasAppliedDamage; protected bool _isstop; protected bool IsStop { get { return _isstop; } set { _isstop = value; //Debug.Log("IsStop 변경 " + value); } } public bool m_IsLockTarget { get; set; } protected bool m_bCanDodge, m_bImmortal; protected int m_ID; protected ServerData m_ServerData; protected Renderer[] arr_Renderer; protected TurnOff_GO[] arr_Effects; protected Dictionary dic_skillextra = new Dictionary(); protected Dictionary dic_ccData = new Dictionary(); protected Dictionary> dic_ccAddRate = new Dictionary>(); protected void Init_CC() { if (dic_ccData.Count == 0) for (eCC i = 0; i < eCC.Max; i++) dic_ccData.Add(i, new CCData()); foreach (var item in dic_ccData) item.Value.Init(); dic_ccAddRate.Clear(); foreach (var key in dic_skillextra.Keys.ToList()) dic_skillextra[key] = false; } protected void Check_CCAddRate(eCC cc, Actor actor, double v = 0) { if (!dic_ccAddRate.ContainsKey(cc)) dic_ccAddRate.Add(cc, new Dictionary()); if (!dic_ccAddRate[cc].ContainsKey(actor)) dic_ccAddRate[cc].Add(actor, v); } protected double Get_CCAddRate(eCC cc, Actor actor) { return dic_ccAddRate.ContainsKey(cc) && dic_ccAddRate[cc].ContainsKey(actor) ? dic_ccAddRate[cc][actor] : 0; } protected Action act_MoveEnd; protected List list_SkillData = new List(); ProjectileData m_SkillData; public HUDUI m_HUDUI { get; set; } protected virtual void Awake() { m_NavMeshAgent = GetComponent(); m_BoxCollider = GetComponent(); m_animation = GetComponent(); arr_Renderer = GetComponentsInChildren(); arr_Effects = GetComponentsInChildren(true); for (int i = 0; i < 6; i++) list_SkillData.Add(new ProjectileData { shooter = this }); // HUD 만들기 Make_HUDobj(); m_NavSpeed = m_NavMeshAgent.speed; m_NavStopDistance = m_NavMeshAgent.stoppingDistance; } void Make_HUDobj() { float maxY = float.MinValue; // 가장 큰 y값을 저장할 변수 // 캐릭터 하위의 모든 Renderer를 찾음 Renderer[] renderers = GetComponentsInChildren(); // 각 Renderer의 Bounds.max.y를 비교 foreach (Renderer renderer in renderers) { float rendererMaxY = renderer.bounds.max.y; if (rendererMaxY > maxY) { maxY = rendererMaxY; } } var hud_hp = new GameObject("HUD_HP"); tf_HUD_HP = hud_hp.transform; tf_HUD_HP.parent = transform; tf_HUD_HP.position = Get_position() + Vector3.down * 0.1f; // maxY를 기준으로 HUD 위치 조정 Vector3 headPosition = new Vector3(transform.position.x, maxY, transform.position.z); var hud_dmg = new GameObject("HUD_Dmg"); tf_HUD_Dmg = hud_dmg.transform; tf_HUD_Dmg.parent = transform; tf_HUD_Dmg.position = headPosition; } protected virtual void Start() { } protected virtual void OnEnable() { if (gos_Effect != null) DSUtil.InActivateGameObjects(gos_Effect); } protected virtual void OnDestroy() { if (m_HUDUI) Destroy(m_HUDUI.gameObject); } protected override void Update() { if (IsChargeAttack) { if (IsStop || IsDead() || IsCC()) return; if (DSUtil.CheckNull(m_Target) || m_Target.IsDead()) Set_Target(); if (DSUtil.CheckNull(m_Target)) { Play_Idle(); return; } if (Vector3.Distance(Get_position(), m_Target.Get_position()) > m_NavMeshAgent.stoppingDistance) Play_Run(); else if (CurAnim != eAnim.Attack) Play_Attack(0, (float)m_Stat.Get_Stat(eStat.FinalAttackSpeed)); } Update_ETC(); } protected virtual void FixedUpdate() { } protected void Update_ETC() { foreach (var item in dic_ccData) { if (item.Value.CCReduceTime > 0f) item.Value.CCReduceTime -= 0.0001f; if (item.Value.CCReduceTime < 0f) item.Value.CCReduceTime = 0f; } foreach (var item in dic_ccData) { if (item.Value.TimeUpdate && item.Value.CCTime > 0) { item.Value.CCTime -= Time.deltaTime; if (item.Value.CCTime <= 0) { switch (item.Key) { case eCC.STR_Mul_Up: Off_StatUpBuff(eStat.STR); break; case eCC.DEX_Mul_Up: Off_StatUpBuff(eStat.DEX); break; case eCC.INT_Mul_Up: Off_StatUpBuff(eStat.INT); break; case eCC.LUK_Mul_Up: Off_StatUpBuff(eStat.LUK); break; } } } } } protected bool isPlaying() { float normalizedTime = m_animation.GetCurrentAnimatorStateInfo(0).normalizedTime; // normalizedTime을 0.0에서 1.0 사이로 맞춤 normalizedTime = Mathf.Repeat(normalizedTime, 1.0f); // 애니메이션이 95% 이하로 진행 중인지 확인 return normalizedTime < 0.95f; } protected bool isPlaying(params eAnim[] anims) { var curState = m_animation.GetCurrentAnimatorStateInfo(0); for (int i = 0; i < anims.Length; i++) { if (curState.IsName(MyValue.Get_AnimName(anims[i]))) return true; } return false; } protected virtual void Set_Target(bool _usemagic = false) { } public virtual void Set(bool isEnemy, Actor owner, ServerData sdata, int _id, bool _stop, bool _ui = false) { if (IsRole(eRole.PC)) ObjSize = GetComponent().bounds.size; else ObjSize = GetComponentInChildren().bounds.size; gameObject.SetActive(true); Init_CC(); DeadStatus = false; m_Enemy = isEnemy; Make_HUDUI(); m_ServerData = sdata; CurAnim = eAnim.Idle; Play_Idle(); m_ID = _id; IsStop = _stop; //m_NavMeshAgent.speed = m_NavSpeed; receiveaccumulateDmg = m_Damage = 0; } public virtual void Off() { if (!DSUtil.CheckNull(m_HUDUI)) m_HUDUI.Off(); gameObject.SetActive(false); } public virtual void Set_Card(int index, int chapter) { } public virtual void ReSet() { } public virtual void Set_Stat(bool init) { if (DSUtil.CheckNull(m_Stat)) m_Stat = MyValue.MakeorGet_ActorStatInfo(m_Role, Get_ServerData(), null); else m_Stat.Reset(); m_NavMeshAgent.speed = (float)m_Stat.Get_Stat(eStat.FinalMoveSpeed); } protected void Add_MoveSpeed(float _v) { m_NavMeshAgent.speed = Mathf.Min(m_NavSpeed + _v, 8.5f); } public virtual void Set_MaxHP_Minus_HP(double _hp) { m_Stat.Set_Stat(false, eStat.HP, _hp); } public virtual void Set_Stat_SelectSkill(SelectSkillTableData _sstd) { } public virtual void Stop(bool _stop) { IsStop = _stop; if (IsStop) { if (m_NavMeshAgent && m_NavMeshAgent.isOnNavMesh) m_NavMeshAgent.ResetPath(); Play_Idle(); } } public virtual void Set_JoystickStatus(int status) { } public void Set_Warp(Vector3 _pos) { if (m_BoxCollider) m_BoxCollider.enabled = true; m_NavMeshAgent.enabled = true; // 사망 시 off 됨. 다시 세팅될 때 켜줌 m_NavMeshAgent.Warp(_pos); } public virtual void Run_byJoystick(Vector3 _v) { } protected void StopMove_Imm(bool setIdle) { if (setIdle) CurAnim = eAnim.Idle; if (m_NavMeshAgent.isOnNavMesh) { m_NavMeshAgent.isStopped = true; m_NavMeshAgent.ResetPath(); // 경로를 비워서 멈춤 m_NavMeshAgent.velocity = Vector3.zero; // 이 경우도 velocity를 0으로 설정 } } int FindCount = 0; protected bool Set_Path(Vector3 _pos) { if (m_NavMeshAgent.enabled && m_NavMeshAgent.isOnNavMesh) { NavMeshPath path = new NavMeshPath(); m_NavMeshAgent.CalculatePath(_pos, path); switch (path.status) { case NavMeshPathStatus.PathComplete: m_NavMeshAgent.speed = Get_MoveSpeed(); m_NavMeshAgent.SetPath(path); FindCount = 0; // 성공 시 초기화 return true; case NavMeshPathStatus.PathPartial: ++FindCount; Debug.Log($"Path Partial. Attempt: {FindCount}"); if (FindCount > 5) { FindCount = 0; return false; } var newpos = DSUtil.Get_RandomPos_onNavMesh(_pos, 0f, 5f); return Set_Path(newpos); case NavMeshPathStatus.PathInvalid: Debug.LogWarning("Path Invalid."); // 적 근처로 워프넣어볼까? //Set_Warp(DSUtil.Get_RandomPos_onNavMesh(_pos, 3f)); break; } } return false; } protected void Set_Move(Vector3 _pos) { if (m_NavMeshAgent.enabled && m_NavMeshAgent.isOnNavMesh) { m_fAttackMoveTime = 1f; #if UNITY_EDITOR if (SceneManager.GetActiveScene().name == "StatTest") m_fAttackMoveTime = 0f; #endif m_NavMeshAgent.stoppingDistance = 0; // 툴에서 사용 용도 m_NavMeshAgent.isStopped = false; m_NavMeshAgent.angularSpeed = 0f; NavMeshPath path = new NavMeshPath(); m_NavMeshAgent.CalculatePath(_pos, path); switch (path.status) { case NavMeshPathStatus.PathComplete: m_NavMeshAgent.SetPath(path); break; } } } protected void Set_Destination(Vector3 _pos) { if (m_NavMeshAgent.enabled && m_NavMeshAgent.isOnNavMesh) { m_NavMeshAgent.ResetPath(); m_NavMeshAgent.SetDestination(_pos); } } protected bool Complete_Destination() { if (m_NavMeshAgent.isOnNavMesh && !m_NavMeshAgent.pathPending) if (m_NavMeshAgent.remainingDistance <= m_NavMeshAgent.stoppingDistance) if (!m_NavMeshAgent.hasPath || m_NavMeshAgent.velocity.sqrMagnitude == 0f) return true; return false; } public void ReCal_NaveMesh() { //return; // TODO 정인호 : 내비메시의 이상한 위치에 있으면 주변을 검색해서 내비메시 위로 올리는데 이상한 위치로 갈 수 있어서 일단 다시 뺌 if (m_ID != 61 && m_NavMeshAgent && m_NavMeshAgent.enabled) { var newpos = DSUtil.Get_RandomPos_onNavMesh(Get_position(), 0f, 1f); if (!Vector3.Equals(newpos, Get_position())) Set_Warp(newpos); } } public void Set_AttackCoolTime(float _rate) { var cooltime = m_Stat.Get_Stat(eStat.AttackCoolTime) * _rate; if (m_attackCoolTime > cooltime) m_attackCoolTime = cooltime; } protected void Make_HUDUI(Action act = null) { #if UNITY_EDITOR if (SceneManager.GetActiveScene().name == "StatTest" || SceneManager.GetActiveScene().name == "Settings") return; #endif InGameInfo.Ins.Get_HUDUI(hudui => { m_HUDUI = hudui; m_HUDUI.name = name; m_HUDUI.Init(this, tf_HUD_HP); act?.Invoke(); }); } public virtual DamageInfo Get_DamageInfo(ProjectileData _pd, double _attackrate = 1d, bool forceCri = false) { var atkData = Get_CCData(eCC.ATK_Up); var addAtk = atkData.CCTime > 0 ? atkData.CCDmg : 0f; var dinfo = new DamageInfo(); dinfo.Beater = this; dinfo.Beater_pd = _pd; dinfo.BaseDmg = addAtk + (_pd.BaseDmg > 0 ? _pd.BaseDmg : m_Stat.Get_Stat(eStat.BaseDmg)); dinfo.Damage = dinfo.BaseDmg * _attackrate; dinfo.PiercingDmg = dinfo.BaseDmg * (m_Stat.Get_Stat(eStat.PIERCING_Multiplier) + dinfo.Get_AddValue(eAddExtraType.Add_Piercing_Multiplier_bySpiriBless)); dinfo.TextColor = HUDBase.Get_TextColor(m_AttackType); if (dic_ccData[eCC.PiercingBuff].CCTime > 0) dinfo.PiercingDmg += dinfo.BaseDmg * m_Stat.Get_Stat(eStat.PiercingBuff_byAttack); dinfo.Cal_Cri(m_AttackType, m_Stat, forceCri); // 크리티컬 판정 return dinfo; } public virtual void Get_Damage(DamageInfo _dinfo) { if (IsDead() || m_bImmortal) return; if (_dinfo.Damage < 1) _dinfo.Damage = 1d; //if (Get_HP() >= Get_MaxHP() && Get_HP() <= _dinfo.Damage) // 한 방에 사망 // Kill_OnePunch(_dinfo); //VeryStrongDamage(_dinfo.Damage); //if (!IsRole(eRole.PC)) _dinfo.Damage = 2500; // 테스트 : 데미지 고정 if (!DSUtil.CheckNull(_dinfo.Beater)) { var beaterStat = _dinfo.Beater.Get_StatInfo(); double reduceDef = 0d, atk_fixed = 0d; // 방어력 계산 double def = 0d; switch (_dinfo.Beater.m_AttackType) { case eAttackType.Physics: def = m_Stat.Get_Stat(eStat.FinalDef); def -= beaterStat.Get_Stat(eStat.DEF_Ignore); def -= def * (beaterStat.Get_Stat(eStat.DEF_Ignore_Rate) * beaterStat.Get_MainStatValue()); var hpper = (float)(m_Stat.Get_Stat(eStat.HP) / m_Stat.Get_Stat(eStat.MaxHP)); if (hpper <= m_Stat.Get_Stat(eStat.HeroBuffHP)) def += m_Stat.Get_Stat(eStat.DEF) * m_Stat.Get_Stat(eStat.HeroBuff_DEF); Check_CCAddRate(eCC.DEF_Down, _dinfo.Beater); ++dic_ccAddRate[eCC.DEF_Down][_dinfo.Beater]; if (dic_ccAddRate[eCC.DEF_Down][_dinfo.Beater] > beaterStat.Get_Stat(eStat.DEF_Down_Limit)) dic_ccAddRate[eCC.DEF_Down][_dinfo.Beater] = beaterStat.Get_Stat(eStat.DEF_Down_Limit); reduceDef = beaterStat.Get_Stat(eStat.DEF_Down) * dic_ccAddRate[eCC.DEF_Down][_dinfo.Beater]; // 방어력 감소 체크 def -= reduceDef; if (beaterStat.Get_Stat(eStat.DEF_Down_Step3) >= 1) atk_fixed = reduceDef; if (dic_ccData[eCC.DEF_Down].CCTime > 0f) def -= dic_ccData[eCC.DEF_Down].CCDmg; break; case eAttackType.Magic: def = m_Stat.Get_Stat(eStat.FinalMDef); Check_CCAddRate(eCC.M_DEF_Down, _dinfo.Beater); ++dic_ccAddRate[eCC.M_DEF_Down][_dinfo.Beater]; if (dic_ccAddRate[eCC.M_DEF_Down][_dinfo.Beater] > beaterStat.Get_Stat(eStat.M_DEF_Down_Limit)) dic_ccAddRate[eCC.M_DEF_Down][_dinfo.Beater] = beaterStat.Get_Stat(eStat.M_DEF_Down_Limit); reduceDef = beaterStat.Get_Stat(eStat.M_DEF_Down) * dic_ccAddRate[eCC.M_DEF_Down][_dinfo.Beater]; // 마법저항력 감소 체크 def -= reduceDef; if (beaterStat.Get_Stat(eStat.M_DEF_Down_Step3) >= 1) atk_fixed = reduceDef; if (dic_ccData[eCC.M_DEF_Down].CCTime > 0f) def -= dic_ccData[eCC.M_DEF_Down].CCDmg; break; } if (def > 0f) { double defmul = table_GlobalValue.Ins.Get_Int("Defense_Coefficient"); // 기존 def_cal 계산식에서 / 를 *로 변경 var def_cal = def * defmul * (0.0001 + def * defmul * 0.0001) * 1000000; var dmg = Math.Round(def_cal * _dinfo.Damage * 0.000001); // /1000000을 *0.000001로 변경 _dinfo.Damage -= dmg; } else { var cal1 = 2d - Math.Pow(0.94d, def * 0.01); var cal2 = cal1 * 1000000; var cal3 = cal2 * _dinfo.Damage; _dinfo.Damage = Math.Round(cal3 * 0.000001); // /1000000을 *0.000001로 변경 } // 몬스터 데미지 추가 if (IsRole(eRole.Mob)) { Check_CCAddRate(eCC.MobDamage, _dinfo.Beater); ++dic_ccAddRate[eCC.MobDamage][_dinfo.Beater]; if (dic_ccAddRate[eCC.MobDamage][_dinfo.Beater] > beaterStat.Get_Stat(eStat.MobDamage_Limit)) dic_ccAddRate[eCC.MobDamage][_dinfo.Beater] = beaterStat.Get_Stat(eStat.MobDamage_Limit); _dinfo.Damage += _dinfo.Damage * beaterStat.Get_Stat(eStat.Monster_DMG_Multiplier) * dic_ccAddRate[eCC.MobDamage][_dinfo.Beater]; _dinfo.PiercingDmg += beaterStat.Get_Stat(eStat.BaseDmg) * beaterStat.Get_Stat(eStat.MOB_Piercing_Multiplier); } else if (IsRole(eRole.Boss)) { Check_CCAddRate(eCC.BossDamage, _dinfo.Beater); ++dic_ccAddRate[eCC.BossDamage][_dinfo.Beater]; if (dic_ccAddRate[eCC.BossDamage][_dinfo.Beater] > beaterStat.Get_Stat(eStat.BossDamage_Limit)) dic_ccAddRate[eCC.BossDamage][_dinfo.Beater] = beaterStat.Get_Stat(eStat.BossDamage_Limit); _dinfo.Damage += _dinfo.Damage * beaterStat.Get_Stat(eStat.BOSS_DMG_Multiplier) * dic_ccAddRate[eCC.BossDamage][_dinfo.Beater]; _dinfo.PiercingDmg += beaterStat.Get_Stat(eStat.BaseDmg) * beaterStat.Get_Stat(eStat.BOSS_Piercing_Multiplier); } // 고정 피해 계산 _dinfo.Damage += (int)_dinfo.Beater.m_Stat.Get_Stat(eStat.ATK_FIXED) + (int)atk_fixed - (int)m_Stat.Get_Stat(eStat.ATK_FIXED_DECREASE); if (_dinfo.Damage < 1d) _dinfo.Damage = 1d; } _dinfo.PiercingDmg -= _dinfo.PiercingDmg * m_Stat.Get_Stat(eStat.PIERCING_Block); _dinfo.Damage += _dinfo.PiercingDmg; // 관통 피해 추가 // 데미지 감소 적용 _dinfo.Damage -= _dinfo.Damage * m_Stat.Get_Stat(eStat.DMG_DECREASE); if (dic_ccData[eCC.ManaShield].CCTime > 0d) { // 마나 실드 var reduceDmg = Mathf.Max(1, (int)(_dinfo.Damage * dic_ccData[eCC.ManaShield].CCDmg)); _dinfo.Damage -= reduceDmg; var useMP = Mathf.Max(1, (int)(reduceDmg * dic_ccData[eCC.ManaShield].CCReduceTime)); Heal_MP(-useMP, true); if (m_Stat.Get_Stat(eStat.MP) <= 0) { dic_ccData[eCC.ManaShield].CCTime = 0d; dic_ccData[eCC.ManaShield].Off_Effect(); } } Cal_Damage(_dinfo); Check_CC_byAttack(_dinfo); #if UNITY_EDITOR if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name == "StatTest") { MainToStatTest.Ins.Set_Dmglabel(HUDBase.Get_TextColor(_dinfo.Beater.m_AttackType) + (_dinfo.Critical == eStat.CRI || _dinfo.Critical == eStat.M_CRI ? "" + _dinfo.Critical + " " : " ") + _dinfo.Damage); return; } #endif } public virtual void Cal_Damage(DamageInfo _dinfo) { if (IsDead()) return; m_Stat.Set_Stat(false, eStat.HP, _dinfo.Damage); _dinfo.act_returnLastDmg?.Invoke(_dinfo.Damage); _dinfo.act_CriAfterHit?.Invoke(_dinfo.Critical); Add_ReceiveDmg(_dinfo.Damage); _dinfo.Beater?.Add_MyRealDmg(_dinfo.Damage); BossRaidCard_HP(); var pd = _dinfo.Beater_pd; if (m_Stat.Get_Stat(eStat.HP) <= 0d) { Check_Drain_byKill(_dinfo); DeadStatus = _dinfo.IsDeadByThisDamage = true; Set_Die(); if (_dinfo.Beater.IsRole(eRole.BattleNPC)) ServerInfo.Ins.m_ServerData.Add_TitleCondition(72, 73); // 칭호 : 승차감 좋은 버스, 택시 if (!DSUtil.CheckNull(pd) && pd.IsSkill(eEffect.Skill_Ignited) && pd.CC_AddVal2 > 0) { // 버닝효과 체크, 버닝 효과 발동 var ccData = Get_CCData(eCC.Burn); if (ccData.CCTime > 0f) { var other = ActorInfo.Ins.Get_NearstAllyActor(IsEnemy(), Get_position(), 5f); if (!DSUtil.CheckNull(other)) { other.DotDamage(eCC.Burn, pd.shooter.Get_DamageInfo(pd), ccData.CCTime, pd.m_SkillListTableData.f_ExtraValue2 + pd.CC_AddVal1, pd.m_SkillListTableData.f_ExtraValue3); pd.m_ProjectileBase.Show_Effect(other, (float)ccData.CCTime, ccData); } } } } else { if (DSUtil.CheckNull(pd) || !DSUtil.CheckNull(pd) && !pd.IsSkill(eEffect.Skill_Ignited) && !pd.IsSkill(eEffect.Select_BodyonFire)) Play_Hit(); } #if UNITY_EDITOR if (SceneManager.GetActiveScene().name == "StatTest") return; #endif // UI 설정 m_HUDUI.Set_HPSlider(m_Stat.Get_Stat(eStat.HP), m_Stat.Get_Stat(eStat.MaxHP)); InGameInfo.Ins.Get_HUDDMGUI().Set(tf_HUD_Dmg, _dinfo.TextColor, _dinfo.Damage, _dinfo.Critical); //if (IsRole(eRole.Boss)) { GameUI.Ins.IngameUI.m_BossInfoUI.Set_HP(m_Stat.Get_Stat(eStat.HP), m_Stat.Get_Stat(eStat.MaxHP)); } // TODO 정인호 : 보스 hp ui } public void Add_MyRealDmg(double _dmg) { m_Damage += _dmg; } public double Get_RealDamage() { return m_Damage; } public virtual void Add_ReceiveDmg(double _dmg) { receiveaccumulateDmg += _dmg; } public double Get_ReceiveDmg() { return receiveaccumulateDmg; } protected virtual void Kill_OnePunch(DamageInfo dinfo) { } protected virtual void VeryStrongDamage(double dmg) { } public virtual void OnTrigger_Damage(Actor _actor) { } protected virtual void Set_Die() { Cancel_Freeze(0f); foreach (var key in dic_ccCoroutine.Keys.ToList()) dic_ccCoroutine[key] = null; Play_Die(); Set_Coroutine(After_Die, 3f); // TODO 정인호 : 애니메이터에서 애니메이션 길이값 가져오는 법이 있긴 한데 일관성이 없음 if (m_BoxCollider) m_BoxCollider.enabled = false; m_NavMeshAgent.enabled = false; m_IsLockTarget = false; Set_Outline(false); } protected virtual void After_Die() { #if UNITY_EDITOR if (SceneManager.GetActiveScene().name == "StatTest") { On_Regen(); transform.localPosition = Vector3.zero; CurAnim = eAnim.Die; Play_Idle(); MyValue.MyPC.Change_Target(false, this); return; } #endif m_animation.speed = 0f; switch (m_Role) { case eRole.Mob: case eRole.Boss: case eRole.OBJ: //MobInfo.Ins.Add_Dead(); Off(); break; case eRole.PC: //InGameInfo.Ins.Defeat_byMonster(); // 소환수 이동 var summ = ActorInfo.Ins.Get_Actor(eRole.Summon); if (!DSUtil.CheckNull(summ)) summ.On_Regen(); // 펫 부활 var pet = ActorInfo.Ins.Get_Actor(eRole.Pet); if (!DSUtil.CheckNull(pet)) pet.On_Regen(); // PC 부활 On_Regen(); break; } } protected void Reset_AttackCoolTime() { m_attackCoolTime = m_Stat.Get_Stat(eStat.AttackCoolTime); } protected virtual void Projectile_To_Target(string _proj) { Reset_AttackCoolTime(); ProjectileInfo.Ins.Shoot_Projectile(_proj, this, m_Target, 1f, Get_CenterPositionFoward() ); } protected virtual void Projectile_To_Target2(string _proj) { Reset_AttackCoolTime(); ProjectileInfo.Ins.Shoot_Projectile(_proj, this, m_Target, 1f, Get_CenterPositionFoward()); } protected virtual void Projectile_To_Target3(string _proj) { Reset_AttackCoolTime(); ProjectileInfo.Ins.Shoot_Projectile(_proj, this, m_Target, 1f, Get_CenterPositionFoward()); } protected virtual void Heal_To_Target() { } protected virtual void Set_Script() { } protected virtual void Create_LastEffect() { } public virtual void BossRaidCard_AddDmg(double _dmg) { } public virtual void BossRaidCard_HP() { } public virtual bool Use_Skill(SkillListTableData skilldata, bool autoskill, int index) { if (skilldata.e_SkillType == eSkillType.Passive) return false; if (CurAnim >= eAnim.Skill) { if (!autoskill) MessageInfo.Ins.Add_Log(109); return false; } // 내 직업이 사용할 수 있는 스킬인가? if (skilldata.n_SkillClassID > 0 && skilldata.n_SkillClassID != m_ID) return false; m_Magic = dic_MagicData[index]; if (IsDead() || IsCC() || CurAnim >= eAnim.Skill) { Del_Magic(); return false; } if (skilldata.e_SkillTarget == eSkillTarget.Enemy) { if (DSUtil.CheckNull(m_Target)) Set_Target(true); if (DSUtil.CheckNull(m_Target)) { if (IsRole(eRole.PC)) ToastUI.Ins.Set(105); Del_Magic(); return false; } else if (Vector3.Distance(m_Target.Get_position(), Get_position()) > skilldata.f_SkillRange) { // 마법 사용 사정거리보다 멀리 있다. 마법 쏘러 가자. return false; } } if (IsRole(eRole.PC)) { var needMP = skilldata.n_MP - (skilldata.n_MP * m_Stat.Get_Stat(eStat.SKILL_COST)); if (needMP > m_Stat.Get_Stat(eStat.MP)) { if (!autoskill) { ToastUI.Ins.Set(106); MessageInfo.Ins.Add_Log(106); } Del_Magic(); return false; } } if (!Check_MagicCoolTime(index)) return false; list_SkillData[index].m_SkillListTableData = m_Magic.m_SkillTableData; list_SkillData[index].target = m_Target; m_SkillData = list_SkillData[index]; m_Stat.Set_Stat(false, eStat.MP, skilldata.n_MP); Set_MagicCoolTime(skilldata.Get_CoolTime(m_Stat.Get_Stat(eStat.COOLTIME_Multiplier)), index); return Play_Skill(skilldata.s_Animation); } public virtual void Shoot_Skill() { if (IsDead() || DSUtil.CheckNull(m_Magic)) return; InGameInfo.Ins.Shoot_Effect(m_SkillData); //SoundInfo.Ins.Play_OneShot(eSound.s009_CastSpell); //if (IsRole(eRole.PC)) //NewGameUI.Ins.m_GuideQuestUI.Add_GuideQuest(ePurpose.ShootMagic); Del_Magic(); } public void Set_Magic(SkillListTableData skill, Actor target) { m_Magic = new UseMagicInfo { m_SkillTableData = skill }; m_SkillData = new ProjectileData { shooter = this, target = target, m_SkillListTableData = skill }; } public void Del_Magic() { if (!DSUtil.CheckNull(co_casting)) { StopCoroutine(co_casting); co_casting = null; } m_Magic = null; } public virtual void Set_MagicCoolTime(float _time, int _index) { } public virtual void Set_SkillCoolTime(bool add, int skillid, float rate) { } protected virtual bool Check_MagicCoolTime(int _index) { return false; } public virtual void Heal(float _rate, bool showhud = true) { if (IsDead()) return; var heal_hp = m_Stat.Get_Stat(eStat.MaxHP) * _rate; m_Stat.Set_Stat(true, eStat.HP, heal_hp); if (showhud) { InGameInfo.Ins.Get_HUDDMGUI().Set(tf_HUD_Dmg, "", heal_hp, eStat.None); if (m_HUDUI != null) m_HUDUI.Set_HPSlider(m_Stat.Get_Stat(eStat.HP), m_Stat.Get_Stat(eStat.MaxHP)); } } public virtual void Heal(double _hp, bool showhud = true) { if (IsDead()) return; m_Stat.Set_Stat(true, eStat.HP, _hp); #if UNITY_EDITOR if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name == "StatTest") { MainToStatTest.Ins.Set_Dmglabel($"HP : {_hp}"); return; } #endif if (!DSUtil.CheckNull(m_HUDUI)) m_HUDUI.Set_HPSlider(m_Stat.Get_Stat(eStat.HP), m_Stat.Get_Stat(eStat.MaxHP)); if (showhud) InGameInfo.Ins.Get_HUDDMGUI().Set(tf_HUD_Dmg, "", _hp, eStat.None); } public virtual void Heal_MP(double _mp, bool showhud = true) { if (IsDead()) return; m_Stat.Set_Stat(true, eStat.MP, _mp); #if UNITY_EDITOR if (SceneManager.GetActiveScene().name == "StatTest") { MainToStatTest.Ins.Set_Dmglabel($"MP : {_mp}"); return; } #endif if (showhud) InGameInfo.Ins.Get_HUDDMGUI().Set(tf_HUD_Dmg, "", _mp, eStat.None); } #region 스킬 동작 IEnumerator Co_JumpAttack(float heightPos_y, float duration) { var startPos = Get_position(); // 현재 위치 var targetPos = Get_TeleportPostion(); var elapsed = 0f; while (elapsed < duration) { elapsed += Time.deltaTime; float t = elapsed / duration; // 포물선의 중간 높이를 만들기 위해 선형 보간 사용 Vector3 currentPos = Vector3.Lerp(startPos, targetPos, t); // 높이를 포물선 형태로 변경 currentPos.y += Mathf.Sin(t * Mathf.PI) * (heightPos_y - startPos.y); transform.position = currentPos; // 캐릭터 위치 업데이트 yield return null; } transform.position = targetPos; // 최종 위치 설정 } public void Set_Invisible(float invisibleTime, Action actVisible) { StartCoroutine(Co_Invisible(invisibleTime, actVisible)); } IEnumerator Co_Invisible(float invisibleTime, Action actVisible) { m_animation.speed = 0f; m_bImmortal = true; for (int i = 0; i < arr_Renderer.Length; i++) arr_Renderer[i].enabled = false; Weapon_OnOff(false); OptionInfo.Ins.PCMove = false; yield return new WaitForSeconds(invisibleTime); m_animation.speed = 1f; m_bImmortal = false; for (int i = 0; i < arr_Renderer.Length; i++) arr_Renderer[i].enabled = true; Weapon_OnOff(true); OptionInfo.Ins.PCMove = true; actVisible?.Invoke(); } protected virtual void Weapon_OnOff(bool active) { } #endregion public int Get_ID() { return m_ID; } public virtual int Get_Group() { return 0; } public virtual NavMeshAgent Get_Agent() { return m_NavMeshAgent; } public Vector3 Get_position() { return transform.position; } public Vector3 Get_Center_position() { return new Vector3(transform.position.x, transform.position.y + ObjSize.y * 0.5f, transform.position.z); } public Vector3 Get_Top_postion() { return tf_HUD_Dmg.position; } public Vector3 Get_CenterPositionFoward(float dist = 1f) { return Get_Center_position() + transform.forward * dist; } public Vector3 Get_PositionFoward(float dist = 1f) { return Get_position() + transform.forward * dist; } public Vector3 Get_PositionBack(float dist = 1f) { return Get_position() + -transform.forward * dist; } public Vector3 Get_TeleportPostion(float dist = 1f) { var startPos = Get_position(); // 현재 위치 Vector3 direction = (m_Target.Get_position() - Get_position()).normalized; // 목표와 현재 위치의 방향 벡터를 구함 return m_Target.Get_position() - direction * 1f; // 목표 위치에서 -1f 앞 지점 계산 } public float Get_ScaleSizeDist() { return transform.localScale.x > 2f ? ObjSize.z * 0.5f : 0f; } public ActorStatInfo Get_StatInfo() { return m_Stat; } public double Get_HP() { return m_Stat.Get_Stat(eStat.HP); } public double Get_MaxHP() { return m_Stat.Get_Stat(eStat.MaxHP); } public double Get_MaxMP() { return m_Stat.Get_Stat(eStat.MaxMP); } public Actor Get_Target() { return m_Target; } public virtual void Del_Target(bool forcedel = false) { if (m_Target) { if (!forcedel && m_Target.m_IsLockTarget && !m_Target.IsDead()) return; if (IsRole(eRole.PC) && !IsEnemy()) m_Target.Set_Outline(false); } m_Target = null; } public bool IsDead() { return DeadStatus || !gameObject.activeInHierarchy; } public bool IsOnlyDead() { return DeadStatus; } public bool IsRole(eRole _role) { return m_Role == _role; } public bool IsEnemy() { return m_Enemy; } public virtual bool IsBerserkPet() { return false; } public virtual bool Get_IsMainPC() { return false; } public bool Get_SelectSkill(eEffect _effect) { if (IsRole(eRole.PC) && !IsEnemy()) return InGameInfo.Ins.Get_SelectSkillData(_effect); return false; } public ServerData Get_ServerData() { return m_ServerData; } public virtual void Change_Target(bool _ispc, Actor target, bool _ChangeTargetByHit = false) { if (!DSUtil.CheckNull(target) && !target.IsDead()) { if (_ispc) { if (!DSUtil.CheckNull(MyValue.MyPC.m_Target)) MyValue.MyPC.m_Target.Set_Outline(false); } if (_ChangeTargetByHit) { if (DSUtil.CheckNull(m_Target) || m_Target.IsDead()) { m_Target = target; FindOtherTargetTime = 7.5f; } } else { m_Target = target; FindOtherTargetTime = 7.5f; } if (_ispc) { m_Target.Set_Outline(true); // 퀘스트 몹은 선택 사항이므로 마녀가 터치로만 타겟을 잡을 수가 있다. 퀘스트몹을 선택했다는 것은 퀘스트를 하겠다는 뜻이므로 모든 펫이 같이 때린다. // 강화석도 같이 캐자 if (m_Target.IsRole(eRole.QuestMob) || (m_Target.IsRole(eRole.OBJ) && m_Target.m_SubRole == eSubRol.Ore)) ActorInfo.Ins.Get_Actors(eRole.Pet, 0).ForEach(f => f.Change_Target(false, m_Target)); } } } public void Resurrection(float _hprate) { Heal(_hprate); Play_Idle(); if (m_BoxCollider) m_BoxCollider.enabled = true; m_NavMeshAgent.enabled = true; } protected virtual void On_NavMeshAgent() { if (!IsCC()) { // 모든 상태이상이 해제 되었다. m_NavMeshAgent.updatePosition = true; if (m_NavMeshAgent.isOnNavMesh) m_NavMeshAgent.isStopped = false; m_animation.speed = OriginalAnimSpeed; } } #region 적 처치 시 회복 void Check_Drain_byKill(DamageInfo _dinfo) { if (!DSUtil.CheckNull(_dinfo) && !DSUtil.CheckNull(_dinfo.Beater) && _dinfo.Beater.IsEnemy() != IsEnemy()) { var statinfo = _dinfo.Beater.Get_StatInfo(); if (!DSUtil.CheckNull(statinfo)) { if (DSUtil.RandomTrue(statinfo.Get_Stat(eStat.KillToHP_Rate))) { // 회복 _dinfo.Beater.Heal(statinfo.Get_Stat(eStat.KillToHP)); _dinfo.Beater.Heal_MP(statinfo.Get_Stat(eStat.KillToMP)); } if (DSUtil.RandomTrue(statinfo.Get_Stat(eStat.KillToMP_Rate))) { // MP 회복 _dinfo.Beater.Heal(statinfo.Get_Stat(eStat.KillToHP)); _dinfo.Beater.Heal_MP(statinfo.Get_Stat(eStat.KillToMP)); } } } } #endregion public bool IsCC() { foreach (var item in dic_ccData) { if (item.Key >= eCC.Freeze && item.Value.CCTime > 0) return true; } return false; } protected virtual void Check_CC_byAttack(DamageInfo _dinfo) { if (dic_ccData[eCC.Freeze].CCTime > 0f) Off_Freeze(); float knockbackTime = 0f; if ((IsRole(eRole.Mob) || IsRole(eRole.Boss)) && !IsCC()) knockbackTime = table_GlobalValue.Ins.Get_Float("f_KnockbackTime"); var beaterActor = _dinfo.Beater; if (!DSUtil.CheckNull(_dinfo) && !DSUtil.CheckNull(beaterActor)) { if (!DSUtil.CheckNull(_dinfo.Beater_pd)) { // 서리 상태인 적을 냉기 폭격으로 때렸을 때 얼림 var pd = _dinfo.Beater_pd; if (!DSUtil.CheckNull(pd.m_SkillListTableData) && pd.m_SkillListTableData.e_Skill == eEffect.Skill_IceArrows && pd.CC_AddVal2 > 0f && IsSkillExtraStatus(eSkillExtraType.Frost)) Freeze(pd.CC_AddVal2, _dinfo.act_AfterFreezing); } var statinfo = beaterActor.Get_StatInfo(); if (!DSUtil.CheckNull(statinfo)) { var cc = eCC.Blooding; if (DSUtil.RandomTrue(statinfo.Get_Stat(eStat.Blooding))) { // 출혈 체크 DotDamage(eCC.Blooding, _dinfo.Copy(), statinfo.Get_Stat(eStat.BloodingTime), statinfo.Get_Stat(eStat.BloodingDelay), statinfo.Get_Stat(eStat.BloodingDmg)); } cc = eCC.Stun; if (dic_ccData[cc].CCTime <= 0f) { // 무한 스턴 방지 var addrate = Get_CCAddRate(cc, beaterActor); Check_CCAddRate(cc, beaterActor); dic_ccAddRate[cc][beaterActor] += statinfo.Get_Stat(eStat.StunAdd); if (DSUtil.RandomTrue(statinfo.Get_Stat(eStat.Stun) + addrate)) { // 스턴 체크 dic_ccAddRate[cc][beaterActor] = 0; dic_ccData[cc].CCTime = statinfo.Get_Stat(eStat.StunTime); _dinfo.Damage = dic_ccData[cc].CCDmg = _dinfo.Damage * statinfo.Get_Stat(eStat.StunDmg); Cal_Damage(_dinfo); Stun(dic_ccData[cc].CCTime); } } knockbackTime += (float)statinfo.Get_Stat(eStat.AttackKnockBack); if (DSUtil.RandomTrue(statinfo.Get_Stat(eStat.AttackSpeedRate_byAttack))) beaterActor.Buff_or_Debuff(eCC.ATKSPD_Up, beaterActor.Get_StatInfo().Get_Stat(eStat.AttackSpeedTime_byAttack), beaterActor.Get_StatInfo().Get_Stat(eStat.AttackSpeedBuff_byAttack)); if (DSUtil.RandomTrue(statinfo.Get_Stat(eStat.MoveSpeedRate_byAttack))) beaterActor.Buff_or_Debuff(eCC.MOVSPD_Up, beaterActor.Get_StatInfo().Get_Stat(eStat.MoveSpeedTime_byAttack), beaterActor.Get_StatInfo().Get_Stat(eStat.MoveSpeedBuff_byAttack)); if (DSUtil.RandomTrue(statinfo.Get_Stat(eStat.PiercingRate_byAttack))) beaterActor.Buff_or_Debuff(eCC.PiercingBuff, beaterActor.Get_StatInfo().Get_Stat(eStat.PiercingTime_byAttack), beaterActor.Get_StatInfo().Get_Stat(eStat.PiercingRate_byAttack)); var STCdata = _dinfo.Beater_pd.m_skillTypeConfigTable; if (!DSUtil.CheckNull(STCdata) && STCdata.e_SkillExtraTiming == eSkillExtraTiming.Hit) Check_Extra(_dinfo); Check_EnchantOption(_dinfo); if (knockbackTime > 0f) KnockBack(knockbackTime); } } } public void Check_Extra(DamageInfo _dinfo) { var pd = _dinfo.Beater_pd; if (pd.e_SkillExtraType == eSkillExtraType.None) return; float val1 = 0f, val2 = 0f, val3 = 0f, val4 = 0f; bool bSKill, bOption; SkillListTableData skillData = _dinfo.Beater_pd.m_SkillListTableData; bSKill = !DSUtil.CheckNull(skillData); if (bSKill) { val1 = skillData.f_ExtraValue1; val2 = skillData.f_ExtraValue2; val3 = skillData.f_ExtraValue3; val4 = skillData.f_ExtraValue4; } else { OptionConfigTableData optionData = _dinfo.Beater_pd.m_OptionConfigTableData; bOption = !DSUtil.CheckNull(optionData); if (bOption) { val1 = optionData.f_ExtraValue1; val2 = optionData.f_ExtraValue2; val3 = optionData.f_ExtraValue3; val4 = optionData.f_ExtraValue4; } } if (!DSUtil.RandomTrue(val4)) return; // 확률 체크 SkillTypeConfigTableData skillExtraData = _dinfo.Beater_pd.m_skillTypeConfigTable; ActorStatInfo statinfo = _dinfo.Beater.Get_StatInfo(); CCData ccdata = null; float LifeTime = val1 + pd.CC_AddTime; switch (skillExtraData.e_SkillExtraType) { // 적에게 case eSkillExtraType.Frost: case eSkillExtraType.Slow: Buff_or_Debuff(eCC.ATKSPD_Down, LifeTime, val2 + pd.CC_AddVal1); Buff_or_Debuff(eCC.MOVSPD_Down, LifeTime, val3 + pd.CC_AddVal2); if (_dinfo.bExtraDmg) Cal_Damage(_dinfo); // 추가 데미지 break; case eSkillExtraType.Freezing: Freeze(LifeTime, _dinfo.act_AfterFreezing); if (_dinfo.bExtraDmg) Cal_Damage(_dinfo); // 추가 데미지 break; case eSkillExtraType.Burn: DotDamage(eCC.Burn, _dinfo.Copy(), LifeTime, val2 + pd.CC_AddVal1, val3); break; case eSkillExtraType.Blood: DotDamage(eCC.Blooding, _dinfo.Copy(), LifeTime, val2, val3); break; case eSkillExtraType.Poison: DotDamage(eCC.Poison, _dinfo.Copy(), LifeTime, val2, val3); break; case eSkillExtraType.Stun: Stun(LifeTime); if (_dinfo.bExtraDmg) { _dinfo.Damage *= val2 + pd.CC_AddDmg; Cal_Damage(_dinfo); // 스턴 추가 데미지 } break; case eSkillExtraType.DefenceDecrease: Buff_or_Debuff(eCC.DEF_Down, LifeTime, val2); Buff_or_Debuff(eCC.M_DEF_Down, LifeTime, val3); if (_dinfo.bExtraDmg) Cal_Damage(_dinfo); // 추가 데미지 break; // 시전자에게 case eSkillExtraType.StatUp: { var rate = val3; var type = (int)val2; var lst = MyValue.dic_StatUp[type]; for (int i = 0; i < lst.Count; i++) Stat_BufforDebuff(statinfo, lst[i], LifeTime, rate, type, i == lst.Count - 1); } break; case eSkillExtraType.ManaShield: LifeTime += LifeTime * pd.Get_SkillDamagePercent(); Buff_or_Debuff(eCC.ManaShield, LifeTime, val3, 0, val2); ccdata = dic_ccData[eCC.ManaShield]; break; case eSkillExtraType.SwordShield: break; case eSkillExtraType.SpeedUp: Buff_or_Debuff(eCC.ATKSPD_Up, LifeTime, val2); Buff_or_Debuff(eCC.MOVSPD_Up, LifeTime, val3); break; case eSkillExtraType.Aggro: break; case eSkillExtraType.VampirHeal: _dinfo.Beater.Heal(val2); _dinfo.Beater.Heal_MP(val3); break; case eSkillExtraType.Cure: _dinfo.Beater.DotHeal(LifeTime, val2, _dinfo.Beater.Get_MaxHP() * val3, _dinfo.Beater.Get_MaxMP() * val3); break; case eSkillExtraType.Knockback: KnockBack(val1); break; case eSkillExtraType.Airborne: KnockedAirborne(val1); break; case eSkillExtraType.Curse: // 단순 상태 확인 및 이펙트 표시 용도 break; } if (!dic_skillextra.ContainsKey(skillExtraData.e_SkillExtraType)) dic_skillextra.Add(skillExtraData.e_SkillExtraType, true); dic_skillextra[skillExtraData.e_SkillExtraType] = true; Set_Coroutine(() => { if (dic_skillextra.ContainsKey(skillExtraData.e_SkillExtraType)) dic_skillextra[skillExtraData.e_SkillExtraType] = false; }, LifeTime); pd.m_ProjectileBase.Show_Effect(this, LifeTime, ccdata); } public void Check_EnchantOption(DamageInfo _dinfo, bool whenhit = true) { if (!DSUtil.CheckNull(_dinfo.Beater)) { var sdata = _dinfo.Beater.Get_ServerData(); if (!DSUtil.CheckNull(sdata)) for (int i = 0; i < sdata.Slot.Count; i++) { for (int j = 0; j < sdata.Slot[i].Enchant.Count; j++) { var optionid = sdata.Slot[i].Enchant[j].ID; if (optionid > 0) { var statinfo = _dinfo.Beater.Get_StatInfo(); var Tdata = table_optionconfig.Ins.Get_Data(optionid); var dcopy = _dinfo.Copy(); dcopy.Beater_pd.m_OptionConfigTableData = Tdata; if (DSUtil.CheckNull(dcopy.Beater_pd)) dcopy.Beater_pd = new ProjectileData(); var val = Tdata.Get_Value(sdata.Slot[i].Enchant[j].Lv); switch (Tdata.e_OptionType) { case eStat.STR_EXTRA_STUN: if (whenhit) { dcopy.Set_Extra(eSkillExtraType.Stun); dcopy.bExtraDmg = true; dcopy.Damage = statinfo.Get_Stat(eStat.STR) * val; Check_Extra(dcopy); } break; case eStat.DEX_EXTRA_BLEED: if (whenhit) { dcopy.Set_Extra(eSkillExtraType.Blood); dcopy.Beater_pd.BaseDmg = statinfo.Get_Stat(eStat.DEX) * val; Check_Extra(dcopy); } break; case eStat.INT_EXTRA_SLOW: if (whenhit) { dcopy.Set_Extra(eSkillExtraType.Slow); dcopy.bExtraDmg = true; dcopy.Damage = statinfo.Get_Stat(eStat.INT) * val; Check_Extra(dcopy); } break; case eStat.LUK_EXTRA_CURSE: if (whenhit && DSUtil.RandomTrue(Tdata.f_ExtraValue4)) { dcopy.Damage = statinfo.Get_Stat(eStat.LUK) * val; Cal_Damage(dcopy); } break; case eStat.STR_EXTRA_SPLASH: if (whenhit && DSUtil.RandomTrue(Tdata.f_ExtraValue4)) { dcopy.Damage = statinfo.Get_Stat(eStat.STR) * val; var allies = ActorInfo.Ins.Get_AlliesActors(IsEnemy(), Get_position(), Tdata.f_ExtraValue1); for (int k = 0; k < allies.Count; k++) { allies[k].Cal_Damage(dcopy); InGameInfo.Ins.Show_Effect("Effect_STR_EXTRA_SPLASH", allies[k]); } } break; case eStat.DEX_EXTRA_DART: if (!whenhit && DSUtil.RandomTrue(Tdata.f_ExtraValue4)) { ProjectileData pd = new ProjectileData(); pd.CheckOptionWhenStart = false; pd.shooter = _dinfo.Beater; pd.eStartPos = eProjectileStartPos.Custom; pd.v3_StartPos = _dinfo.Beater.Get_Center_position(); pd.m_OptionConfigTableData = Tdata; pd.BaseDmg = statinfo.Get_Stat(eStat.DEX) * val; ProjectileInfo.Ins.Shoot_Projectile("Projectile_Suriken", pd); } break; case eStat.INT_EXTRA_FREEZING: if (!whenhit && DSUtil.RandomTrue(Tdata.f_ExtraValue4)) { ProjectileData pd = new ProjectileData(); pd.CheckOptionWhenStart = false; pd.shooter = _dinfo.Beater; pd.eStartPos = eProjectileStartPos.Custom; pd.v3_StartPos = _dinfo.Beater.Get_Center_position(); pd.e_SkillExtraType = eSkillExtraType.Freezing; pd.m_OptionConfigTableData = Tdata; pd.BaseDmg = statinfo.Get_Stat(eStat.INT) * val; ProjectileInfo.Ins.Shoot_Projectile("Projectile_INT_EXTRA_FREEZING", pd); } break; case eStat.LUK_EXTRA_CRITICAL: if (!whenhit) { _dinfo.act_CriAfterHit = cri => { if (cri == eStat.CRI || cri == eStat.M_CRI) { dcopy.Damage = statinfo.Get_Stat(eStat.LUK) * val; dcopy.Critical = eStat.None; Cal_Damage(dcopy); } }; } break; } } } } } } public void Set_DicCCData(eCC cc, double time, double dmg, bool isUpdate = true) { dic_ccData[cc].TimeUpdate = isUpdate; dic_ccData[cc].CCTime = time; dic_ccData[cc].CCDmg = dmg; } #region 버프 or 디버프 : 공속, 이속, 관통력, 방마저, 스탯 /// /// stat = 힘, 민, 지, 행 /// public void Stat_BufforDebuff(ActorStatInfo statinfo, eStat stat, float LifeTime, float rate, int type = 0, bool resetStat = false) { if (stat == eStat.STR || stat == eStat.DEX || stat == eStat.INT || stat == eStat.LUK) { statinfo.Set_Buff(MyValue.dic_StatUp_from_Stat[stat], rate); Buff_or_Debuff(MyValue.dic_StatUpCC_from_Stat[stat], LifeTime, rate, type); if (resetStat) statinfo.Reset(true); } } public void Buff_or_Debuff(eCC cc, double lifeTime, double val, int ival = 0, float fval = 0f) { dic_ccData[cc].TimeUpdate = true; dic_ccData[cc].CCTime = lifeTime; dic_ccData[cc].CCDmg = val; dic_ccData[cc].CCVal = ival; dic_ccData[cc].CCReduceTime = fval; } public CCData Get_CCData(eCC cc) { return dic_ccData[cc]; } public bool IsSkillExtraStatus(eSkillExtraType skillExtraType) { return dic_skillextra.ContainsKey(skillExtraType) && dic_skillextra[skillExtraType]; } protected void Off_StatUpBuff(eStat stat) { Get_StatInfo().Set_Buff(MyValue.dic_StatUp_from_Stat[stat], 0d); Get_StatInfo().Reset(true); } #endregion #region 상태이상 : 도트 데미지 (출혈, 독) Dictionary dic_ccCoroutine = new Dictionary(); public void DotDamage(eCC cc, DamageInfo dinfocopy, double lifetime, double gaptime, double dmg) { if (!dic_ccCoroutine.ContainsKey(cc)) dic_ccCoroutine.Add(cc, null); dic_ccData[cc].CCTime = lifetime; dic_ccData[cc].CCDelay = gaptime; dic_ccData[cc].CCDmg = dmg; if (!DSUtil.CheckNull(dic_ccCoroutine[cc])) StopCoroutine(dic_ccCoroutine[cc]); dic_ccCoroutine[cc] = StartCoroutine(Co_DotDamage(cc, dinfocopy)); } IEnumerator Co_DotDamage(eCC cc, DamageInfo dinfocopy) { var ccData = dic_ccData[cc]; var gapTime = (float)ccData.CCDelay; while (ccData.CCTime > 0) { var dinfo = dinfocopy.Beater.Get_DamageInfo(dinfocopy.Beater_pd, ccData.CCDmg); dinfo.TextColor = $"{cc} "; Cal_Damage(dinfo); yield return new WaitForSeconds(gapTime); ccData.CCTime -= gapTime; } dic_ccCoroutine[cc] = null; } #endregion #region 상태이상 : 도트 힐 Coroutine co_dotheal; public void DotHeal(double lifetime, float gaptime, double healhp, double healmp) { if (healhp < 1) healhp = 1; if (healmp < 1) healmp = 1; if (!DSUtil.CheckNull(co_dotheal)) StopCoroutine(co_dotheal); co_dotheal = StartCoroutine(Co_DotHeal(lifetime, gaptime, healhp, healmp)); } IEnumerator Co_DotHeal(double lifetime, float gaptime, double healhp, double healmp) { while (lifetime > 0) { yield return new WaitForSeconds(gaptime); Heal(healhp); Heal_MP(healmp); lifetime -= gaptime; } co_dotheal = null; } #endregion #region 상태이상 : 프리즈 Action act_AfterFreezing; public virtual void Freeze(float _freezeTime, Action act = null) { if (DSUtil.CheckNull(m_NavMeshAgent) || DSUtil.CheckNull(m_animation)) return; if (DSUtil.CheckNull(act_AfterFreezing)) act_AfterFreezing = act; dic_ccData[eCC.Freeze].CCTime = 10f; if (!IsDead()) { OriginalAnimSpeed = m_animation.speed; m_animation.speed = 0f; } StopMove_Imm(true); //Remove_Freeze(); //for (int j = 0; j < arr_Renderer.Length; j++) //{ // var materials = arr_Renderer[j].sharedMaterials.ToList(); // materials.Add(ProjectileInfo.Ins.arr_materials[0]); // arr_Renderer[j].materials = materials.ToArray(); //} _freezeTime -= (float)dic_ccData[eCC.Freeze].CCReduceTime; if (_freezeTime < 0.1f) _freezeTime = 0.1f; dic_ccData[eCC.Freeze].CCReduceTime += 0.05f; if (IsRole(eRole.Boss) || transform.localScale.x > 2f) Cancel_Freeze(_freezeTime * 0.4f); else if (IsRole(eRole.PC)) Cancel_Freeze(_freezeTime * 0.5f); else Cancel_Freeze(_freezeTime); } void Remove_Freeze() { for (int j = 0; j < arr_Renderer.Length; j++) { var materials = arr_Renderer[j].sharedMaterials.ToList(); materials.Remove(ProjectileInfo.Ins.arr_materials[0]); arr_Renderer[j].materials = materials.ToArray(); } } void Off_Freeze() { Remove_Freeze(); dic_ccData[eCC.Freeze].CCTime = 0f; InGameInfo.Ins.Show_Effect("Effect_Hit_IceBolt", transform.position); act_AfterFreezing?.Invoke(this); } void Cancel_Freeze(float _offTime) { if (dic_ccData[eCC.Freeze].CCTime > 0f) { if (IsInvoking(nameof(Off_Freeze))) CancelInvoke(nameof(Off_Freeze)); Invoke(nameof(Off_Freeze), _offTime); } dic_ccData[eCC.Freeze].CCReduceTime = 0; On_NavMeshAgent(); } #endregion #region 상태이상 : 넉백 float StunAfterKnockBackTime = 0f; public virtual void KnockBack(double _time, float speed = 4f) { if (IsRole(eRole.OBJ) || IsRole(eRole.Boss) || DSUtil.CheckNull(m_NavMeshAgent) || IsCC()) return; if (dic_ccData[eCC.KnockBack].CCTime < _time) StartCoroutine(Co_KnockBack(_time, speed)); } IEnumerator Co_KnockBack(double _time, float speed) { dic_ccData[eCC.KnockBack].CCTime = _time; //if (IsRole(eRole.Boss)) _time *= 0.7f; dic_ccData[eCC.KnockBack].CCTime -= dic_ccData[eCC.KnockBack].CCReduceTime; if (dic_ccData[eCC.KnockBack].CCTime < 0.1f) dic_ccData[eCC.KnockBack].CCTime = 0.1f; dic_ccData[eCC.KnockBack].CCReduceTime += 0.05f; while (dic_ccData[eCC.KnockBack].CCTime > 0f) { dic_ccData[eCC.KnockBack].CCTime -= Time.deltaTime; transform.Translate(speed * Time.deltaTime * Vector3.back); Set_Warp(transform.position); yield return null; } dic_ccData[eCC.KnockBack].CCTime = 0f; OriginalAnimSpeed = 1f; On_NavMeshAgent(); if (StunAfterKnockBackTime > 0) { Stun(StunAfterKnockBackTime, true); StunAfterKnockBackTime = 0f; } #if UNITY_EDITOR if (SceneManager.GetActiveScene().name == "StatTest") { transform.localPosition = Vector3.zero; } #endif } public void Stun_AfterKnockBack(float time) { StunAfterKnockBackTime = time; } #endregion #region 상태이상 : 특정 위치로 끌어당기기 public virtual void Attract(Vector3 _pos) { if (DSUtil.CheckNull(m_NavMeshAgent)) return; if (gameObject.activeInHierarchy && dic_ccData[eCC.Attract].CCTime <= 0f) StartCoroutine(Co_Attract(_pos)); } IEnumerator Co_Attract(Vector3 _pos) { dic_ccData[eCC.Attract].CCTime = 10f; float t = 0.3f; while (t > 0f) { m_NavMeshAgent.Warp(Vector3.MoveTowards(transform.position, _pos, Time.deltaTime * 2f)); yield return null; t -= Time.deltaTime; } dic_ccData[eCC.Attract].CCTime = 0f; On_NavMeshAgent(); } #endregion #region 상태이상 : 공중으로 에어본 public virtual void KnockedAirborne(double _airborneTime = 1d) { if (dic_ccData[eCC.KnockedAirborne].CCTime > 0) return; StartCoroutine(Co_KnockedAirborne((float)_airborneTime)); } IEnumerator Co_KnockedAirborne(float _airborneTime) { dic_ccData[eCC.KnockedAirborne].CCTime = _airborneTime; StopMove_Imm(true); m_NavMeshAgent.enabled = false; Vector3 v3_ori = new Vector3(transform.position.x, transform.position.y, transform.position.z); Vector3 v3_target = new Vector3(transform.position.x, transform.position.y + 1f, transform.position.z); float t = 0f; while (t < 1f) { yield return null; t += Time.deltaTime * 2f; transform.position = Vector3.Lerp(v3_ori, v3_target, t); } yield return new WaitForSeconds(_airborneTime * 0.75f); t = 0f; while (t < 1f) { yield return null; t += Time.deltaTime * 4f; transform.position = Vector3.Lerp(v3_target, v3_ori, t); } dic_ccData[eCC.KnockedAirborne].CCTime = 0f; m_NavMeshAgent.enabled = true; On_NavMeshAgent(); } #endregion #region 상태이상 : 스턴(기절) public void Stun(double time, bool showEffect = false) { StartCoroutine(Co_Stun(time, showEffect)); } IEnumerator Co_Stun(double _time, bool showEffect = false) { m_animation.speed = 1f; //AnimationPlay("stun"); var cc = eCC.Stun; dic_ccData[cc].CCTime = _time; StopMove_Imm(true); yield return new WaitForSeconds((float)_time); dic_ccData[cc].CCTime = 0f; On_NavMeshAgent(); if (showEffect) InGameInfo.Ins.Show_Effect("Effect_Stun", this, eEffectLocation.Top, (float)_time); } #endregion #region 이동속도 public void Set_MoveSpeed(bool _add, double _v) { if (DSUtil.CheckNull(m_NavMeshAgent)) return; if (_add) m_NavMeshAgent.speed += (float)_v; else m_NavMeshAgent.speed -= (float)_v; } public float Get_MoveSpeed() { var speed = m_NavSpeed; if (dic_ccData[eCC.MOVSPD_Up].CCTime > 0) speed += speed * (float)dic_ccData[eCC.MOVSPD_Up].CCDmg; if (dic_ccData[eCC.MOVSPD_Down].CCTime > 0) speed -= speed * (float)dic_ccData[eCC.MOVSPD_Down].CCDmg; return speed; } #endregion #region 점프 public virtual void Jump(float jumpTime, Action after = null) { StartCoroutine(Co_Jump(jumpTime, after)); } IEnumerator Co_Jump(float jumpTime, Action after = null) { StopMove_Imm(false); m_NavMeshAgent.enabled = false; Vector3 v3_ori = new Vector3(transform.position.x, transform.position.y, transform.position.z); Vector3 v3_target = new Vector3(transform.position.x, transform.position.y + 1f, transform.position.z); float t = 0f, speed = 5f; while (t < 1f) { yield return null; t += Time.deltaTime * speed; transform.position = Vector3.Lerp(v3_ori, v3_target, t); } yield return new WaitForSeconds(jumpTime); t = 0f; while (t < 1f) { yield return null; t += Time.deltaTime * speed * 2f; transform.position = Vector3.Lerp(v3_target, v3_ori, t); } m_NavMeshAgent.enabled = true; On_NavMeshAgent(); after?.Invoke(); } #endregion #region 애니메이션 실행 public virtual void Play_Idle() { if (IsDead() || isPlaying(eAnim.Idle)) return; if (CurAnim != eAnim.Idle || (CurAnim == eAnim.Idle && !isPlaying())) { CurAnim = eAnim.Idle; AnimationPlay(MyValue.Get_AnimName(eAnim.Idle)); } } public virtual void Play_Run() { Play_RunAnim(); } protected void Play_RunAnim() { if (!IsDead() && CurAnim != eAnim.Run) { if (m_NavMeshAgent.isOnNavMesh) m_NavMeshAgent.isStopped = false; CurAnim = eAnim.Run; m_animation.speed = 1f; AnimationPlay(MyValue.Get_AnimName(CurAnim)); } if (CurAnim == eAnim.Run && !Get_AnimStatus(eAnim.Run)) AnimationPlay(MyValue.Get_AnimName(CurAnim)); } public virtual void Play_Hit() { HitEffect_Color(); if (IsDead() || IsCC() || CurAnim >= eAnim.Attack) return; // 공격, 스킬 쓸 때는 피격 애님 무시 if (CurAnim == eAnim.Run) return; // 달릴 때도 무시 if (IsRole(eRole.Mob)) m_HitTime = 0.5f; var aniname = MyValue.Get_AnimName(eAnim.Hit); m_animation.speed = 1f; AnimationPlay(aniname); } public virtual void Play_Die() { var aniname = MyValue.Get_AnimName(eAnim.Die); m_animation.speed = 1f; AnimationPlay(aniname); if (IsRole(eRole.PC) && !DSUtil.CheckNull(ActorInfo.Ins)) ActorInfo.Ins.All_DelTarget(); } public virtual void Play_Attack(int _attack, float _as) { if (IsRole(eRole.Pet) && CurAnim == eAnim.Attack) return; if (IsDead() || CurAnim >= eAnim.Skill) return; StopMove_Imm(false); CurAnim = eAnim.Attack + _attack; var aniname = MyValue.Get_AnimName(eAnim.Attack + _attack); m_animation.speed = _as <= 0f ? 1f : _as; if (dic_ccData.ContainsKey(eCC.ATKSPD_Up) && dic_ccData[eCC.ATKSPD_Up].CCTime > 0) m_animation.speed += m_animation.speed * (float)dic_ccData[eCC.ATKSPD_Up].CCDmg; if (dic_ccData.ContainsKey(eCC.ATKSPD_Down) && dic_ccData[eCC.ATKSPD_Down].CCTime > 0f) m_animation.speed -= m_animation.speed * (float)dic_ccData[eCC.ATKSPD_Down].CCDmg; AnimationPlay(aniname); if (m_Target != null) transform.LookAt(m_Target.transform); if (gos_Effect != null && gos_Effect.Length > _attack) { gos_Effect[_attack].SetActive(false); gos_Effect[_attack].SetActive(true); } } Coroutine co_casting; public virtual bool Play_Skill(string motion) { m_animation.speed = 1f; CurAnim = eAnim.Skill; AnimationPlay(motion); if (!DSUtil.CheckNull(m_Target)) transform.LookAt(m_Target.transform); StopMove_Imm(false); if (!DSUtil.CheckNull(m_Magic)) { if (!string.IsNullOrEmpty(m_Magic.m_SkillTableData.s_NextAnimation)) { co_casting = StartCoroutine(Co_Casting(m_Magic.m_SkillTableData.f_CastingTime)); if (m_NavMeshAgent.isOnNavMesh) m_NavMeshAgent.ResetPath(); } switch (m_Magic.m_SkillTableData.e_Skill) { case eEffect.Skill_JumpAttack: StartCoroutine(Co_JumpAttack(1f, 0.8f)); break; case eEffect.Skill_FatalBlow: StartCoroutine(Co_JumpAttack(0.8f, 0.6f)); break; } if (!string.IsNullOrEmpty(m_Magic.m_SkillTableData.s_CastingEffect)) InGameInfo.Ins.Show_Effect(m_Magic.m_SkillTableData.s_CastingEffect, Get_position()); } return true; } IEnumerator Co_Casting(float castTime) { yield return new WaitForSeconds(castTime); if (!DSUtil.CheckNull(m_Magic)) AnimationPlay(m_Magic.m_SkillTableData.s_NextAnimation); else AnimationPlay("casting_end"); } public virtual void Play_Dodge() { if (IsAvoidCoolTime() || CurAnim == eAnim.Dodge || IsDead()) return; Set_AvoidCoolTime(); Set_AutoBraking(false); act_MoveEnd = Set_AutoBraking; CurAnim = eAnim.Dodge; m_animation.speed = 1f; m_NavMeshAgent.speed = 6f; m_NavMeshAgent.isStopped = false; Del_Magic(); AnimationPlay(MyValue.Get_AnimName(CurAnim)); //Set_Path(transform.position + transform.forward * 3f); Set_Move(transform.position + transform.forward * 3f); //Set_Warp(transform.position + transform.forward * 2f); } public void AnimationPlay(string aniname) { m_animation.Play(aniname); //if (IsRole(eRole.Boss)) Debug.Log(aniname); } protected bool Get_AnimStatus(eAnim anim) { return m_animation.GetCurrentAnimatorStateInfo(0).IsName(MyValue.Get_AnimName(anim)); } #endregion #region 아웃라인 Outline m_Outline; public void Set_Outline(bool active) { if (active) { if (DSUtil.CheckNull(m_Outline)) m_Outline = gameObject.AddComponent(); m_Outline.enabled = true; m_Outline.OutlineColor = new Color32(168, 0, 0, 102); m_Outline.OutlineWidth = 5f; } else if (m_Outline != null) m_Outline.enabled = false; Set_MobMark(active); } protected virtual void Set_MobMark(bool active) { } #endregion #region 히트 이펙트 public virtual void HitEffect_Color() { if (!ProjectileInfo.Ins || IsInvoking(nameof(Off_HitEffect_Color))) return; for (int j = 0; j < arr_Renderer.Length; j++) { var materials = arr_Renderer[j].sharedMaterials.ToList(); materials.Add(ProjectileInfo.Ins.arr_materials[1]); arr_Renderer[j].materials = materials.ToArray(); } Invoke(nameof(Off_HitEffect_Color), 0.1f); } void Off_HitEffect_Color() { for (int j = 0; j < arr_Renderer.Length; j++) { var materials = arr_Renderer[j].sharedMaterials.ToList(); materials.Remove(ProjectileInfo.Ins.arr_materials[1]); arr_Renderer[j].materials = materials.ToArray(); } } #endregion #region 캐릭터 크기 조절 public void Set_ScaleControl(bool returntoOriginalScale, float targetscale = 1f, Action actComplete = null) { StartCoroutine(Co_ScaleControl(returntoOriginalScale, targetscale, actComplete)); } protected virtual IEnumerator Co_ScaleControl(bool returntoOriginalScale, float targetscale, Action actComplete = null) { yield break; } #endregion public bool CanMove() { return !IsCC() && m_NavMeshAgent.isOnNavMesh && !m_NavMeshAgent.isStopped; } protected virtual bool IsAvoidCoolTime() { return false; } protected virtual void Set_AvoidCoolTime() { } public virtual void On_Is10_4() { } public virtual void Check_10_4() { } public virtual MonsterAppearData Get_MonsterStatTableData() { return null; } public virtual void On_Regen() { gameObject.SetActive(true); DeadStatus = false; m_Stat.Clear_BuffDebuff(); m_Stat.Set_Stat(eStat.HP, 0); Heal(1f, false); Init_CC(); m_animation.speed = 1f; } public virtual void Set_AutoBraking(bool _active) { } public void Set_Auto() { m_Auto = !m_Auto; ServerInfo.Ins.m_ServerData.Set_Common(eCommon.Auto, m_Auto ? 1 : 0); if (m_Auto) { IsStop = false; NewGameUI.Ins.m_GuideQuestUI.Add_GuideQuest(ePurpose.AutoMagic); } else { Del_Magic(); if (m_Target != null) { if (IsRole(eRole.PC)) { m_Target.Set_Outline(false); m_NavMeshAgent.ResetPath(); Play_Idle(); } } Del_Target(); } } public Actor Get_MyPet() { return m_MyPet; } public void Set_MyPet(Actor actor) { m_MyPet = actor; } #region 애니메이션 이벤트 public virtual void Event_Idle(int a) { CurAnim = eAnim.Idle; #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 1, a); #endif } public virtual void Move(float b) { #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 2, 0, b); #endif } public virtual void Interpolation(string s) { #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 3, 0, 0f, s); #endif } public virtual void Dodge(int a) { #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 1, a); #endif } public virtual void Immortal(int a) { #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 1, a); #endif } public virtual void Hit(float b) { #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 2, 0, b); #endif m_DamageRate = b; } public virtual void Projectile(string s) { #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 3, 0, 0f, s); #endif } /// /// 0 None, 1 스킬 사용 시 이동 금지 /// public virtual void SkillEvent(int a) { #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 1, a); #endif Shoot_Skill(); if (a == 0 && m_NavMeshAgent.isOnNavMesh) // 움직임 가능 m_NavMeshAgent.isStopped = false; else if (a == 1) { IsStop = true; m_NavMeshAgent.ResetPath(); } } public virtual void Indicator(int a) { #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 1, a); #endif } public virtual void FootR(string s) { #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 3, 0, 0f, s); #endif } public virtual void FootL(string s) { #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 3, 0, 0f, s); #endif } public virtual void ShowEffect(AnimationEvent s) { #if UNITY_EDITOR if (SettingsMain.Ins) SettingsMain.Ins.Add_Event(System.Reflection.MethodBase.GetCurrentMethod().Name, 3, s.intParameter, s.floatParameter, s.stringParameter); #endif switch (s.intParameter) { case 0: InGameInfo.Ins.Show_Effect(s.stringParameter, Get_Center_position(), transform.eulerAngles); break; case 1: InGameInfo.Ins.Show_Effect(s.stringParameter, Get_position(), transform.eulerAngles); break; case 2: InGameInfo.Ins.Show_Effect(s.stringParameter, Get_Center_position()); break; case 3: InGameInfo.Ins.Show_Effect(s.stringParameter, Get_position()); break; } } public virtual void Init_CurAnim(bool resetpos) { CurAnim = eAnim.Idle; if (resetpos) Set_Warp(Vector3.zero); } public eAnim Get_CurAnim() { return CurAnim; } public void Set_CurAnim(eAnim anim) { CurAnim = anim; } public virtual bool Is_Immortal() { return m_bImmortal; } #endregion }