Project_WL/Assets/Script/Character/Mob/MobActor.cs

875 lines
36 KiB
C#
Raw Normal View History

2024-12-15 01:39:39 +00:00
using System;
2025-02-21 01:07:35 +00:00
using System.Collections;
using System.Collections.Generic;
2024-12-15 01:39:39 +00:00
using UnityEngine;
using UnityEngine.SceneManagement;
2025-02-19 03:22:49 +00:00
public enum eMobStatus { None, PatrolWait, PatrolRot, Patroling, Battle, BattleStop, Attack, Chase, Skill }
2024-12-15 01:39:39 +00:00
public class MobActor : Actor
{
2025-02-21 03:21:31 +00:00
public Transform tf_MeeleAttackPos;
2024-12-15 01:39:39 +00:00
public int MagicID, HealCount;
public float HealRate = 0.1f;
protected int m_SpawnerId;
protected eMobStatus MobStatus;
Vector3 OriginalPos, TargetPatrolPos;
float m_PatrolDelay, m_PatrolTime, f_BaseChaseRange, HealPerSec, HPRegenPerSec;
2024-12-15 01:39:39 +00:00
bool b_IsFirstAttack, NoUpdate_byTool;
protected MonsterAppearData m_MonsterAppearData;
protected MonsterTableData m_MonsterTableData;
protected Dictionary<SkillListTableData, int> dic_skill = new Dictionary<SkillListTableData, int>();
2024-12-15 01:39:39 +00:00
Action<int> m_actDie;
2025-02-07 08:04:56 +00:00
protected NoSeeLongDMob m_NoSeeLongDMob;
2025-02-21 03:21:31 +00:00
bool useMeeleAttackPos;
2025-02-07 08:04:56 +00:00
bool isNSLDMob;
2025-02-27 00:42:29 +00:00
protected List<Actor> list_summon = new List<Actor>();
2025-05-21 23:13:07 +00:00
protected Dictionary<string, Material> dic_mainMat = new Dictionary<string, Material>();
protected Dictionary<string, Material> dic_dissolveMat = new Dictionary<string, Material>();
2025-02-07 08:04:56 +00:00
2024-12-15 01:39:39 +00:00
protected override void Start()
{
base.Start();
GetComponent<Rigidbody>().isKinematic = true;
2025-02-07 08:04:56 +00:00
m_NoSeeLongDMob = GetComponent<NoSeeLongDMob>();
isNSLDMob = !DSUtil.CheckNull(m_NoSeeLongDMob);
2025-02-21 03:21:31 +00:00
useMeeleAttackPos = !DSUtil.CheckNull(tf_MeeleAttackPos);
2025-05-21 23:13:07 +00:00
for (int i = 0; i < arr_Renderer.Length; i++)
{
dic_mainMat.Add(arr_Renderer[i].name, arr_Renderer[i].material);
dic_dissolveMat.Add(arr_Renderer[i].name, new Material(InGameInfo.Ins.mat_Dissolve));
dic_dissolveMat[arr_Renderer[i].name].mainTexture = arr_Renderer[i].material.mainTexture;
}
2024-12-15 01:39:39 +00:00
}
public override void Set(bool isEnemy, Actor owner, ServerData sdata, int _id, bool _stop, bool _ui = false)
{
2025-05-21 23:13:07 +00:00
if (dic_mainMat.Count > 0)
{
for (int i = 0; i < arr_Renderer.Length; i++)
arr_Renderer[i].material = dic_mainMat[arr_Renderer[i].name];
}
2024-12-15 01:39:39 +00:00
base.Set(isEnemy, owner, sdata, _id, _stop);
m_PatrolTime = 0f;
2024-12-15 01:39:39 +00:00
if (MagicID > 0) m_Magic = new UseMagicInfo { m_SkillTableData = table_skilllist.Ins.Get_Data_orNull(MagicID), m_uiIndex = -1 };
m_SpawnerId = _id;
m_MonsterAppearData = table_monsterappear.Ins.Get_Data_orNull(m_SpawnerId);
//var chapter = InGameInfo.Ins.Get_CurStageData().Chapter;
if (transform.localScale.x > 1f)
{
m_NavMeshAgent.stoppingDistance = m_NavStopDistance * transform.localScale.x;
if (m_AttackType == eAttackType.Physics && m_NavMeshAgent.stoppingDistance > 7f) m_NavMeshAgent.stoppingDistance = 7f;
//else m_AttackType == eAttackType.Range && m_NavMeshAgent.stoppingDistance > 20f) m_NavMeshAgent.stoppingDistance = 20f;
}
//if (m_SubRole == eSubRol.Dummy) IsStop = true; // 가만히 맞아야 할 때
2024-12-15 01:39:39 +00:00
#if UNITY_EDITOR
if (SceneManager.GetActiveScene().name == "StatTest") return;
#endif
Set_Warp(Get_position());
}
2025-02-27 00:42:29 +00:00
public virtual void Set(MonsterTableData mobtable, Vector3 pos, Action<int> actDie, int order, float noDmgTime = 0f)
2024-12-15 01:39:39 +00:00
{
m_Role = eRole.Mob;
m_SubRole = mobtable.e_MonsterType;
2024-12-15 01:39:39 +00:00
m_actDie = actDie;
2025-02-27 00:42:29 +00:00
NoDmgTime = noDmgTime;
bool IsBoss = IsSubRole(eSubRol.Boss);
2024-12-15 01:39:39 +00:00
m_MonsterTableData = mobtable;
transform.localScale = m_MonsterTableData.f_DefaultScale * Vector3.one;
2024-12-15 01:39:39 +00:00
m_AttackType = m_MonsterTableData.e_AttackType;
m_NavStopDistance = m_MonsterTableData.f_BaseATKRange;
2024-12-15 01:39:39 +00:00
b_IsFirstAttack = m_MonsterTableData.b_IsFirstAttack;
f_BaseChaseRange = m_MonsterTableData.f_BaseChaseRange;
2024-12-15 01:39:39 +00:00
//var chapter = InGameInfo.Ins.Get_CurStageData().Chapter;
//if (IsBoss && chapter < 101) { GameUI.Ins.IngameUI.m_BossInfoUI.Set(m_MonsterTableData.Get_Name()); }
// 순찰 모드로 전환
transform.SetPositionAndRotation(pos, Quaternion.identity);
OriginalPos = pos;
Set_Warp(pos);
2024-12-15 01:39:39 +00:00
Change_MobStatus(eMobStatus.PatrolWait);
// 몹 스탯 설정
m_Stat = new ActorStatInfo(m_Role, m_MonsterTableData, m_MonsterAppearData);
2025-01-27 06:13:58 +00:00
m_Stat.Set_Maze();
2024-12-15 01:39:39 +00:00
Reset_AttackCoolTime();
2025-02-09 23:50:15 +00:00
m_NavSpeed = m_NavMeshAgent.speed = (float)m_Stat.Get_Stat(eStat.FinalMoveSpeed);
2025-02-26 03:01:07 +00:00
//m_NavMeshAgent.avoidancePriority = 51 + order;
2024-12-15 01:39:39 +00:00
2025-02-11 07:09:38 +00:00
HealPerSec = 0f;
HPRegenPerSec = (float)m_Stat.Get_Stat(eStat.HP_REGEN_Per1Sec);
2024-12-15 01:39:39 +00:00
#if UNITY_EDITOR
if (SceneManager.GetActiveScene().name == "StatTest")
{
transform.localPosition = Vector3.zero;
return;
}
#endif
//GameUI.Ins.IngameUI.m_ChapterQuest.Add_PurposeCount(new ChapterQuestAddData { purpose = ePurpose.MeetMob, mobid = m_MonsterTableData.n_MonsterID });
}
public void Set(int iteration, bool isFirstAttack, float chaseRange)
{
b_IsFirstAttack = isFirstAttack;
f_BaseChaseRange *= chaseRange;
m_Stat.Set_Wave(iteration);
}
2025-02-13 04:40:04 +00:00
public override void On_Regen(bool reincarnation = false, float healrate = 1f)
2024-12-15 01:39:39 +00:00
{
2025-02-13 04:40:04 +00:00
base.On_Regen(reincarnation, healrate);
2024-12-15 01:39:39 +00:00
Change_MobStatus(eMobStatus.PatrolWait);
2025-02-13 04:40:04 +00:00
if (m_BoxCollider) m_BoxCollider.enabled = true;
m_NavMeshAgent.enabled = true;
if (!reincarnation)
{
Set_Warp(OriginalPos);
InGameInfo.Ins.Show_Effect("Effect_MonsterSpawn", Get_position());
Reset_Extra();
list_summon.ForEach(f => f.Off());
2025-02-13 04:40:04 +00:00
}
2024-12-15 01:39:39 +00:00
}
protected override void Update()
{
2025-02-11 07:09:38 +00:00
if (IsDead()) return;
Update_HealPerSec();
if (NoUpdate_byTool || IsStop || IsCC()) return;
if (isNSLDMob && m_NoSeeLongDMob.IsNoSeeMob()) return;
base.Update();
if (IsSubRole(eSubRol.Mimic)) Del_Target();
2024-12-15 01:39:39 +00:00
// 순찰 중
switch (MobStatus)
{
case eMobStatus.PatrolWait:
if (m_PatrolDelay > 0f)
m_PatrolDelay -= Time.deltaTime;
else
Change_MobStatus(eMobStatus.PatrolRot);
//if (!IsSubRole(eSubRol.Mimic))
// Check_Battle();
2024-12-15 01:39:39 +00:00
break;
case eMobStatus.PatrolRot: // TargetPatrolPos 위치를 바라봄
2024-12-15 01:39:39 +00:00
Vector3 directionToTarget = (TargetPatrolPos - transform.position).normalized;
Quaternion lookRotation = Quaternion.LookRotation(new Vector3(directionToTarget.x, 0, directionToTarget.z));
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 5f);
if (Quaternion.Angle(transform.rotation, lookRotation) < 5f)
Change_MobStatus(eMobStatus.Patroling);
break;
case eMobStatus.Patroling: // TargetPatrolPos 위치로 이동함
m_PatrolTime -= Time.deltaTime;
if (m_PatrolTime <= 0f || Complete_Destination())
2025-02-09 23:50:15 +00:00
{
2024-12-15 01:39:39 +00:00
Change_MobStatus(eMobStatus.PatrolWait);
2025-02-09 23:50:15 +00:00
if (!IsSubRole(eSubRol.Mimic))
Check_Battle();
}
2024-12-15 01:39:39 +00:00
break;
case eMobStatus.BattleStop:
Change_MobStatus(eMobStatus.PatrolRot);
2025-01-31 06:08:53 +00:00
if (!IsSubRole(eSubRol.Mimic))
Heal(1f);
2024-12-15 01:39:39 +00:00
break;
case eMobStatus.Battle:
if (isTarget)
2024-12-15 01:39:39 +00:00
{
2025-03-01 03:21:02 +00:00
if (CurAnim < eAnim.Attack && !DSUtil.WithInDistance(Get_position(), m_Target.Get_position(), m_NavMeshAgent.stoppingDistance))
2024-12-15 01:39:39 +00:00
{
if (!isPlaying(eAnim.Attack, eAnim.Attack2, eAnim.Attack3))
Change_MobStatus(eMobStatus.Chase);
}
else
Change_MobStatus(eMobStatus.Attack);
}
else
Change_MobStatus(eMobStatus.BattleStop);
Check_Patrol();
break;
case eMobStatus.Attack:
if (isTarget)
2024-12-15 01:39:39 +00:00
{
if (m_Target.IsDead())
{
Check_Battle();
if (MobStatus == eMobStatus.Attack) // 다음 타겟 못 찾았음
Change_MobStatus(eMobStatus.PatrolWait);
}
else
{
2025-05-19 22:43:22 +00:00
if (!DSUtil.WithInDistance(m_Target.Get_position(), Get_position(), m_NavStopDistance))
2024-12-15 01:39:39 +00:00
Change_MobStatus(eMobStatus.Chase);
else if (m_attackCoolTime <= 0f)
{
m_attackCoolTime = 1f;
2025-02-10 02:56:16 +00:00
Play_Attack(0, (float)m_Stat.Get_Stat(eStat.FinalAttackSpeed));
2024-12-15 01:39:39 +00:00
}
}
}
else
Change_MobStatus(eMobStatus.BattleStop);
break;
case eMobStatus.Chase:
if (isTarget)
2024-12-15 01:39:39 +00:00
{
Set_Path(m_Target.Get_position());
2025-03-01 03:21:02 +00:00
if (DSUtil.WithInDistance(Get_position(), m_Target.Get_position(), m_NavMeshAgent.stoppingDistance))
2024-12-15 01:39:39 +00:00
Change_MobStatus(eMobStatus.Attack);
}
Check_Patrol();
break;
case eMobStatus.Skill:
if (!isTarget || (isTarget && m_Target.IsDead()))
Change_MobStatus(eMobStatus.PatrolWait);
break;
2024-12-15 01:39:39 +00:00
}
{
if (m_attackCoolTime > 0f) m_attackCoolTime -= Time.deltaTime;
if (m_HitTime > 0f) { m_HitTime -= Time.deltaTime; if (m_attackCoolTime > 0f) return; }
if (GoToTargetTime > 0f) GoToTargetTime -= Time.deltaTime;
2024-12-15 01:39:39 +00:00
//// 일정 시간이 지나면 가장 가까운 적을 다시 찾아봄
//if (FindOtherTargetTime > 0f)
//{
// FindOtherTargetTime -= Time.deltaTime;
// if (FindOtherTargetTime <= 0f)
// {
// FindOtherTargetTime = 7.5f;
// FindNextTarget(m_FindDist);
// }
//}
}
}
2025-02-11 07:09:38 +00:00
void Update_HealPerSec()
{
if (HPRegenPerSec > 0f)
{
HealPerSec += Time.deltaTime;
if (HealPerSec >= 1f)
{
HealPerSec = 0f;
if (m_Stat.Get_Stat(eStat.HP_REGEN_Per1Sec) > 0)
Heal(HPRegenPerSec);
}
}
}
2025-02-16 00:14:00 +00:00
public override void Change_MobStatus(eMobStatus mobStatus)
2024-12-15 01:39:39 +00:00
{
#if UNITY_EDITOR
if (SceneManager.GetActiveScene().name == "StatTest") return;
#endif
MobStatus = mobStatus;
switch (mobStatus)
{
case eMobStatus.PatrolWait:
Del_Target();
Play_Idle();
m_PatrolDelay = m_MonsterTableData.f_PatrolWaitTime;
if (m_NavMeshAgent.isOnNavMesh && !IsCC()) m_NavMeshAgent.isStopped = false;
m_NavMeshAgent.stoppingDistance = 0.1f;
break;
case eMobStatus.PatrolRot:
Del_Target();
if (m_NavMeshAgent.isOnNavMesh && !IsCC()) m_NavMeshAgent.isStopped = false;
TargetPatrolPos = DSUtil.Get_RandomPos_onNavMesh(OriginalPos, m_MonsterAppearData.f_PatrolRange - 1f, m_MonsterAppearData.f_PatrolRange);
break;
case eMobStatus.Patroling:
Del_Target();
Play_Run();
Set_Path(TargetPatrolPos);
m_NavMeshAgent.stoppingDistance = 0.1f;
m_PatrolTime = 5f;
2024-12-15 01:39:39 +00:00
break;
case eMobStatus.Battle:
m_NavMeshAgent.stoppingDistance = m_NavStopDistance;
2024-12-15 01:39:39 +00:00
FindNextTarget(10000f);
break;
case eMobStatus.BattleStop:
Del_Target();
Play_Idle();
StopMove_Imm(true);
Reset_Extra();
2024-12-15 01:39:39 +00:00
break;
case eMobStatus.Attack:
break;
case eMobStatus.Chase:
Play_Run();
break;
2025-04-07 23:18:30 +00:00
case eMobStatus.Skill:
StopMove_Imm(false);
m_NavMeshAgent.isStopped = false;
break;
2024-12-15 01:39:39 +00:00
}
}
2025-02-16 00:14:00 +00:00
protected override void Check_Battle()
2024-12-15 01:39:39 +00:00
{
2025-06-05 00:11:03 +00:00
if (b_IsFirstAttack || isTarget) // 타겟이 있었던 상황도 전투 상태였음
2024-12-15 01:39:39 +00:00
{ // 선공이고, 플레이어가 추적 범위 안에 들어오면 전투 상태로 전환
var enemies = ActorInfo.Ins.Get_EnemyActors(IsEnemy(), Get_position(), f_BaseChaseRange);
2024-12-15 01:39:39 +00:00
if (enemies.Count > 0)
Change_MobStatus(eMobStatus.Battle);
}
}
void Check_Patrol()
{
// 플레이어가 추적 범위 밖으로 나가면 순찰 상태로 전환
if (MobStatus != eMobStatus.PatrolRot && !isPlaying(eAnim.Attack, eAnim.Skill) &&
2025-03-01 03:21:02 +00:00
(!isTarget || !DSUtil.WithInDistance(OriginalPos, Get_position(), m_MonsterTableData.f_BaseChaseRange)))
2024-12-15 01:39:39 +00:00
Change_MobStatus(eMobStatus.BattleStop);
}
//protected override void Check_Attack()
//{
// // 현재 애니메이션 상태 정보를 가져옴
// AnimatorStateInfo stateInfo = m_animation.GetCurrentAnimatorStateInfo(0);
// // 애니메이션의 특정 구간 (예: 30%에서 40% 사이) 확인
// if (stateInfo.normalizedTime >= 0.3f && stateInfo.normalizedTime <= 0.4f && stateInfo.IsName("attack"))
// {
// // 데미지를 한 번만 적용
// if (!hasAppliedDamage)
// {
// switch (CurAnim)
// {
// case eAnim.Attack:
// case eAnim.Attack2:
// case eAnim.Attack3:
// case eAnim.Attack4:
// switch (m_AttackType)
// {
// // 근접
// case eAttackType.MeleePhysics:
// case eAttackType.MeleeMagic:
// case eAttackType.MeleePure:
// m_Target.Get_Damage(Get_DamageInfo());
// break;
// // 원거리
// case eAttackType.RangePhysics:
// case eAttackType.RangeMagic:
// case eAttackType.RangePure:
// ProjectileInfo.Ins.Shoot_Projectile(m_MonsterTableData.s_Porjectile, this, m_Target, 1f, tfs_ProjectileStart[0].position);
// break;
// }
// break;
// case eAnim.Skill1:
// case eAnim.Skill2:
// break;
// }
// hasAppliedDamage = true; // 데미지가 적용되었음을 표시
// }
// }
// else
// {
// // 구간을 벗어나면 다시 데미지 적용 가능하도록 설정
// hasAppliedDamage = false;
// }
//}
2025-02-10 00:50:00 +00:00
protected void FindNextTarget(float _dist)
2024-12-15 01:39:39 +00:00
{
switch (m_SubRole)
{
2025-02-10 00:50:00 +00:00
case eSubRol.Mimic: break;
default:
2024-12-15 01:39:39 +00:00
m_Target = ActorInfo.Ins.Get_Nearest_EnemyActor_orNull(IsEnemy(), Get_position());
break;
}
}
protected override void Kill_OnePunch(DamageInfo dinfo)
{
base.Kill_OnePunch(dinfo);
if (!DSUtil.CheckNull(dinfo.Beater_pd) &&
!DSUtil.CheckNull(dinfo.Beater_pd.m_SkillListTableData) &&
dinfo.Beater_pd.m_SkillListTableData.e_Skill == eEffect.Skill_FireBolt)
ServerInfo.Ins.m_ServerData.Add_TitleCondition(59); // 칭호 : 두방은 사치
}
protected override void VeryStrongDamage(double dmg)
{
base.VeryStrongDamage(dmg);
if (dmg > 1000000000000d) ServerInfo.Ins.m_ServerData.Add_Item(new ItemData(eItem.Title, 68, 1)); // 칭호 : 한방있는
}
2024-12-15 01:39:39 +00:00
protected override void Set_Die()
{
2024-12-28 00:20:09 +00:00
#if UNITY_EDITOR
if (SceneManager.GetActiveScene().name == "StatTest")
return;
#endif
2024-12-15 01:39:39 +00:00
var sdata = ServerInfo.Ins.m_ServerData;
2025-02-13 04:40:04 +00:00
if (n_Reincarnation <= 0)
{
2025-05-22 05:44:55 +00:00
StartCoroutine(Co_Dissolve());
MonsterSimpleInfo.Ins.DeadTarget(this);
2025-03-09 05:52:14 +00:00
// 골드 드랍
2025-03-06 07:47:57 +00:00
DropItemInfo.Ins.Drop_DropItem(2, m_MonsterAppearData.n_DropGold, Get_position());
2025-03-09 05:52:14 +00:00
// 경험치
var pcstat = MyValue.MyPC.Get_StatInfo();
var exp = m_MonsterAppearData.n_DropExp;
exp += (uint)(exp * (pcstat.Get_Stat(eStat.EXP_Multiplier) + pcstat.Get_Stat(eStat.Battle_EXP_Multiplier)));
sdata.PC.Add_Exp(exp);
2025-03-09 05:52:14 +00:00
// 아이템 드랍
var rndBag = table_randombag.Ins.Get_DataList(m_MonsterAppearData.n_DropReward);
for (int i = 0; i < rndBag.Count; i++)
{
if (DSUtil.RandomTrue(rndBag[i].f_DropRate))
{
DropItemInfo.Ins.Drop_DropItem(rndBag[i].n_ItemId, rndBag[i].n_DropCount, Get_position());
break;
}
}
2024-12-15 01:39:39 +00:00
#if UNITY_EDITOR
if (SceneManager.GetActiveScene().name == "StatTest") return;
2024-12-15 01:39:39 +00:00
#endif
2025-03-17 23:31:46 +00:00
sdata.Add_CollectionMobKill(m_MonsterTableData.n_MonsterID);
sdata.Add_MissionCount(ePurpose.KILL_MONSTER, m_MonsterTableData.n_MonsterID);
2025-03-19 04:20:05 +00:00
sdata.Add_MissionCount(ePurpose.KILL_MONSTER_GRADE, IsSubRole(eSubRol.Boss) ? 3 : IsSubRole(eSubRol.Elite) ? 2 : 1);
sdata.Add_MissionCount(ePurpose.KILL_MONSTER_GRADE_ACC, IsSubRole(eSubRol.Boss) ? 3 : IsSubRole(eSubRol.Elite) ? 2 : 1);
2025-03-17 23:31:46 +00:00
sdata.Add_MissionCount(ePurpose.KILL_MONSTER_ALL);
sdata.Add_MissionCount(ePurpose.KILL_MONSTER_ACC);
2024-12-15 01:39:39 +00:00
}
2025-03-17 23:31:46 +00:00
base.Set_Die();
2025-05-21 23:13:07 +00:00
}
IEnumerator Co_Dissolve()
{
yield return new WaitForSeconds(0.5f);
for (int i = 0; i < arr_Renderer.Length; i++)
arr_Renderer[i].material = dic_dissolveMat[arr_Renderer[i].name];
float prog = 1f;
while (prog > 0f)
{
yield return null;
prog -= Time.deltaTime * 0.5f;
for (int i = 0; i < arr_Renderer.Length; i++)
arr_Renderer[i].sharedMaterial.SetFloat("_Progress", prog);
}
2024-12-15 01:39:39 +00:00
}
protected override void After_Die()
{
base.After_Die();
if (n_Reincarnation == 0)
m_actDie?.Invoke(m_MonsterTableData.n_MonsterID);
}
2024-12-15 01:39:39 +00:00
public override void Shoot_Skill()
{
base.Shoot_Skill();
Reset_AttackCoolTime();
2024-12-15 01:39:39 +00:00
}
2025-02-19 04:14:09 +00:00
public override DamageInfo Get_DamageInfo(ProjectileData _pd, bool forceCri = false)
2025-02-10 05:35:41 +00:00
{
2025-02-19 04:14:09 +00:00
var dinfo = base.Get_DamageInfo(_pd, forceCri);
2025-02-10 05:35:41 +00:00
if (m_Stat.Get_Stat(eStat.DMG_TO_HP) > 0d)
dinfo.act_returnLastDmg = Get_LastDmg;
2025-02-10 06:47:31 +00:00
if (m_MonsterTableData.n_PassiveSkillID > 0)
{
var skilldata = table_skilllist.Ins.Get_Data_orNull(m_MonsterTableData.n_PassiveSkillID);
if (skilldata.e_SkillExtraType != eSkillExtraType.None)
{
_pd.m_SkillListTableData = skilldata;
_pd.e_SkillExtraType = skilldata.e_SkillExtraType;
_pd.m_skillTypeConfigTable = table_skilltypeconfig.Ins.Get_Data_orNull(_pd.e_SkillExtraType);
}
}
2025-02-10 05:35:41 +00:00
return dinfo;
}
private void Get_LastDmg(double dmg)
{
if (m_Stat.Get_Stat(eStat.DMG_TO_HP) > 0d)
Heal(dmg * m_Stat.Get_Stat(eStat.DMG_TO_HP));
}
2024-12-15 01:39:39 +00:00
public override void Get_Damage(DamageInfo _dinfo)
{
//_dinfo.Damage = 1f; // 테스트 : 몹 안 죽게
base.Get_Damage(_dinfo);
// 멀리서 맞았으면 맞은 몹을 타겟으로 잡고 주변 몹들도 같이 간다.
if (!isTarget)
2024-12-15 01:39:39 +00:00
{
Change_Target(false, _dinfo.Beater, true);
2024-12-15 01:39:39 +00:00
// TODO 정인호 : 몬스터 주변 몬스터 부르기
//var allies = ActorInfo.Ins.Get_EnemyActors(m_Role, transform, m_byHitDist);
//for (int i = 0; i < allies.Count; i++)
// if (allies[i].Get_Target() == null)
// allies[i].Change_Target(false, m_Target, true);
}
2025-05-06 22:41:40 +00:00
else
{
var dist1 = DSUtil.Get_Distance(m_Target.Get_position(), Get_position());
var dist2 = DSUtil.Get_Distance(_dinfo.Beater.Get_position(), Get_position());
if (dist1 > dist2) Change_Target(false, _dinfo.Beater, true);
}
if (m_MonsterTableData.n_PassiveSkillID > 0 && !IsDead())
{
var skilldata = table_skilllist.Ins.Get_Data_orNull(m_MonsterTableData.n_PassiveSkillID);
if (skilldata.e_SkillEnhance == eSkillEnhance.SummonMob)
{
int perval1 = (int)(Get_hpLostPercentage() / skilldata.f_ExtraValue1);
if (n_SummonCount < perval1)
{
++n_SummonCount;
if (list_summon.Count >= n_SummonCount * skilldata.f_ExtraValue2)
{
int startindex = (n_SummonCount - 1) * (int)skilldata.f_ExtraValue2;
for (int i = startindex; i < skilldata.f_ExtraValue2; i++)
list_summon[i].On_Regen();
}
else
{
var mobData = table_monsterlist.Ins.Get_Data_orNull((int)skilldata.f_ExtraValue4);
for (int i = 0; i < skilldata.f_ExtraValue2; i++)
{
AddrResourceMgr.Ins.LoadObject<GameObject>(mobData.s_MonsterPrefab, handle =>
{
var mob = DSUtil.Get_Clone<MobActor>(handle.Result, transform.parent);
AddrResourceMgr.Ins.Set_AddressableReleaseSelf(mob.gameObject);
ActorInfo.Ins.Add_Actor(mob, eRole.Mob, m_MonsterAppearData.n_SpawnerID, mobData.s_MonsterPrefab);
mob.Set(true, null, null, m_MonsterAppearData.n_SpawnerID, false);
mob.Set(mobData, DSUtil.Get_RandomPos_onNavMesh(Get_position(), 2f), null, 0);
mob.m_SubRole = eSubRol.Summon;
mob.On_Regen();
mob.Get_StatInfo().Reset_byStatInfo(Get_StatInfo(), skilldata.f_ExtraValue3);
list_summon.Add(mob);
});
}
}
}
}
else if (skilldata.e_SkillEnhance == eSkillEnhance.AcidicLiquid)
{
ProjectileInfo.Ins.Shoot_Projectile("Projectile_Mob_AcidcLiquid", this, null, 0f, Get_position(), 4f,
pb =>
{
var pc = pb.GetComponent<Projectile_Curved>();
var endpos = DSUtil.Get_RandomPos_onNavMesh(Get_position(), 1.8f, 4f);
pc.Launch_Curved(Get_position(), endpos, 1.5f, 4f, true, () =>
{
ProjectileInfo.Ins.Shoot_Projectile("Projectile_Mob_AcidcLiquidPoison", this, null, 1f,
pc.transform.position, 3f, pb =>
{
var pd = pb.Get_ProjectTileData();
pd.e_SkillExtraType = eSkillExtraType.Poison;
pd.m_skillTypeConfigTable = table_skilltypeconfig.Ins.Get_Data_orNull(pd.e_SkillExtraType);
pd.m_SkillListTableData = skilldata;
});
});
});
}
}
2024-12-15 01:39:39 +00:00
}
public override void Change_Target(bool _ispc, Actor target, bool _ChangeTargetByHit = false)
{
base.Change_Target(_ispc, target, _ChangeTargetByHit);
if (isTarget) b_IsFirstAttack = true;
2024-12-15 01:39:39 +00:00
if (b_IsFirstAttack) Change_MobStatus(eMobStatus.Battle);
}
protected override void Heal_To_Target()
{
base.Heal_To_Target();
if (isTarget) m_Target.Heal(HealRate);
2024-12-15 01:39:39 +00:00
if (HealCount > 0)
{
var allies = ActorInfo.Ins.Get_AlliesActors(IsEnemy(), Get_position());
var hurts = allies.FindAll(f => f != m_Target && f.Get_HP() < f.Get_MaxHP());
for (int i = 0; i < hurts.Count; i++)
{
hurts[i].Heal(HealRate);
if (i + 1 == HealCount - 1) break;
}
}
}
public override MonsterAppearData Get_MonsterStatTableData() { return m_MonsterAppearData; }
public override bool isNoseeMob() { return isNSLDMob ? m_NoSeeLongDMob.IsNoSeeMob() : false; }
2024-12-15 01:39:39 +00:00
public override int Get_Group() { return m_SpawnerId; }
protected override void Set_MobMark(bool active)
2025-03-03 02:19:33 +00:00
{ InGameInfo.Ins.Get_Obj(eObj.MobMark).GetComponent<MobMark>().Set(active, this); }
2024-12-15 01:39:39 +00:00
2025-02-10 05:35:41 +00:00
public override void Play_Hit()
{
base.Play_Hit();
switch (m_SubRole)
{
default:
switch (CurAnim)
{
case eAnim.Die:
case eAnim.Hit:
case eAnim.Attack:
case eAnim.Skill:
return;
}
break;
case eSubRol.Elite:
switch (CurAnim)
{
case eAnim.Run:
case eAnim.Die:
case eAnim.Hit:
case eAnim.Attack:
case eAnim.Skill:
return;
}
break;
case eSubRol.Boss:
return;
}
if (IsDead() || IsCC()) return;
if (IsRole(eRole.Mob)) m_HitTime = 0.5f;
m_animation.speed = 1f;
AnimationPlay(MyValue.Get_AnimName(eAnim.Hit));
}
2024-12-15 01:39:39 +00:00
public override void Projectile(string s)
{
base.Projectile(s);
if (ProjectileInfo.isIns)
2025-02-21 03:21:31 +00:00
{
if (m_MonsterTableData.n_PassiveSkillID > 0)
{
var skilldata = table_skilllist.Ins.Get_Data_orNull(m_MonsterTableData.n_PassiveSkillID);
if (skilldata.e_SkillEnhance == eSkillEnhance.RageOfFairy)
{
int perval1 = (int)(Get_hpLostPercentage() / skilldata.f_ExtraValue1);
if (perval1 > 0) Buff_or_Debuff(eCC.MultiShot, 1000f, 0d, perval1);
else Buff_or_Debuff(eCC.MultiShot, 0f, 0d, 0);
}
}
Shoot_Projectile(m_MonsterTableData.s_Porjectile1, m_MonsterTableData.f_ProjectileLifeTime1,
useMeeleAttackPos ? tf_MeeleAttackPos.position : Get_CenterPositionFoward());
2025-02-21 03:21:31 +00:00
}
2024-12-15 01:39:39 +00:00
}
2025-05-09 04:27:04 +00:00
public override void Set_Target(Actor target)
{
base.Set_Target(target);
m_NavMeshAgent.stoppingDistance = m_NavStopDistance;
Change_MobStatus(eMobStatus.Attack);
}
2025-02-13 04:40:04 +00:00
protected override void Check_Extra(eSkillExtraTiming timing)
{
2025-02-13 04:40:04 +00:00
base.Check_Extra(timing);
// Dictionary의 Key를 배열로 가져오기 (복사본을 사용하여 수정 방지)
var keys = new List<SkillListTableData>(dic_skill.Keys);
for (int i = 0; i < keys.Count; i++)
{
var temp = keys[i];
2025-02-18 01:55:30 +00:00
if (temp.e_SkillExtraType == eSkillExtraType.None) continue;
var skilltype = table_skilltypeconfig.Ins.Get_Data_orNull(temp.e_SkillExtraType);
2025-02-13 04:40:04 +00:00
if (skilltype.e_SkillExtraTiming == timing)
{
switch (skilltype.e_SkillExtraType)
{
case eSkillExtraType.Barrier: // 배리어 On
2025-05-14 05:01:30 +00:00
if (dic_skill[temp] > 0 && !IsDead())
{
var conditionHP = Get_MaxHP() * temp.f_ExtraValue1;
if (conditionHP >= Get_HP())
2025-02-26 02:42:03 +00:00
Show_Barrier(temp, skilltype, 10000);
}
break;
2025-02-13 04:40:04 +00:00
case eSkillExtraType.Reincarnation: // 부활 체크
if (n_Reincarnation > 0 && IsDead())
{
--n_Reincarnation;
On_Regen(true, temp.f_ExtraValue2);
2025-04-07 23:18:30 +00:00
InGameInfo.Ins.Show_Effect(skilltype.e_SkillEffect, Get_position(), null, skilltype.s_SkillEffectWhenOff);
2025-02-13 04:40:04 +00:00
Check_Battle();
}
break;
2025-02-13 22:49:30 +00:00
case eSkillExtraType.PerHPBuff_SPD:
2025-05-14 05:01:30 +00:00
if (!IsDead())
PerHPBuff(eCC.PerHPBuff_SPD, eCC.ATKSPD_Up, eCC.MOVSPD_Up, temp, skilltype);
2025-02-13 23:52:05 +00:00
break;
case eSkillExtraType.PerHPBuff_ADEF:
2025-05-14 05:01:30 +00:00
if (!IsDead())
PerHPBuff(eCC.PerHPBuff_ADEF, eCC.ATK_Mul, eCC.DEF_Mul, temp, skilltype);
2025-02-13 23:52:05 +00:00
break;
case eSkillExtraType.PerHPBuff_AMDEF:
2025-05-14 05:01:30 +00:00
if (!IsDead())
PerHPBuff(eCC.PerHPBuff_AMDEF, eCC.ATK_Mul, eCC.MDEF_Mul, temp, skilltype);
2025-02-13 22:49:30 +00:00
break;
2025-02-19 04:56:56 +00:00
case eSkillExtraType.PerHPBuff_AASPD:
2025-05-14 05:01:30 +00:00
if (!IsDead())
PerHPBuff(eCC.PerHPBuff_AASPD, eCC.ATK_Mul, eCC.ATKSPD_Up, temp, skilltype);
break;
case eSkillExtraType.PerHPBuff_AMSPD:
2025-05-14 05:01:30 +00:00
if (!IsDead())
PerHPBuff(eCC.PerHPBuff_AMSPD, eCC.ATK_Mul, eCC.MOVSPD_Up, temp, skilltype);
2025-02-19 04:56:56 +00:00
break;
2025-02-21 01:07:35 +00:00
case eSkillExtraType.Revive30:
if (!IsDead())
{
bool revive = false;
if (n_Reincarnation == 3 && Get_hpLostPercentage() >= temp.f_ExtraValue1)
revive = true;
else if (n_Reincarnation == 2 && Get_hpLostPercentage() >= temp.f_ExtraValue1 * 2f)
revive = true;
else if (n_Reincarnation == 1 && Get_hpLostPercentage() >= temp.f_ExtraValue1 * 3f)
revive = true;
if (revive)
{
if (!DSUtil.CheckNull(revive_co)) StopCoroutine(revive_co);
2025-02-21 01:20:47 +00:00
revive_co = StartCoroutine(Co_Revive(3f, temp.f_ExtraValue2, temp.f_ExtraValue3, skilltype));
2025-02-21 01:07:35 +00:00
}
}
else
n_Reincarnation = 0;
break;
}
}
}
}
2025-05-14 05:01:30 +00:00
ProjectileData pd_Barrier = new ProjectileData { e_SkillExtraType = eSkillExtraType.Barrier };
2025-02-26 02:42:03 +00:00
protected void Show_Barrier(SkillListTableData skilldata, SkillTypeConfigTableData skilltype, float lifeTime)
{
2025-05-14 05:01:30 +00:00
pd_Barrier.m_skillTypeConfigTable = skilltype;
2025-02-26 02:42:03 +00:00
dic_skill[skilldata] = 0;
dic_skillextra[skilltype.e_SkillExtraType] = true;
2025-05-14 05:01:30 +00:00
InGameInfo.Ins.Show_SkillTypeEffect(pd_Barrier, this, lifeTime,
2025-02-26 02:42:03 +00:00
effect =>
{
2025-04-07 23:18:30 +00:00
effect.Set_EffectwhenOff(skilltype.s_SkillEffectWhenOff);
2025-02-26 02:42:03 +00:00
if (!dic_CCEffect.ContainsKey(eCC.Barrier))
dic_CCEffect.Add(eCC.Barrier, null);
dic_CCEffect[eCC.Barrier] = effect;
dic_ccData[eCC.Barrier].TimeUpdate = true;
dic_ccData[eCC.Barrier].CCTime = lifeTime;
dic_ccData[eCC.Barrier].CCDmg = Get_MaxHP() * skilldata.f_ExtraValue2;
});
}
2025-02-21 01:07:35 +00:00
Coroutine revive_co;
2025-02-21 01:20:47 +00:00
IEnumerator Co_Revive(float revivetime, float nodmgtime, float dmg, SkillTypeConfigTableData skilltype)
2025-02-21 01:07:35 +00:00
{
--n_Reincarnation;
DeadStatus = true;
Play_Die();
2025-05-23 22:18:32 +00:00
var raisetime = 0.5f;
var showindigatetime = 0.5f;
yield return new WaitForSeconds(showindigatetime);
IndicatorInfo.Ins.Show_Indicator("Revive30_Indicator", Get_position(), revivetime - showindigatetime + raisetime);
2025-02-21 01:07:35 +00:00
2025-05-23 22:18:32 +00:00
yield return new WaitForSeconds(revivetime - showindigatetime);
// 무적 쉴드
NoDmgTime = nodmgtime + raisetime;
2025-04-07 23:18:30 +00:00
InGameInfo.Ins.Show_Effect(skilltype.e_SkillEffect, this, skilltype.e_EffectLocation, nodmgtime,
effect => { effect.Set_EffectwhenOff(skilltype.s_SkillEffectWhenOff); });
2025-02-21 01:20:47 +00:00
2025-05-23 22:18:32 +00:00
yield return new WaitForSeconds(raisetime);
2025-02-21 04:51:21 +00:00
Play_Idle();
DeadStatus = false;
2025-05-23 22:18:32 +00:00
ProjectileInfo.Ins.Shoot_Projectile("Projectile_Revive30", this, null, dmg, Get_position(), 2f);
2025-02-21 01:07:35 +00:00
}
2025-02-13 23:52:05 +00:00
void PerHPBuff(eCC skilltypecc, eCC buffcc1, eCC buffcc2, SkillListTableData temp, SkillTypeConfigTableData skilltype)
{
if (!dic_ccValue.ContainsKey(buffcc1)) dic_ccValue.Add(buffcc1, 0f);
if (!dic_ccValue.ContainsKey(buffcc2)) dic_ccValue.Add(buffcc2, 0f);
int perval1 = (int)(Get_hpLostPercentage() / temp.f_ExtraValue1);
if (temp.f_ExtraValue1 > 0) // val1이 0이 아니어야 함 (0으로 나누는 오류 방지)
{
dic_ccValue[buffcc1] = perval1 * temp.f_ExtraValue2;
dic_ccValue[buffcc2] = perval1 * temp.f_ExtraValue3;
}
if (perval1 > 0)
Show_TargetEffect_NoTime(skilltypecc, skilltype.e_SkillEffect, skilltype.e_EffectLocation);
}
2025-02-13 23:30:11 +00:00
void Show_TargetEffect_NoTime(eCC cc, string effectprefab, eEffectLocation location)
{
if (!dic_CCEffect.ContainsKey(cc) || !dic_CCEffect[cc].IsMyEffect(this))
InGameInfo.Ins.Show_Effect(effectprefab, this, location, 1000000,
effect =>
{
if (!dic_CCEffect.ContainsKey(cc))
dic_CCEffect.Add(cc, null);
dic_CCEffect[cc] = effect;
});
else if (!dic_CCEffect[cc].isActiveAndEnabled)
{
dic_CCEffect[cc].gameObject.SetActive(true);
dic_CCEffect[cc].Reset_Time(100000);
}
}
float Get_hpLostPercentage()
{
var maxHP = Get_MaxHP();
return (float)((maxHP - Get_HP()) / maxHP); // 체력 감소 비율 (0.0 ~ 1.0)
}
void Reset_Extra()
{
if (m_MonsterTableData.n_PassiveSkillID <= 0)
return;
var pSkill = table_skilllist.Ins.Get_Data_orNull(m_MonsterTableData.n_PassiveSkillID);
if (!dic_skill.ContainsKey(pSkill))
dic_skill[pSkill] = 0;
n_SummonCount = n_Reincarnation = 0;
list_summon.ForEach(f => f.Off());
2025-02-13 04:40:04 +00:00
switch (pSkill.e_SkillExtraType)
{
2025-02-13 04:40:04 +00:00
case eSkillExtraType.Barrier:
dic_skill[pSkill] = 1;
dic_skillextra[pSkill.e_SkillExtraType] = false;
2025-02-13 04:40:04 +00:00
// dic_ccData[eCC.Barrier]가 존재하는지 확인 후 초기화
if (dic_ccData.ContainsKey(eCC.Barrier))
dic_ccData[eCC.Barrier].CCDmg = 0;
2025-02-13 04:40:04 +00:00
// dic_CCEffect[eCC.Barrier]가 존재하는지 확인 후 제거
if (dic_CCEffect.ContainsKey(eCC.Barrier) && dic_CCEffect[eCC.Barrier].IsMyEffect(this))
dic_CCEffect[eCC.Barrier].Off_Imm();
break;
case eSkillExtraType.Reincarnation:
n_Reincarnation = (int)pSkill.f_ExtraValue1; // 부활 횟수
break;
2025-02-21 01:07:35 +00:00
case eSkillExtraType.Revive30:
n_Reincarnation = 3;
break;
}
}
2024-12-15 01:39:39 +00:00
public void Set_NoUpdate_byTool(MonsterTableData mobdata)
{
NoUpdate_byTool = true;
m_MonsterTableData = mobdata;
}
}