using CodeStage.AntiCheat.ObscuredTypes; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using Random = UnityEngine.Random; public class Actor : AddrHandleBase { [SerializeField] protected Animation m_anim; protected int m_Identity; // 0 pc, 1~9 mob protected bool isInit, isSetImage; protected Actor _Target; protected Actor m_Target { get { return _Target; } set { _Target = value; } } protected ObscuredBool CantSetTarget; protected ActorTableDataBase m_TableData; protected Dictionary dic_Card = new Dictionary(); protected ObscuredBool bStartBattle, bResurrectioning; protected HUD_HPShield m_HUD_HPShield; protected SelfDestructData m_SelfDestructData = new SelfDestructData(); protected eActorStatus ActorStatus; protected StatusConditionsListTableData m_AttackData; ObscuredDouble m_AttackCoolTime; protected List list_Specificity = new List(); Dictionary> dic_activeCondition = new Dictionary>(); protected ServerData m_ServerData; protected ActorStatInfo m_StatInfo; protected ProjectileData m_BaseAttackPD = new ProjectileData(); // 기본 공격 protected ActorStatInfo m_PDHPDmgStatInfo; protected ProjectileData m_PDHPDmg = new ProjectileData(); // 체력 비례 데미지 protected Dictionary dic_cardProjectile = new Dictionary(); protected Dictionary> dic_CardStatInfo = new Dictionary>(); protected ObscuredInt m_AttackCount /* 공격 횟수 */, m_AttackSuccessCount /* 공격 성공 횟수 */, m_AvoidCount /* 회피 횟수 */; protected ObscuredInt m_HitCount /* 맞은 횟수 */; protected ObscuredInt m_TotalAttackCount, m_TotalAttackSuccessCount, m_TotalAvoidCount; protected Dictionary dic_HitType = new Dictionary { { eAttackType.Melee, 0 }, { eAttackType.Range, 0 } }; protected Dictionary dic_StatusEffect = new Dictionary(); static List list_NoUpdateCC = new List // 업데이트 할 수 없는 CC기 { eStatusConditionsType.Stun, eStatusConditionsType.Freezing }; Dictionary dic_StatusEffectData = new Dictionary(); Dictionary> dic_ActiveConditionData = new Dictionary>(); #if UNITY_EDITOR private void Reset() { m_anim = GetComponent(); } #endif protected virtual void Awake() { } protected virtual void Update() { if (!bStartBattle || IsDead() || bResurrectioning || m_SelfDestructData.m_Status == eSelfDestructStatus.Soon) return; foreach (var item in dic_StatusEffect) item.Value.Update(); if (IsCC()) return; if (Get_AttackType() == eAttackType.Range && dic_StatusEffect[eStatusConditionsType.Blind].IsActive()) return; if (m_AttackCoolTime > 0) { m_AttackCoolTime -= Time.deltaTime; if (m_AttackCoolTime <= 0f) { m_AttackCoolTime = m_StatInfo.Get_TotalStat(eStat.AttackCoolTime); m_AttackCoolTime.RandomizeCryptoKey(); if (m_Target && !m_Target.IsDead()) Play_Attack(); else Find_Target(); } } foreach (var item in dic_Card) item.Value.Update(); } void Init() { for (eCardType i = 0; i < eCardType.Max; i++) { dic_CardStatInfo.Add(i, new List()); for (int j = 0; j < table_cardlist.Ins.Get_Data(i).n_ProjectileCount; j++) dic_CardStatInfo[i].Add(new ActorStatInfo(this, false)); } for (eStatusConditionsType i = 0; i < eStatusConditionsType.Max; i++) dic_StatusEffect.Add(i, new StatusEffectData()); } public virtual void Set(int identity, ActorTableDataBase actordata, HUD_HPShield hUD_HPShield, ServerData sdata = null) { if (!isInit) { isInit = true; Init(); } gameObject.SetActive(true); m_Identity = identity; isSetImage = false; ActorStatus = eActorStatus.Idle; m_ServerData = sdata; m_TableData = actordata; m_HUD_HPShield = hUD_HPShield; m_StatInfo = MyValue.Get_ActorStatInfo(this, m_TableData); m_HUD_HPShield.Set(m_StatInfo); Set_Battle(false); bResurrectioning = false; bResurrectioning.RandomizeCryptoKey(); m_SelfDestructData.Set_Status(eSelfDestructStatus.None); dic_Card.Clear(); m_StatInfo.Clear_BuffDebuff(); Set_Equipment(); Set_Specificity(); m_AttackCoolTime = m_StatInfo.Get_TotalStat(eStat.AttackCoolTime); } public ServerData Get_ServerData() { return m_ServerData; } public virtual void Set(int index) { } public virtual void ActorSet(ActorSettingData setdata) { if (gameObject.activeSelf) StartCoroutine(Co_ActorSet(setdata)); } IEnumerator Co_ActorSet(ActorSettingData setdata) { if (setdata != null) { while (!bStartBattle) yield return null; if (setdata.PreemptiveStrike) Set_Battle_PreemptiveStrike(); if (setdata.StunTime > 0f) Set_StatusEffect(eStatusConditionsType.Stun, setdata.StunTime); } } public virtual void Set_TargetObj(bool active) { } public void Init_IngameDatas() { // 탐험 입장 시 최초 한 번 실행 foreach (var item in dic_Card) item.Value.Init_IngameDatas(); m_TotalAttackCount = 0; m_TotalAttackCount.RandomizeCryptoKey(); m_TotalAvoidCount = 0; m_TotalAvoidCount.RandomizeCryptoKey(); m_TotalAttackSuccessCount = 0; m_TotalAttackSuccessCount.RandomizeCryptoKey(); dic_HitType[eAttackType.Melee] = 0; dic_HitType[eAttackType.Melee].RandomizeCryptoKey(); dic_HitType[eAttackType.Range] = 0; dic_HitType[eAttackType.Range].RandomizeCryptoKey(); } public void Init_EveryMeetMonster() { foreach (var item in dic_Card) item.Value.Init_EveryMeetMonster(); m_AttackCount = 0; m_AttackCount.RandomizeCryptoKey(); m_AttackSuccessCount = 0; m_AttackSuccessCount.RandomizeCryptoKey(); m_HitCount = 0; m_HitCount.RandomizeCryptoKey(); m_AvoidCount = 0; m_AvoidCount.RandomizeCryptoKey(); } public void Set_Trasform(Vector3 pos, float scale) { m_TableData = null; transform.position = pos; transform.localScale = Vector3.one * scale; } public void Set_Battle(bool battle) { if (m_StatInfo == null || m_TableData == null) return; if (battle && SelectCardUI.Ins.IsActive()) return; bStartBattle = battle; bStartBattle.RandomizeCryptoKey(); if (bStartBattle) Find_Target(); } public virtual void Del_Target() { if (m_Target != null) { } m_Target = null; } public virtual void Set_Target(Actor target) { if (isCantSetTarget()) return; m_Target = target; MonsterNodeControler.Ins.Set_TargetUI(m_Target); } public virtual bool isCantSetTarget() { return CantSetTarget; } public Actor Get_Target() { return m_Target; } public void Find_Target() { m_Target = InGameInfo.Ins.Get_Enemy_orNull(m_TableData.m_Role, isCantSetTarget()); if (IsRole(eRole.PC)) MonsterNodeControler.Ins.Set_TargetUI(m_Target); } public virtual Vector3 Get_World_Position(eEffectPivot pivot = eEffectPivot.Center) { return transform.position; } public ActorStatInfo Get_ActorStatInfo() { return m_StatInfo; } public bool IsRole(eRole role) { return m_TableData.m_Role == role; } public ActorTableDataBase Get_Data() { return m_TableData; } public virtual eAttackType Get_AttackType() { return m_TableData.Get_AttackType(); } public void Set_HUD(bool active) { if (m_HUD_HPShield != null) { if (active) m_HUD_HPShield.Set_Init(this); else m_HUD_HPShield.gameObject.SetActive(active); } } public void Set_HUD() { if (m_HUD_HPShield && m_StatInfo != null) m_HUD_HPShield.Set(m_StatInfo); } public bool IsBoss() { return m_TableData.IsBoss(); } public virtual int Get_Identity() { return m_Identity; } public virtual int Get_MobIndex() { return 0; } public virtual void Set_MobIndex_byLineChange() { } public SelfDestructData Get_SelfDestructData() { return m_SelfDestructData; } protected virtual float Get_ProjectileSpeed() { return 0f; } public CardSkillData Get_CardSkillData_orNull(eCardType cardType) { return dic_Card.ContainsKey(cardType) ? dic_Card[cardType] : null; } #region 배틀 public virtual void Set_Line(eMobBattlePos eline) { } public virtual eMobBattlePos Get_Line() { return eMobBattlePos.Backline; } public virtual bool IsFrontLine() { return false; } public virtual bool IsMiddleLine() { return false; } public virtual bool IsBackLine() { return false; } public virtual bool IsMobLine(eMobBattlePos eline) { return false; } public bool IsDead() { return IsInvalid() || m_StatInfo == null || m_StatInfo.Get_TotalStat(eStat.HP) <= 0; } public bool IsInvalid() { return m_TableData == null; } public bool IsSet() { return isSetImage; } public virtual bool IsShield() { return false; } public int Get_TotalAttackCount() { return m_TotalAttackCount; } public int Get_AttackCount() { return m_AttackCount; } public void Add_CardSkill(CardListTableData data) { var skilldata = new CardSkillData(); dic_Card.Add(data.e_CardType, skilldata); skilldata.Add(this, data); var cardtype = eCardType.G1_MaxShieldUpOnSkillGain; if (dic_Card.ContainsKey(cardtype)) if (data.e_CardGrade == eGrade.Common || data.e_CardGrade == eGrade.UnCommon) { m_StatInfo.Set_Stat(true, eStat.MaxShield, dic_Card[cardtype].m_Data.Get_IntValue1()); Refresh_PCUI(); } OnEvent_RunSkillCard(data.e_CardType); } bool Can_RunCard(eCardType cardtype, eCardType addcard) { return dic_Card.ContainsKey(cardtype) && (addcard == eCardType.Max || cardtype == addcard); } void Counting_onActiveCondition(eActiveConditions condition, int arg1, int arg2) { if (dic_ActiveConditionData.ContainsKey(condition)) { for (int i = 0; i < dic_ActiveConditionData[condition].Count; i++) dic_ActiveConditionData[condition][i].Counting(arg1, arg2); } } public void Get_Dmg(int dmg, ProjectileData pdData = null) { int hitter_dmg = dmg; var huddmg = IngameUIManager.Ins.Get_HUD_Dmg(); var isCri = pdData != null ? pdData.isCri : false; bool ischeat_mujuck = false; var my_shield = (int)m_StatInfo.Get_TotalStat(eStat.Shield); if (my_shield > 0) { // 쉴드 우선 계산 if (my_shield >= hitter_dmg) { my_shield -= hitter_dmg; hitter_dmg = 0; } else { hitter_dmg -= my_shield; my_shield = 0; var cardtype = eCardType.G1_HealHpOnShieldBreak; if (dic_Card.ContainsKey(cardtype)) { Heal(eHealType.Normal, dic_Card[cardtype].m_Data.Get_FloatValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); } } m_HUD_HPShield.Hit_Shield(); if (!ischeat_mujuck) m_StatInfo.Set_Stat(eStat.Shield, my_shield); OnEvent_MyShield_Hit(pdData); if (dic_Card.ContainsKey(eCardType.G1_NoSimultaneousHpShieldLoss)) hitter_dmg = 0; } if (hitter_dmg > 0) { // 쉴드를 깍고도 남은 경우 if (!ischeat_mujuck) m_StatInfo.Set_Stat(false, eStat.HP, hitter_dmg); huddmg.Set(isCri, false, hitter_dmg, Get_World_Position()); if (IsDead()) { var cardtype = eCardType.G5_ReviveOnDeath; if (dic_Card.ContainsKey(cardtype)) { if (DSUtil.RandomTrue(dic_Card[cardtype].m_Data.Get_FloatValue1())) { Set_Buff(true, eStat.Resurrection, 1); Set_Buff(eStat.Resurrection_Shield, 1); Set_Buff(eStat.Resurrection_Heal, 1); } } cardtype = eCardType.G1_AutoUsePotionOnDeath; if (dic_Card.ContainsKey(cardtype) && m_StatInfo.Get_TotalStat(eStat.Potion) > 0) { Use_Potion(true, 10); // 테스트 : 물약 회복량 return; } if (dic_activeCondition.ContainsKey(eActiveConditions.Die_Self)) { for (int i = 0; i < dic_activeCondition[eActiveConditions.Die_Self].Count; i++) { var temp = dic_activeCondition[eActiveConditions.Die_Self][i]; if (temp.m_TData.e_StatusConditionsType == eStatusConditionsType.Resurrection) { // 부활 데이터 저장 Set_Buff(true, eStat.Resurrection, temp.m_TData.Get_Rate_orValue()); Set_Buff(temp.m_TData.e_Stat1, temp.m_TData.Get_StatValue1()); Set_Buff(temp.m_TData.e_Stat2, temp.m_TData.Get_StatValue2()); // 부활은 더이상 못하게 삭제 dic_activeCondition[eActiveConditions.Die_Self].RemoveAt(i); break; } } } if (m_StatInfo.Get_BuffStat(eStat.Resurrection) > 0) { Set_Buff(false, eStat.Resurrection, 1); Set_Buff(eStat.Resurrection_Shield, 1); Set_Buff(eStat.Resurrection_Heal, 1); StartCoroutine(Co_Resurrection()); } else { Set_Die(pdData); MonsterNodeControler.Ins.Check_LineAllDead(); if (IsRole(eRole.Mob)) { Set_HUD(false); } else if (IsRole(eRole.PC)) DefeatUI.Ins.Set(); pdData?.Hitter.OnEvent_Kill(this); pdData?.Hitter.Find_Target(); } m_SelfDestructData.Stop(this); } else { if (m_SelfDestructData.m_Status == eSelfDestructStatus.Check_Rate) { // 자폭 가능 시, 얻어맞으면 value 확률로 자폭하기 if (DSUtil.RandomTrue(m_SelfDestructData.m_Data.m_TData.Get_StatValue1())) m_SelfDestructData.co_SelfDestruct = StartCoroutine(Co_Selfdestruct()); } if (dic_Card.ContainsKey(eCardType.G1_MaxDodgeWhenHpBelow)) { var card = dic_Card[eCardType.G1_MaxDodgeWhenHpBelow]; if (m_StatInfo.Get_BuffStat(eStat.Avoid_G1_MaxDodgeWhenHpBelow) <= 0 && m_StatInfo.Get_TotalStat(eStat.HP) <= card.m_Data.Get_IntValue1()) { Set_Buff(eStat.Avoid_G1_MaxDodgeWhenHpBelow, 0.9); Refresh_PCUI(); } } } } else huddmg.Set(isCri, true, dmg, Get_World_Position()); m_HUD_HPShield.Set(m_StatInfo); Play_Hit(); OnEvent_ActiveConditions(); OnEvent_GetDmg(pdData); } public void Get_Dmg(ProjectileData pdData) { if (IsDead()) return; switch (pdData.e_CardType) { case eCardType.G1_CastReaperOnLevelUp: case eCardType.G1_CastReaperOnNthCrit: Get_Dmg(9999, pdData); return; } Check_Specificity(eActiveConditions.Hit_PreemptiveStrike, pdData); if (pdData.e_AttackType == eAttackType.Range && dic_Card.ContainsKey(eCardType.G5_RangedDamageRandomReflect)) Reflect_Projectile(eCardType.G5_RangedDamageRandomReflect, pdData); var huddmg = IngameUIManager.Ins.Get_HUD_Dmg(); if (dic_StatusEffect[eStatusConditionsType.Invincibility_Time].IsActive()) { huddmg.Set(false, true, -5, Get_World_Position()); return; } var dmgimmune = (int)m_StatInfo.Get_TotalStat(eStat.Dmg_Immune); if (dmgimmune > 0) { --dmgimmune; m_StatInfo.Set_Buff(eStat.Dmg_Immune, dmgimmune); huddmg.Set(false, true, -5, Get_World_Position()); if (dic_StatusEffectData.ContainsKey(eStatusConditionsType.Invincibility_Count)) dic_StatusEffectData[eStatusConditionsType.Invincibility_Count].Counting(dmgimmune, 0); return; } var hitterstat = pdData.m_HitterStat; if (IsShield()) { huddmg.Set(false, true, -5, Get_World_Position()); return; } if (pdData.Hitter.Get_TotalAttackCount() == 1 && hitterstat.Get_BuffStat(eStat.MyRangeAttackAvoid) > 0) { hitterstat.Set_Buff(eStat.MyRangeAttackAvoid, 0); Run_AvoidStatus(pdData, huddmg); return; } var adddmg_1time = (int)hitterstat.Get_BuffStat(eStat.AddDmg_1Time); hitterstat.Set_Buff(eStat.AddDmg_1Time, 0); var adddmgmul_1time = hitterstat.Get_BuffStat(eStat.AddDmgMul_1Time); hitterstat.Set_Buff(eStat.AddDmgMul_1Time, 0); var hitterAttacktype = pdData.e_AttackType; bool HitterisMob = pdData.Hitter.IsRole(eRole.Mob); var isHit = HitterisMob || hitterAttacktype == eAttackType.Skill; if (!isHit) { // 빗나감 체크는 PC만 var avoid = m_StatInfo.Get_TotalStat(hitterAttacktype == eAttackType.Melee ? eStat.Avoid_Melee : eStat.Avoid_Range); isHit = DSUtil.RandomTrue(hitterstat.Get_TotalStat(eStat.HitRate) / (avoid * 3.69)); } if (!isHit) { // 빗나감 pdData.Hitter.OnEvent_NoMiss_Hitter(pdData, false); huddmg.Set(false, true, -1, Get_World_Position()); return; } if (HitterisMob && IsRole(eRole.PC)) { // PC 회피율 적용 var avoid = m_StatInfo.Get_TotalStat(hitterAttacktype == eAttackType.Melee ? eStat.Avoid_Melee : eStat.Avoid_Range); if (DSUtil.RandomTrue(avoid)) { // 회피 Run_AvoidStatus(pdData, huddmg); return; } } if (hitterAttacktype == eAttackType.Melee && m_StatInfo.Get_TotalStat(eStat.Shield) > 0 && dic_Card.ContainsKey(eCardType.G2_NegateMeleeDamageWithShield) && DSUtil.RandomTrue(dic_Card[eCardType.G2_NegateMeleeDamageWithShield].m_Data.Get_FloatValue2())) { // 근접 무효화 체크 huddmg.Set(false, true, -3, Get_World_Position()); return; } if (hitterAttacktype == eAttackType.Range && m_StatInfo.Get_TotalStat(eStat.Shield) > 0 && dic_Card.ContainsKey(eCardType.G2_NegateRangedAttackWithShield) && DSUtil.RandomTrue(dic_Card[eCardType.G2_NegateRangedAttackWithShield].m_Data.Get_FloatValue2())) { // 원거리 무효화 체크 huddmg.Set(false, true, -4, Get_World_Position()); return; } var adddmg_mul = 1f; var FirstAttackTripleDamage = pdData.Hitter.Get_CardSkillData_orNull(eCardType.G5_FirstAttackTripleDamage); if (FirstAttackTripleDamage != null && m_HitCount == 0 && m_AvoidCount == 0) adddmg_mul = FirstAttackTripleDamage.m_Data.Get_FloatValue1(); if (m_StatInfo.Get_BuffStat(eStat.AvoidAll_Count) > 0) { m_StatInfo.Set_Buff(eStat.AvoidAll_Count, m_StatInfo.Get_BuffStat(eStat.AvoidAll_Count) - 1); Run_AvoidStatus(pdData, huddmg); return; } var hitter_dmg = (int)(hitterstat.Get_Damage() * adddmg_mul); hitter_dmg += adddmg_1time; if (adddmgmul_1time > 0f) hitter_dmg = (int)(hitter_dmg * adddmgmul_1time); if (IsMiddleLine() && hitterstat.Get_BuffStat(eStat.AddDmgMul_MiddleLine) > 0) hitter_dmg = (int)(hitter_dmg * hitterstat.Get_BuffStat(eStat.AddDmgMul_MiddleLine)); if (pdData.isCri) { var hittercard = pdData.Hitter.Get_CardSkillData_orNull(eCardType.G1_ThirdCritDamage); if (hittercard != null) hittercard.Add_UseCountACC(1, () => { hitterstat.Set_Buff(eStat.AddCriDmg_1Time, hittercard.m_Data.Get_FloatValue2()); }); hitter_dmg = (int)(hitter_dmg * hitterstat.Get_TotalStat(eStat.CriDmg)); Refresh_PCUI(); } #region 데미지 감소 (절대값) var reducedmg = 0; if (hitterAttacktype == eAttackType.Melee) reducedmg = (int)m_StatInfo.Get_TotalStat(eStat.ReduceMeeleDmg); else if (hitterAttacktype == eAttackType.Range) { reducedmg = (int)m_StatInfo.Get_TotalStat(eStat.ReduceRangeDmg); if (dic_Card.ContainsKey(eCardType.G3_RangedHitNextAttackDamageUp)) m_StatInfo.Set_Buff(true, eStat.AddDmgMul_1Time, dic_Card[eCardType.G3_RangedHitNextAttackDamageUp].m_Data.Get_FloatValue2()); } reducedmg += (int)m_StatInfo.Get_TotalStat(eStat.ReduceDmg); hitter_dmg -= reducedmg; #endregion #region 데미지 감소 (%) var reducedmg_rate = m_StatInfo.Get_TotalStat(hitterAttacktype == eAttackType.Melee ? eStat.ReduceMeeleDmg_Mul : eStat.ReduceRangeDmg_Mul); if (hitterAttacktype == eAttackType.Range && m_StatInfo.Get_TotalStat(eStat.Shield) > 0 && dic_Card.ContainsKey(eCardType.G2_ReduceRangedDamageWithShield)) reducedmg_rate += dic_Card[eCardType.G2_ReduceRangedDamageWithShield].m_Data.Get_FloatValue2(); hitter_dmg -= (int)(hitter_dmg * reducedmg_rate); #endregion if (hitter_dmg < 0) hitter_dmg = 1; var dmg = hitter_dmg; if (m_StatInfo.Get_TotalStat(eStat.Shield) > 0 && dic_Card.ContainsKey(eCardType.G4_ShieldedDamageReduction)) dmg -= (int)(dmg * dic_Card[eCardType.G4_ShieldedDamageReduction].m_Data.Get_FloatValue2()); if (hitterstat.Get_Stat(eStat.FixedDmg) > 0) dmg = hitter_dmg = (int)hitterstat.Get_Stat(eStat.FixedDmg); else if (pdData.isCri) pdData.Hitter.OnEvent_Cri(pdData, dmg); Get_Dmg(dmg, pdData); ++m_HitCount; m_HitCount.RandomizeCryptoKey(); pdData.Hitter.OnEvent_NoMiss_Hitter(pdData, true); OnEvent_Hit(pdData, this, dmg); } void Reflect_Projectile(eCardType cardType, ProjectileData pdData, bool randomTarget = true, bool usecardprojectile = false) { var pd = Get_CardProjectileData(cardType); pdData.Copy(pd); pd.e_CardType = cardType; if (usecardprojectile) { pd.s_Projectile = dic_Card[cardType].m_Data.s_Projectile; pd.e_AttackType = dic_Card[cardType].m_Data.e_ProjectileAttackType; } pd.m_Role = m_TableData.m_Role; if (randomTarget) pd.Target = InGameInfo.Ins.Get_RandomEnemy_orNull(pd.m_Role); else pd.Target = pd.Hitter; pd.Hitter = this; if (pd.Target != null) ProjectileMgr.Ins.Shoot_Projectile(pd, Get_World_Position(), pd.Target.Get_World_Position(), pd.Target, actor => { actor.Get_Dmg(pd); }); } void Reflect_Projectile(ProjectileData pdData, int fixeddmg) { var pd = new ProjectileData(); pdData.Copy(pd); pd.m_Role = m_TableData.m_Role; pd.Target = pd.Hitter; pd.Hitter = this; pd.m_HitterStat.Set_Stat(eStat.FixedDmg, fixeddmg); if (pd.Target != null) ProjectileMgr.Ins.Shoot_Projectile(pd, Get_World_Position(), pd.Target.Get_World_Position(), pd.Target, actor => { actor.Get_Dmg(pd); }); } protected virtual void Set_Die(ProjectileData pdData) { var isCurse = IsCurse(); foreach (var item in dic_StatusEffect) item.Value.Off(); if (isCurse) { Set_StatusEffect(eStatusConditionsType.Curse_Explosion, 3f, true); if (m_PDHPDmgStatInfo == null) m_PDHPDmgStatInfo = new ActorStatInfo(this, false); m_PDHPDmgStatInfo.Set_Stat(eStat.Attack_Min, m_StatInfo.Get_TotalStat(eStat.MaxHP) * 0.5); m_PDHPDmgStatInfo.Set_Stat(eStat.Attack_Max, m_StatInfo.Get_TotalStat(eStat.MaxHP) * 0.5); m_PDHPDmgStatInfo.Set_Stat(eStat.HitRate, m_StatInfo.Get_TotalStat(eStat.HitRate)); m_PDHPDmg.Set("", Get_Data().m_Role, eAttackType.Melee, this, m_PDHPDmgStatInfo); var mobs = InGameInfo.Ins.Get_Mobs_4Nearby(Get_MobIndex()); for (int i = 0; i < mobs.Length; i++) mobs[i].Get_Dmg(m_PDHPDmg); } } IEnumerator Co_Selfdestruct() { var data = m_SelfDestructData.m_Data; m_SelfDestructData.Set_Status(eSelfDestructStatus.Soon); m_SelfDestructData.eff_SelfDestruct.Set(data.m_sclData.s_SkillEffect, Get_World_Position(), 3f); yield return new WaitForSeconds(3f); EffectMgr.Ins.Show_Effect($"{data.m_sclData.s_SkillEffect}_exp", Get_World_Position(), 1f); Get_Dmg((int)m_StatInfo.Get_TotalStat(eStat.HP)); // 본인 자폭 // 정인호 : 자폭 데미지 주기 (플레이어 + 십자) var dmg = (int)(m_StatInfo.Get_Damage() * data.m_TData.Get_StatValue2()); var pc = InGameInfo.Ins.Get_Enemy_orNull(eRole.Mob); pc.Get_Dmg(dmg); EffectMgr.Ins.Show_Effect($"{data.m_sclData.s_SkillEffect}_exp", pc.Get_World_Position(), 1f); var mobs = InGameInfo.Ins.Get_Mobs_4Nearby(Get_MobIndex()); for (int i = 0; i < mobs.Length; i++) { mobs[i].Get_Dmg(dmg); EffectMgr.Ins.Show_Effect($"{data.m_sclData.s_SkillEffect}_exp", mobs[i].Get_World_Position(), 1f); } } IEnumerator Co_Resurrection() { bResurrectioning = true; bResurrectioning.RandomizeCryptoKey(); EffectMgr.Ins.Show_Effect(table_StatusConditionsList.Ins.Get_Data_orNull(eStatusConditionsType.Resurrection).s_SkillEffect, Get_World_Position(), 3f); yield return new WaitForSeconds(3f); bResurrectioning = false; bResurrectioning.RandomizeCryptoKey(); Heal_Shield((float)m_StatInfo.Get_BuffStat(eStat.Resurrection_Shield)); var rh = m_StatInfo.Get_BuffStat(eStat.Resurrection_Heal); if (dic_Card.ContainsKey(eCardType.G1_AngelFeatherHeal)) rh += rh * dic_Card[eCardType.G1_AngelFeatherHeal].m_Data.Get_FloatValue2(); Heal(eHealType.Normal, (float)rh); } public virtual void Shoot_Projectile() { if (m_Target == null) return; if (Get_AttackCount() == 1 && Get_AttackType() == eAttackType.Range) { var card = m_Target.Get_CardSkillData_orNull(eCardType.G1_RangedFirstAttackSelfDamage); if (card != null) { Shoot_BaseProjectile(this); return; } } Shoot_Projectile(m_Target, m_BaseAttackPD, target => { OnEvent_ShootProjectile(m_BaseAttackPD); target.Get_Dmg(m_BaseAttackPD); ActorStatus = eActorStatus.Idle; }); } public void Shoot_BaseProjectile(Actor target) { Shoot_Projectile(target, m_BaseAttackPD, targetactor => { OnEvent_ShootProjectile(m_BaseAttackPD); targetactor.Get_Dmg(m_BaseAttackPD); ActorStatus = eActorStatus.Idle; }); } public void Shoot_AddProjectiles(eCardType cardtype, params Actor[] fixedTarget) { if (dic_Card.ContainsKey(cardtype)) Shoot_AddProjectiles(dic_Card[cardtype], fixedTarget); } public void Shoot_AddProjectiles(CardSkillData card, params Actor[] fixedTarget) { var loop = card.m_Data.n_ProjectileCount > fixedTarget.Length ? card.m_Data.n_ProjectileCount : fixedTarget.Length; for (int i = 0; i < loop; i++) { var cardtype = card.m_Data.e_CardType; var attacktype = card.m_Data.e_ProjectileAttackType; var delaytime = card.m_Data.f_ProjectileDelayTime; var pd = Get_CardProjectileData(i, card); pd.Set(card.m_Data.s_Projectile, m_TableData.m_Role, attacktype, this, dic_CardStatInfo[cardtype][i], cardtype); if (fixedTarget.Length == 0) { Shoot_Projectile_Delay(MonsterNodeControler.Ins.Get_RandomTarget(), pd, target => { target.Get_Dmg(pd); }, delaytime * i); } else { var targetLocal = fixedTarget.Length > i ? fixedTarget[i] : fixedTarget[0]; // <-- 중요: 로컬로 복사 Shoot_Projectile_Delay(targetLocal, pd, target => { target.Get_Dmg(pd); }, delaytime * i); } } } void Shoot_Projectile(Actor target, ProjectileData pd, Action act_end) { if (target == null) return; pd.Set(target, Get_ProjectileSpeed()); var startpos = Get_World_Position(); if (IsRole(eRole.PC)) { var mobindex = target.Get_MobIndex(); if (mobindex < 0) mobindex += 3; // 라인 교체로 내려갔을 수도 있으므로 기존 위치로 잡음 switch (mobindex) { case 0: case 3: case 6: startpos = InGameInfo.Ins.tfs_ProjectileStart[0].position; break; case 1: case 4: case 7: startpos = InGameInfo.Ins.tfs_ProjectileStart[1].position; break; case 2: case 5: case 8: startpos = InGameInfo.Ins.tfs_ProjectileStart[2].position; break; } } ProjectileMgr.Ins.Shoot_Projectile(pd, startpos, target.Get_World_Position(), target, act_end); } void Shoot_Projectile_Delay(Actor target, ProjectileData pd, Action act_end, float delay) { if (target == null || target.IsDead() || target.Get_MobIndex() < 0) return; StartCoroutine(Co_ProjectileDelay(target, pd, act_end, delay)); } IEnumerator Co_ProjectileDelay(Actor target, ProjectileData pd, Action act_end, float delay) { yield return new WaitForSeconds(delay); Shoot_Projectile(target, pd, act_end); } public ProjectileData Get_BaseProjectileData() { return m_BaseAttackPD; } ProjectileData Get_CardProjectileData(eCardType cardtype) { if (!dic_cardProjectile.ContainsKey(cardtype)) dic_cardProjectile.Add(cardtype, new ProjectileData()); return dic_cardProjectile[cardtype]; } ProjectileData Get_CardProjectileData(int asinfoindex, CardSkillData card) { var cardtype = card.m_Data.e_CardType; if (dic_CardStatInfo[cardtype].Count <= asinfoindex) dic_CardStatInfo[cardtype].Add(new ActorStatInfo(this, false)); var asinfo = dic_CardStatInfo[cardtype][asinfoindex]; asinfo.Clear_All(); asinfo.Set_Stat(eStat.Cri, m_StatInfo.Get_TotalStat(eStat.Cri)); asinfo.Set_Stat(eStat.CriDmg, m_StatInfo.Get_TotalStat(eStat.CriDmg)); asinfo.Set_Stat(eStat.HitRate, m_StatInfo.Get_TotalStat(eStat.HitRate)); if (card.m_Data.n_UseDmg == 1) { asinfo.Set_Stat(eStat.Attack_Min, m_StatInfo.Get_TotalStat(eStat.Attack_Min) * card.m_Data.Get_FloatValue2()); asinfo.Set_Stat(eStat.Attack_Max, m_StatInfo.Get_TotalStat(eStat.Attack_Max) * card.m_Data.Get_FloatValue2()); } else { asinfo.Set_Stat(eStat.Attack_Min, card.m_Data.Get_IntValue1()); asinfo.Set_Stat(eStat.Attack_Max, card.m_Data.Get_IntValue1()); } // PC 버프도 넘겨야 하나? 일단 안 넘김 //m_StatInfo.Set_BuffDebuff(asinfo); // 장비 능력치 추가 asinfo.Set_Stat(true, eStat.Attack_Min, m_StatInfo.Get_TotalStat(eStat.SkillDamageIncrease)); asinfo.Set_Stat(true, eStat.Attack_Max, m_StatInfo.Get_TotalStat(eStat.SkillDamageIncrease)); var amin = (int)(asinfo.Get_TotalStat(eStat.Attack_Min) * m_StatInfo.Get_TotalStat(eStat.SkillDamageIncrease_Mul)); asinfo.Set_Stat(true, eStat.Attack_Min, amin); var amax = (int)(asinfo.Get_TotalStat(eStat.Attack_Max) * m_StatInfo.Get_TotalStat(eStat.SkillDamageIncrease_Mul)); asinfo.Set_Stat(true, eStat.Attack_Max, amax); //////////////////// return Get_CardProjectileData(cardtype); } public void Shoot_Projectile_FixedDmg(eCardType cardtype, int fixedDmg, params Actor[] targets) { if (dic_Card.ContainsKey(cardtype)) Shoot_Projectile_FixedDmg(cardtype, dic_Card[cardtype].m_Data.s_Projectile, fixedDmg, targets); } public void Shoot_Projectile_FixedDmg(eCardType cardtype, string projectile, int fixedDmg, params Actor[] targets) { for (int i = 0; i < targets.Length; i++) { if (dic_CardStatInfo[cardtype].Count <= i) dic_CardStatInfo[cardtype].Add(new ActorStatInfo(this, false)); var asinfo = dic_CardStatInfo[cardtype][i]; asinfo.Clear_All(); asinfo.Set_Stat(eStat.FixedDmg, fixedDmg); asinfo.Set_Stat(eStat.HitRate, m_StatInfo.Get_TotalStat(eStat.HitRate)); var pd = Get_CardProjectileData(cardtype); pd.Set(projectile, m_TableData.m_Role, eAttackType.Melee, this, asinfo); Shoot_Projectile(targets[i], pd, targetlast => { targetlast.Get_Dmg(pd); }); } } /// /// 신비한 폭발 쏘기 /// void Shoot_MysticExplosion(int asinfoindex, CardSkillData card) { var pd = Get_CardProjectileData(asinfoindex, card); var cardtype = card.m_Data.e_CardType; pd.Set(card.m_Data.s_Projectile, m_TableData.m_Role, card.m_Data.e_ProjectileAttackType, this, dic_CardStatInfo[cardtype][asinfoindex], cardtype); var pos = InGameInfo.Ins.tfs_ProjectileStart[3].position; ProjectileMgr.Ins.Shoot_Projectile(pd, pos, pos, null, null); var enemies = InGameInfo.Ins.Get_LineMobs(eMobBattlePos.Frontline, eMobBattlePos.Middleline); for (int i = 0; i < enemies.Count; i++) enemies[i].Get_Dmg(pd); } void Shoot_Curse_RandomTarget() { var target = InGameInfo.Ins.Get_RandomEnemy_orNull(Get_Data().m_Role); if (target) target.Set_StatusEffect(eStatusConditionsType.Curse, 999999f); } #endregion #region 상태 실행 void Run_AvoidStatus(ProjectileData pdData, HUD_Dmg huddmg) { Play_Evasion(); huddmg.Set(false, true, -2, Get_World_Position()); pdData.Hitter.OnEvent_NoMiss_Hitter(pdData, false); OnEvent_Avoid(pdData); } #endregion #region 배틀 이벤트 public void OnEvent_AfterLineChange() { // 이벤트 실행 타이밍 : 라인 체인지 직후 if (m_StatInfo != null && m_StatInfo.Get_BuffStat(eStat.PreemptiveStrike) > 0) m_AttackCoolTime = Time.deltaTime; } public void OnEvent_RunSkillCard(eCardType addcard = eCardType.Max) { // 이벤트 실행 타이밍 : 최초, 카드 추가시, 라인 체인지 직후 // Can_RunCard : 항싱 실행 여부 체크도 포함 // Can_RunCard 체크가 아닌 경우 : 카드 획득 시 실행 여부만 체크 (한 번만 실행) var cardtype = eCardType.G5_AllRangedEnemiesBlindIfBackline; if (Can_RunCard(cardtype, addcard)) { var enemies = InGameInfo.Ins.Get_AllEnemies(Get_Data().m_Role); for (int i = 0; i < enemies.Count; i++) { var data = enemies[i].Get_Data(); if (data != null && enemies[i].IsMiddleLine() && data.Get_AttackType() == eAttackType.Range && !enemies[i].IsCC(eStatusConditionsType.Blind)) enemies[i].Set_StatusEffect(eStatusConditionsType.Blind, dic_Card[cardtype].m_Data.Get_FloatValue3()); } } cardtype = eCardType.G1_MeleeEnemiesAttackSelfChance; if (Can_RunCard(cardtype, addcard)) { var card = dic_Card[cardtype]; var enemies = InGameInfo.Ins.Get_LineMobs(eMobBattlePos.Frontline); for (int i = 0; i < enemies.Count; i++) { if (enemies[i].Get_AttackType() == eAttackType.Melee && DSUtil.RandomTrue(card.m_Data.Get_FloatValue2())) enemies[i].Shoot_BaseProjectile(enemies[i]); } } cardtype = eCardType.G1_InstantCastMysticExplosion; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) Shoot_MysticExplosion(1, dic_Card[cardtype]); cardtype = eCardType.G1_HolyDamageOnMeleeFrontAppear; if (Can_RunCard(cardtype, addcard)) { var enemies = InGameInfo.Ins.Get_AllEnemies(Get_Data().m_Role); for (int i = 0; i < enemies.Count; i++) { if (enemies[i].IsDead()) continue; var data = enemies[i].Get_Data(); if (data != null && enemies[i].IsFrontLine() && data.Get_AttackType() == eAttackType.Melee) Shoot_AddProjectiles(dic_Card[cardtype], enemies[i]); } } cardtype = eCardType.G1_RangedSpawnMagicMissile; if (Can_RunCard(cardtype, addcard)) { var enemies = InGameInfo.Ins.Get_AllEnemies(Get_Data().m_Role); for (int i = 0; i < enemies.Count; i++) { if (enemies[i].IsDead()) continue; var data = enemies[i].Get_Data(); if (data != null && data.Get_AttackType() == eAttackType.Range && DSUtil.RandomTrue(dic_Card[cardtype].m_Data.Get_FloatValue2())) Shoot_AddProjectiles(dic_Card[cardtype], enemies[i]); } } cardtype = eCardType.G1_EnemySpawnHolyDamage; if (Can_RunCard(cardtype, addcard)) { var enemies = InGameInfo.Ins.Get_AllEnemies(Get_Data().m_Role); for (int i = 0; i < enemies.Count; i++) { if (enemies[i].IsDead()) continue; if (DSUtil.RandomTrue(dic_Card[cardtype].m_Data.Get_FloatValue2())) Shoot_AddProjectiles(dic_Card[cardtype], enemies[i]); } } cardtype = eCardType.G1_CurseExplosionOnKill; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) Shoot_Curse_RandomTarget(); cardtype = eCardType.G1_FireMagicMissiles; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) { var card = dic_Card[cardtype]; var targets = new List(); for (int i = 0; i < card.m_Data.n_ProjectileCount; i++) targets.Add(InGameInfo.Ins.Get_RandomEnemy_orNull(Get_Data().m_Role)); Shoot_AddProjectiles(card, targets.ToArray()); } cardtype = eCardType.G1_LifeStealToRandomAll; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) { var card = dic_Card[cardtype]; var target = InGameInfo.Ins.Get_RandomEnemy_orNull(Get_Data().m_Role); if (target) { target.Get_Dmg(card.m_Data.Get_IntValue1()); Heal(eHealType.LifeSteal, card.m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); } } cardtype = eCardType.G1_GetRandomRareOrEpicSkill; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) Add_Card_Random(eGrade.UnCommon, eGrade.Rare); cardtype = eCardType.G1_InstantFullHeal; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) { Heal(eHealType.Normal, 1f); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Mul, 1f); } cardtype = eCardType.G1_CurseEnemiesOnBattlefield; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) { var enemies = InGameInfo.Ins.Get_AllEnemies(Get_Data().m_Role).FindAll(f => !f.IsDead() && !f.IsCurse()); var targetcount = dic_Card[cardtype].m_Data.Get_IntValue1(); var targets = enemies.OrderBy(_ => Guid.NewGuid()).Take(targetcount).ToList(); targets.ForEach(f => f.Set_StatusEffect(eStatusConditionsType.Curse, 99999f)); } cardtype = eCardType.G1_EnemySpawnStunChance; if (Can_RunCard(cardtype, addcard)) { var enemies = InGameInfo.Ins.Get_AllEnemies(m_TableData.m_Role); var carddata = dic_Card[cardtype].m_Data; for (int i = 0; i < enemies.Count; i++) { if (DSUtil.RandomTrue(carddata.Get_FloatValue2())) enemies[i].Set_StatusEffect(carddata.e_StatusConditionsType, carddata.Get_FloatValue3()); } } cardtype = eCardType.G1_FullShieldRecover; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) { Heal_Shield(1f); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Mul, 1f); } cardtype = eCardType.G1_InstantSkillReroll; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) SelectCardUI.Ins.Set_Cards(true); cardtype = eCardType.G1_StunAllMeleeEnemies; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) { var carddata = dic_Card[cardtype].m_Data; var enemies = InGameInfo.Ins.Get_Enemies_byAttackType(Get_Data().m_Role, eAttackType.Melee); for (int i = 0; i < enemies.Count; i++) enemies[i].Set_StatusEffect(carddata.e_StatusConditionsType, carddata.Get_FloatValue3()); } cardtype = eCardType.G1_StunAllRangedEnemies; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) { var carddata = dic_Card[cardtype].m_Data; var enemies = InGameInfo.Ins.Get_Enemies_byAttackType(Get_Data().m_Role, eAttackType.Range); for (int i = 0; i < enemies.Count; i++) enemies[i].Set_StatusEffect(carddata.e_StatusConditionsType, carddata.Get_FloatValue3()); } cardtype = eCardType.G1_DealHolyDamageToAll; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) Shoot_AddProjectiles(dic_Card[cardtype], InGameInfo.Ins.Get_AllEnemies(Get_Data().m_Role).ToArray()); cardtype = eCardType.G1_ShieldIncreaseAttackPower; if (dic_Card.ContainsKey(cardtype) && cardtype == addcard) { if (m_StatInfo.Get_TotalStat(eStat.Shield) > 0) { var carddata = dic_Card[cardtype].m_Data; m_StatInfo.Set_Stat(true, eStat.Attack_Min, carddata.Get_IntValue1()); m_StatInfo.Set_Stat(true, eStat.Attack_Max, carddata.Get_IntValue1()); Refresh_PCUI(); } } cardtype = eCardType.G1_AttackRandomEnemy; CantSetTarget = dic_Card.ContainsKey(cardtype); CantSetTarget.RandomizeCryptoKey(); if (isCantSetTarget()) Find_Target(); } private void TryActivateCard_NoMiss(eCardType cardtype, Action onTrigger) { if (!dic_Card.ContainsKey(cardtype)) return; var card = dic_Card[cardtype]; int n = card.m_Data.Get_IntValue1(); if (m_TotalAttackSuccessCount >= n && m_TotalAttackSuccessCount % n == 0) onTrigger?.Invoke(card); } protected void OnEvent_PlayAttack() { ++m_TotalAttackCount; m_TotalAttackCount.RandomizeCryptoKey(); ++m_AttackCount; m_AttackCount.RandomizeCryptoKey(); m_BaseAttackPD.Set(m_Target, Get_ProjectileSpeed()); Check_Specificity(eActiveConditions.Attack_Normal, m_BaseAttackPD); eCardType cardtype = eCardType.Max; if (m_AttackCount == 1) { // 첫번째 공격 cardtype = eCardType.G1_FirstAttack; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; if (card.UseCount > 0) return; ++card.UseCount; m_StatInfo.Set_Buff(true, eStat.AddDmgMul_1Time, dic_Card[cardtype].m_Data.Get_FloatValue2()); } cardtype = eCardType.G1_FirstAttackHeals; if (dic_Card.ContainsKey(cardtype)) { Heal(eHealType.Normal, dic_Card[cardtype].m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); } cardtype = eCardType.G1_FirstAttackShieldPercent; if (dic_Card.ContainsKey(cardtype)) { Heal_Shield(dic_Card[cardtype].m_Data.Get_FloatValue2()); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Mul, 1f); } cardtype = eCardType.G1_FirstAttackLightningStorm; if (dic_Card.ContainsKey(cardtype)) { var enemies = InGameInfo.Ins.Get_RandomAliveEnemies(Get_Data().m_Role, dic_Card[cardtype].m_Data.Get_IntValue1()).ToArray(); Shoot_AddProjectiles(dic_Card[cardtype], enemies); } var G1_FirstAttackLightning = m_Target.Get_CardSkillData_orNull(eCardType.G1_FirstAttackLightning); if (G1_FirstAttackLightning != null && DSUtil.RandomTrue(G1_FirstAttackLightning.m_Data.Get_FloatValue1())) Shoot_AddProjectiles(G1_FirstAttackLightning, this); cardtype = eCardType.G3_FirstAttackCritChanceUp; if (dic_Card.ContainsKey(cardtype)) m_StatInfo.Set_Buff(true, eStat.AddCri_1Time, dic_Card[cardtype].m_Data.Get_FloatValue2()); } cardtype = eCardType.G1_LowHPEnemyLightning; if (dic_Card.ContainsKey(cardtype)) { var data = dic_Card[cardtype].m_Data; var target_hp = m_Target.Get_ActorStatInfo().Get_TotalStat(eStat.HP); var target_maxhp = m_Target.Get_ActorStatInfo().Get_TotalStat(eStat.MaxHP); if (target_hp < target_maxhp * data.Get_FloatValue1() && DSUtil.RandomTrue(data.Get_FloatValue3())) Shoot_AddProjectiles(cardtype, m_Target); } } public void OnEvent_ShootProjectile(ProjectileData pdData) { if (!pdData.m_HitterStat.IsMainAttack) return; var cardtype = eCardType.G1_IllusionSpear; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; if (card.UseCount <= 0) { ++card.UseCount; Shoot_AddProjectiles(card, InGameInfo.Ins.Get_Enemy_orNull(m_TableData.m_Role, pdData.Target.Get_MobIndex() + 3)); } } } public virtual void OnEvent_Kill(Actor deadactor) { var cardtype = eCardType.G1_FullHealAfterKillsOnce; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; card.Add_UseCountACC(1, () => { AllHeal(eHealType.Normal); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Mul, 1f); }, int.MinValue); } cardtype = eCardType.G1_KillCountRecoverFullShield; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; card.Add_UseCountACC(1, () => { Heal_Shield(1f); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Add, 1f); }, int.MinValue); } cardtype = eCardType.G1_DamageOnKill; if (dic_Card.ContainsKey(cardtype)) Shoot_Projectile_FixedDmg(cardtype, dic_Card[cardtype].m_Data.Get_IntValue1(), InGameInfo.Ins.Get_RandomEnemy_orNull(Get_Data().m_Role)); cardtype = eCardType.G4_MaxAttackUpAndHealOnKill; if (dic_Card.ContainsKey(cardtype)) { var heal = (int)dic_Card[cardtype].m_Data.Get_FloatValue2(); Heal(eHealType.Normal, heal); } cardtype = eCardType.G5_ArcaneExplosionOnKill; if (dic_Card.ContainsKey(cardtype)) Shoot_MysticExplosion(0, dic_Card[cardtype]); cardtype = eCardType.G5_StunBacklineOnKill; if (dic_Card.ContainsKey(cardtype)) { var enemies = InGameInfo.Ins.Get_LineMobs(eMobBattlePos.Middleline); for (int i = 0; i < enemies.Count; i++) enemies[i].Set_StatusEffect(eStatusConditionsType.Stun, dic_Card[cardtype].m_Data.Get_FloatValue3()); } if (deadactor.IsMiddleLine()) { cardtype = eCardType.G1_HealOnBackKill; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; Heal(eHealType.Normal, card.m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); } cardtype = eCardType.G1_CastMagicMissilesOnBackKill; if (dic_Card.ContainsKey(cardtype)) Shoot_AddProjectiles(cardtype, InGameInfo.Ins.Get_RandomEnemy_orNull(Get_Data().m_Role)); cardtype = eCardType.G1_KillBacklineDealHolyDamage; if (dic_Card.ContainsKey(cardtype)) Shoot_AddProjectiles(cardtype, InGameInfo.Ins.Get_RandomAliveEnemies(Get_Data().m_Role, dic_Card[cardtype].m_Data.Get_IntValue2()).ToArray()); } } public void OnEvent_NoMiss_Hitter(ProjectileData pdData, bool nomiss) { if (!pdData.m_HitterStat.IsMainAttack) return; var cardtype = eCardType.Max; if (nomiss) { ++m_TotalAttackSuccessCount; m_TotalAttackSuccessCount.RandomizeCryptoKey(); ++m_AttackSuccessCount; m_AttackSuccessCount.RandomizeCryptoKey(); Check_Specificity(eActiveConditions.Attack_Hit, pdData); TryActivateCard_NoMiss(eCardType.G4_NHitFiresDarkMissiles, card => Shoot_AddProjectiles(card, pdData.Target)); TryActivateCard_NoMiss(eCardType.G4_NHitCastsLightning, card => { pdData.Target = InGameInfo.Ins.Get_RandomEnemy_orNull(Get_Data().m_Role); Shoot_AddProjectiles(card, pdData.Target); }); TryActivateCard_NoMiss(eCardType.G4_NHitHealsByMaxHPPercent, card => Heal(eHealType.Normal, card.m_Data.Get_FloatValue2())); TryActivateCard_NoMiss(eCardType.G4_NHitCastsFireballAOE, card => { var rndEnemy = InGameInfo.Ins.Get_RandomEnemy_orNull(Get_Data().m_Role); if (rndEnemy) { pdData.Target = rndEnemy; var rndindex = rndEnemy.Get_MobIndex(); Shoot_AddProjectiles(card, InGameInfo.Ins.Get_Mobs_4Nearby(rndindex)); } }); cardtype = eCardType.G1_FifthAttackBack; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; card.Add_UseCountACC(1, () => { var middletarget = InGameInfo.Ins.Get_Enemy_orNull(Get_Data().m_Role, pdData.Target.Get_MobIndex() + 3); if (middletarget) Shoot_AddProjectiles(card, middletarget); }); } cardtype = eCardType.G1_ThunderOnFifthHit; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; card.Add_UseCountACC(1, () => { Shoot_AddProjectiles(card, pdData.Target); }); } } else { cardtype = eCardType.G1_DamageUpAfterMiss; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; Set_Buff(true, eStat.AddDmgMul_1Time, card.m_Data.Get_FloatValue2()); } cardtype = eCardType.G1_MissRestoreShield; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; Heal_Shield(card.m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Add, 1f); } cardtype = eCardType.G1_MissCastLightningRandomBackRow; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; var targets = InGameInfo.Ins.Get_LineMobs(eMobBattlePos.Middleline); if (targets.Count > 0) { var target = targets[Random.Range(0, targets.Count)]; Shoot_AddProjectiles(card, target); } } cardtype = eCardType.G1_MissCriticalDamageBackRow; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; var targets = InGameInfo.Ins.Get_LineMobs(eMobBattlePos.Middleline); var count = card.m_Data.Get_IntValue1(); if (targets.Count > 0) { var selectedTargets = targets.OrderBy(x => Guid.NewGuid()).Take(count).ToList(); for (int i = 0; i < selectedTargets.Count; i++) { var pd = Get_CardProjectileData(i, card); pd.Set(card.m_Data.s_Projectile, m_TableData.m_Role, card.m_Data.e_ProjectileAttackType, this, dic_CardStatInfo[cardtype][i], cardtype); pd.isCri = true; Shoot_Projectile(selectedTargets[i], pd, target => target.Get_Dmg(pd)); } } } cardtype = eCardType.G1_MissCastLightningAdditionalAttack; if (dic_Card.ContainsKey(cardtype)) Shoot_AddProjectiles(dic_Card[cardtype], pdData.Target); cardtype = eCardType.G1_MissHolyDamage; if (dic_Card.ContainsKey(cardtype)) Shoot_AddProjectiles(dic_Card[cardtype], pdData.Target); } cardtype = eCardType.G1_ElectricShockOnConsecutiveHits; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; if (nomiss) card.Add_UseCountACC(1, () => { Shoot_AddProjectiles(card, pdData.Target); }); else card.UseCount_Acc = 0; } } public void OnEvent_Cri(ProjectileData pdData, int fixeddmg) { if (!pdData.m_HitterStat.IsMainAttack) return; Check_Specificity(eActiveConditions.Attack_Critical, pdData); var cardtype = eCardType.G2_CriUpAfterCri; if (dic_Card.ContainsKey(cardtype)) { Set_Buff(true, eStat.AddCri_1Time, dic_Card[cardtype].m_Data.Get_FloatValue2()); Refresh_PCUI(); } cardtype = eCardType.G3_CritHitChainsToRandomEnemy; if (dic_Card.ContainsKey(cardtype)) if (DSUtil.RandomTrue(dic_Card[cardtype].m_Data.Get_FloatValue2())) Shoot_Projectile_FixedDmg(cardtype, fixeddmg, MonsterNodeControler.Ins.Get_RandomTarget()); cardtype = eCardType.G4_CritStunsAllEnemies; if (dic_Card.ContainsKey(cardtype)) { var enemies = InGameInfo.Ins.Get_AllEnemies(m_TableData.m_Role); var carddata = dic_Card[cardtype].m_Data; for (int i = 0; i < enemies.Count; i++) enemies[i].Set_StatusEffect(carddata.e_StatusConditionsType, carddata.Get_FloatValue3()); } cardtype = eCardType.G5_CastFireballOnCrit; if (dic_Card.ContainsKey(cardtype)) { var targets = InGameInfo.Ins.Get_Mobs_4Nearby(pdData.Target.Get_MobIndex()); Shoot_AddProjectiles(dic_Card[cardtype], targets); } cardtype = eCardType.G1_CastReaperOnNthCrit; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; card.Add_UseCountACC(1, () => { Shoot_AddProjectiles(card, pdData.Target); }); } } public void OnEvent_MeetNode(eStageNodeType nodeType) { var cardtype = eCardType.Max; var data = MyValue.m_MyStageData.Get_CurNodeData(); switch (nodeType) { case eStageNodeType.Mob: break; case eStageNodeType.Treasure: break; case eStageNodeType.Merchant: break; case eStageNodeType.NPC: break; case eStageNodeType.Sanctuary: cardtype = eCardType.G1_GainGoldOnSanctuaryFind; if (dic_Card.ContainsKey(cardtype)) { var gold = dic_Card[cardtype].m_Data.Get_IntValue1(); InGameInfo.Ins.Add_Goods(MyValue.ItemID_Gold, gold); GetItemUI.Ins.Set(new ItemSimpleData { itemid = MyValue.ItemID_Gold, amount = gold }); } cardtype = eCardType.G1_MaxHpPlusOnFountain; if (dic_Card.ContainsKey(cardtype)) { var sanctuarydata = data.Get_Data(); var sanctype = table_SanctuaryConfig.Ins.Get_Data(sanctuarydata.SanctuaryID).e_SanctuaryType; if (sanctype != eSanctuaryType.Sanctuary) { Set_Buff(true, eStat.MaxHP, dic_Card[cardtype].m_Data.Get_IntValue1()); Refresh_PCUI(); } } cardtype = eCardType.G1_FullRecoverAtFountain; if (dic_Card.ContainsKey(cardtype) && m_StatInfo.Get_TotalStat(eStat.Shield) > 0) { Heal(eHealType.Sactuary, 1f); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Mul, 1f); } cardtype = eCardType.G1_TwiceShrineFullRecover; if (dic_Card.ContainsKey(cardtype)) { dic_Card[cardtype].Add_UseCountACC(1, () => { AllHeal(eHealType.Normal); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Mul, 1f); }); } break; case eStageNodeType.BuffDebuff: break; case eStageNodeType.TwoWay: break; case eStageNodeType.Campfire: cardtype = eCardType.G1_CampHealShield; if (dic_Card.ContainsKey(cardtype)) { Heal_Shield(dic_Card[cardtype].m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Add, 1f); } cardtype = eCardType.G1_LevelUpOnCampFind; if (dic_Card.ContainsKey(cardtype)) InGameInfo.Ins.PCLvUp_Imm(); cardtype = eCardType.G1_CampShieldHighIncreaseMaxAttack; if (dic_Card.ContainsKey(cardtype)) { if (m_StatInfo.Get_TotalStat(eStat.Shield) >= m_StatInfo.Get_TotalStat(eStat.MaxShield) * dic_Card[cardtype].m_Data.Get_FloatValue2()) { m_StatInfo.Set_Stat(true, eStat.Attack_Max, dic_Card[cardtype].m_Data.Get_IntValue1()); Refresh_PCUI(); } } cardtype = eCardType.G1_CampFillEmptyPotion; if (dic_Card.ContainsKey(cardtype)) { m_StatInfo.Set_Stat(true, eStat.Potion, dic_Card[cardtype].m_Data.Get_IntValue1()); InGameInfo.Ins.Set_Texts(); } cardtype = eCardType.G1_CampRechargePotion; if (dic_Card.ContainsKey(cardtype)) { m_StatInfo.Set_Stat(true, eStat.Potion, dic_Card[cardtype].m_Data.Get_IntValue1()); InGameInfo.Ins.Set_Texts(); } cardtype = eCardType.G2_GetSkillOnCamp; if (dic_Card.ContainsKey(cardtype)) Add_Card_Random(eGrade.Common); break; case eStageNodeType.Nothing: { int heal = 0, shield = 0; cardtype = eCardType.G1_HealEverySecOutOfCombat; if (dic_Card.ContainsKey(cardtype)) heal += dic_Card[cardtype].m_Data.Get_IntValue1(); heal += (int)m_StatInfo.Get_TotalStat(eStat.ExplorationHpRecovery); shield += (int)m_StatInfo.Get_TotalStat(eStat.ExplorationShieldRecovery); if (heal > 0) { Heal(eHealType.Normal, heal); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); } if (shield > 0) { Heal_Shield(shield); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Add, 1f); } } cardtype = eCardType.G1_ExploreRecoverShieldOverTime; if (dic_Card.ContainsKey(cardtype)) { Heal_Shield(dic_Card[cardtype].m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Add, 1f); } break; case eStageNodeType.Boss: break; case eStageNodeType.Random: break; } if (nodeType != eStageNodeType.Nothing) { cardtype = eCardType.G1_StopExploreHealHP; if (dic_Card.ContainsKey(cardtype)) { Heal(eHealType.Normal, dic_Card[cardtype].m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); } cardtype = eCardType.G1_StopExploreHealShield; if (dic_Card.ContainsKey(cardtype)) { Heal_Shield(dic_Card[cardtype].m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Add, 1f); } } } public void OnEvent_LvUp() { var cardtype = eCardType.G1_HealOnLevelUp; if (dic_Card.ContainsKey(cardtype)) { Heal(eHealType.Normal, dic_Card[cardtype].m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); } cardtype = eCardType.G1_MaxHpUpOnLevelUp; if (dic_Card.ContainsKey(cardtype)) { m_StatInfo.Set_Stat(true, eStat.MaxHP, dic_Card[cardtype].m_Data.Get_IntValue1()); Refresh_PCUI(); } cardtype = eCardType.G1_MaxShieldUpOnLevelUp; if (dic_Card.ContainsKey(cardtype)) { m_StatInfo.Set_Stat(true, eStat.MaxShield, dic_Card[cardtype].m_Data.Get_IntValue1()); Refresh_PCUI(); } cardtype = eCardType.G1_StunAllEnemiesOnLevelUp; if (dic_Card.ContainsKey(cardtype)) { var enemies = InGameInfo.Ins.Get_AllEnemies(Get_Data().m_Role); for (int i = 0; i < enemies.Count; i++) enemies[i].Set_StatusEffect(eStatusConditionsType.Stun, dic_Card[cardtype].m_Data.Get_FloatValue3()); } cardtype = eCardType.G1_CurseEnemiesOnLevelUp; if (dic_Card.ContainsKey(cardtype)) Shoot_Curse_RandomTarget(); cardtype = eCardType.G1_LevelUpRecoverShield; if (dic_Card.ContainsKey(cardtype)) { Heal_Shield(dic_Card[cardtype].m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Add, 1f); } cardtype = eCardType.G2_ShieldRecoverOnLevelUp; if (dic_Card.ContainsKey(cardtype)) m_StatInfo.Set_Stat(true, eStat.Shield, dic_Card[cardtype].m_Data.Get_IntValue1()); } public void OnEvent_Avoid(ProjectileData pdData) { var actorstat = pdData.Hitter.Get_ActorStatInfo(); if (!actorstat.IsMainAttack) return; ++m_TotalAvoidCount; m_TotalAvoidCount.RandomizeCryptoKey(); ++m_AvoidCount; m_AvoidCount.RandomizeCryptoKey(); var cardtype = eCardType.G3_MaxAttackUpEveryNDodges; if (m_TotalAvoidCount > 0 && dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; if (m_TotalAvoidCount % (int)card.m_Data.Get_FloatValue2() == 0) { m_StatInfo.Set_Stat(true, eStat.Attack_Max, card.m_Data.Get_IntValue1()); IngameUIManager.Ins.m_PCMainStatUI.Set(m_StatInfo); } } cardtype = eCardType.G1_LifeStealOnDodge; if (dic_Card.ContainsKey(cardtype)) { var radnomtarget = InGameInfo.Ins.Get_RandomEnemy_orNull(Get_Data().m_Role); if (radnomtarget != null) { var card = dic_Card[cardtype]; radnomtarget.Get_Dmg(card.m_Data.Get_IntValue1()); radnomtarget.Set_StatusEffect(eStatusConditionsType.VampirHeal_Add, 1f); Heal(eHealType.LifeSteal, card.m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); } } cardtype = eCardType.G1_HolyDamageToBackEnemiesOnDodge; if (dic_Card.ContainsKey(cardtype)) { var enemies = InGameInfo.Ins.Get_LineMobs(eMobBattlePos.Middleline); Shoot_Projectile_FixedDmg(cardtype, dic_Card[cardtype].m_Data.Get_IntValue1(), enemies.ToArray()); } cardtype = eCardType.G1_HealOnDoubleDodge; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; card.Add_UseCountACC(1, () => { Heal(eHealType.Normal, card.m_Data.Get_IntValue2()); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); }); } if (pdData.e_AttackType == eAttackType.Melee) { cardtype = eCardType.G1_LightningToBackOnMeleeDodge; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; var target = InGameInfo.Ins.Get_Enemy_orNull(Get_Data().m_Role, pdData.Hitter.Get_MobIndex() + 3); Shoot_AddProjectiles(card, target); } } else { cardtype = eCardType.G1_ReflectOnRangedDodge; if (dic_Card.ContainsKey(cardtype)) Reflect_Projectile(cardtype, pdData); cardtype = eCardType.G1_ShieldOnRangedDodge; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; Heal_Shield(card.m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Add, 1f); } } } public void OnEvent_MyShield_Hit(ProjectileData pdData = null) { var cardtype = eCardType.G4_MaxAttackIncreasesByShield; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; m_StatInfo.Set_Buff(eStat.MaxAttack_byShield, (int)(m_StatInfo.Get_TotalStat(eStat.Shield) * card.m_Data.Get_FloatValue2())); Refresh_PCUI(); } cardtype = eCardType.G5_ReflectAllDamageWhenShielded; if (dic_Card.ContainsKey(cardtype)) Reflect_Projectile(cardtype, pdData, false); } protected virtual void OnEvent_GetDmg(ProjectileData pd) { var cardtype = eCardType.G1_FullShieldIfHpLowAndShieldZero; if (dic_Card.ContainsKey(cardtype) && !IsDead()) { if (m_StatInfo.Get_TotalStat(eStat.Shield) == 0) { var card = dic_Card[cardtype]; if (m_StatInfo.Get_TotalStat(eStat.HP) <= card.m_Data.Get_IntValue1()) { Heal_Shield(1f); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Mul, 1f); } } } if (m_StatInfo.Get_TotalStat(eStat.Reflection) > 0) Reflect_Projectile(pd, (int)m_StatInfo.Get_TotalStat(eStat.Reflection)); } public void OnEvent_Hit(ProjectileData pdData, Actor target, int dmg) { ActorStatInfo actorstat = pdData.m_HitterStat; eAttackType attackType = pdData.e_AttackType; eCardType cardtype = eCardType.Max; if (IsMiddleLine()) { var hittercard = pdData.Hitter.Get_CardSkillData_orNull(eCardType.G1_LifeStealOnBackAttack); if (hittercard != null) { var rndtarget = InGameInfo.Ins.Get_RandomEnemy_orNull(pdData.Hitter.Get_Data().m_Role); if (rndtarget) { rndtarget.Get_Dmg(hittercard.m_Data.Get_IntValue1()); pdData.Hitter.Heal(eHealType.LifeSteal, hittercard.m_Data.Get_IntValue1()); pdData.Hitter.Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); } } } if (!actorstat.IsMainAttack) return; ++dic_HitType[attackType]; dic_HitType[attackType].RandomizeCryptoKey(); Check_Specificity(eActiveConditions.Hit_Count, pdData); Check_Specificity(eActiveConditions.Hit_Noraml, pdData); if (attackType == eAttackType.Melee) { cardtype = eCardType.G4_NhMeleeHitRestoresShield; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; if (dic_HitType[attackType] >= card.m_Data.Get_IntValue1() && dic_HitType[attackType] % card.m_Data.Get_IntValue1() == 0) { m_StatInfo.Set_Stat(true, eStat.Shield, (int)(m_StatInfo.Get_TotalStat(eStat.MaxShield) * card.m_Data.Get_FloatValue2())); Set_HUD(); } } cardtype = eCardType.G1_HolyDamageOnMeleeHit; if (dic_Card.ContainsKey(cardtype)) Shoot_AddProjectiles(dic_Card[cardtype], pdData.Hitter); cardtype = eCardType.G1_ReflectFirstMeleeDamage; if (dic_Card.ContainsKey(cardtype) && !dic_Card[cardtype].list_identity.Contains(pdData.Hitter.Get_Identity())) { dic_Card[cardtype].list_identity.Add(pdData.Hitter.Get_Identity()); Reflect_Projectile(cardtype, pdData, false); } cardtype = eCardType.G1_ReflectLowMeleeAsHoly; if (dic_Card.ContainsKey(cardtype) && dic_Card[cardtype].m_Data.Get_IntValue1() >= dmg) Reflect_Projectile(cardtype, pdData, false, true); } else if (attackType == eAttackType.Range) { cardtype = eCardType.G1_HealOnRangedHit; if (dic_Card.ContainsKey(cardtype)) { Heal(eHealType.Normal, dic_Card[cardtype].m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); } cardtype = eCardType.G1_HealOnRangedHitChance; if (dic_Card.ContainsKey(cardtype)) { if (DSUtil.RandomTrue(dic_Card[cardtype].m_Data.Get_FloatValue2())) { Heal(eHealType.Normal, dic_Card[cardtype].m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Add, 1f); } } cardtype = eCardType.G1_RangedHitDealHolyDamage; if (dic_Card.ContainsKey(cardtype)) Shoot_AddProjectiles(dic_Card[cardtype], pdData.Hitter); } cardtype = eCardType.G1_NullifyDamageEveryNHits; if (dic_Card.ContainsKey(cardtype)) { var card = dic_Card[cardtype]; ++card.UseCount; if (card.UseCount >= card.m_Data.Get_IntValue1()) { card.UseCount = 0; Set_Buff(true, eStat.Dmg_Immune, 1); Set_StatusEffect(eStatusConditionsType.Invincibility_Count, 1f); } } cardtype = eCardType.G1_HealOnDoubleDodge; if (dic_Card.ContainsKey(cardtype)) dic_Card[cardtype].UseCount_Acc = 0; } void OnEvent_ActiveConditions() { var my_shield = (int)m_StatInfo.Get_TotalStat(eStat.Shield); var maxshield = (int)m_StatInfo.Get_TotalStat(eStat.MaxShield); Counting_onActiveCondition(eActiveConditions.MaxShield_Up, my_shield, maxshield); Counting_onActiveCondition(eActiveConditions.MaxShield_Down, my_shield, maxshield); Counting_onActiveCondition(eActiveConditions.MaxShield_Rate, my_shield, maxshield); var hp = (int)m_StatInfo.Get_TotalStat(eStat.HP); var maxhp = (int)m_StatInfo.Get_TotalStat(eStat.MaxHP); Counting_onActiveCondition(eActiveConditions.MaxHp_Up, hp, maxhp); Counting_onActiveCondition(eActiveConditions.MaxHp_Down, hp, maxhp); Counting_onActiveCondition(eActiveConditions.MaxHpRate, hp, maxhp); } #endregion #region 특성 void Set_Specificity() { // 특성 4종 세팅 dic_StatusEffectData.Clear(); dic_ActiveConditionData.Clear(); list_Specificity.Clear(); if (m_TableData.n_Specificity1 > 0) list_Specificity.Add(table_StatusOptionSet.Ins.Get_Data(m_TableData.n_Specificity1)); if (m_TableData.n_Specificity2 > 0) list_Specificity.Add(table_StatusOptionSet.Ins.Get_Data(m_TableData.n_Specificity2)); if (m_TableData.n_Specificity3 > 0) list_Specificity.Add(table_StatusOptionSet.Ins.Get_Data(m_TableData.n_Specificity3)); if (m_TableData.n_Specificity4 > 0) list_Specificity.Add(table_StatusOptionSet.Ins.Get_Data(m_TableData.n_Specificity4)); if (IsRole(eRole.PC)) DeckUI.list_Specificity = list_Specificity; dic_activeCondition.Clear(); for (int i = 0; i < list_Specificity.Count; i++) { var temp = list_Specificity[i]; RunStatusEffect_Instantly(temp, temp.Get_Target(this, m_Target, m_TableData.m_Role), null); if (!dic_activeCondition.ContainsKey(temp.e_ActiveConditions)) dic_activeCondition.Add(temp.e_ActiveConditions, new List()); var sosActordata = new StatusOptionSetActorData { m_Actor = this, m_TData = temp, m_sclData = table_StatusConditionsList.Ins.Get_Data_orNull(temp.e_StatusConditionsType), IsSet = false }; dic_activeCondition[temp.e_ActiveConditions].Add(sosActordata); switch (temp.e_ActiveConditions) { case eActiveConditions.ActiveSkill: dic_StatusEffect[temp.e_StatusConditionsType].Set_ActiveSkill(sosActordata); break; case eActiveConditions.Appear: case eActiveConditions.MaxHp_Up: case eActiveConditions.MaxHp_Down: case eActiveConditions.MaxHpRate: case eActiveConditions.MaxShield_Up: case eActiveConditions.MaxShield_Down: case eActiveConditions.MaxShield_Rate: dic_StatusEffect[temp.e_StatusConditionsType].Set(sosActordata); break; } switch (temp.e_StatusConditionsType) { case eStatusConditionsType.Battle: // 선제공격 Set_Battle_PreemptiveStrike(); break; } } Refresh_PCUI(); m_BaseAttackPD.Set(m_TableData.s_Projectile, m_TableData.m_Role, Get_AttackType(), this, m_StatInfo); OnEvent_ActiveConditions(); } void Check_Specificity(eActiveConditions activeConditions, ProjectileData pdData) { if (dic_activeCondition.ContainsKey(activeConditions)) { var data = dic_activeCondition[activeConditions]; for (int i = 0; i < data.Count; i++) { var temp = data[i]; bool bSuccess = false; var rateval = temp.m_TData.Get_Rate_orValue(); switch (activeConditions) { //case eActiveConditions.Attack_Normal: //case eActiveConditions.Attack_Hit: //case eActiveConditions.Attack_Critical: //case eActiveConditions.Attack_Special: //case eActiveConditions.Hit_Noraml: //case eActiveConditions.Hit_PreemptiveStrike: //case eActiveConditions.Evasion_Rate: //case eActiveConditions.Miss_Rate: //case eActiveConditions.Potion_Use: default: bSuccess = DSUtil.RandomTrue(rateval); break; case eActiveConditions.Hit_Count: case eActiveConditions.Evasion_Count: case eActiveConditions.Miss_Count: case eActiveConditions.Potion_Count: ++temp.Value; bSuccess = temp.Value >= rateval; if (bSuccess) temp.Value = 0; break; case eActiveConditions.MaxHp_Up: break; case eActiveConditions.MaxHp_Down: break; case eActiveConditions.MaxHpRate: break; case eActiveConditions.MaxShield_Up: break; case eActiveConditions.MaxShield_Down: break; case eActiveConditions.MaxShield_Rate: break; //case eActiveConditions.ActiveSkill: //case eActiveConditions.Appear: // bSuccess = true; // break; case eActiveConditions.SurviveAlone: break; case eActiveConditions.Die_Self: bSuccess = pdData.Hitter.IsDead(); break; case eActiveConditions.Die_Front: break; case eActiveConditions.Die_Back: break; case eActiveConditions.Die_Ally: break; } if (bSuccess) Run_Specificity(temp, pdData); } } } public void Run_Specificity(StatusOptionSetActorData temp, ProjectileData pdData) { var sclData = temp.m_sclData; var tData = temp.m_TData; var caster = pdData.Hitter; // 효과를 건 주체 var role = caster.m_TableData.m_Role; var target = pdData.Target; List targets = tData.Get_Targets(caster, target, Get_Data().m_Role); foreach (var t in targets) { //if (t == null || t.IsDead()) continue; switch (tData.e_StatusConditionsType) { case eStatusConditionsType.PC_Evasion_Melee: if (caster.Get_ActorStatInfo().Get_BuffStat(eStat.PreemptiveStrike) > 0) { caster.Get_ActorStatInfo().Set_Buff(eStat.PreemptiveStrike, 0); Set_Buff(tData.e_Stat1, temp.m_TData.Get_StatValue1()); } break; case eStatusConditionsType.PC_CriticalRate_Add: // Hit_Count 피격 횟수 해당 피격 {Value} 횟수 충족 시 발동 m_StatInfo.Set_Buff(true, temp.m_TData.e_Stat1, temp.m_TData.Get_StatValue1()); m_StatInfo.Set_Buff(true, temp.m_TData.e_Stat2, temp.m_TData.Get_StatValue2()); Refresh_PCUI(); break; case eStatusConditionsType.VampirHeal_Add: { var dmg = (int)temp.m_TData.Get_StatValue1(); t.Get_Dmg(dmg); Heal(eHealType.LifeSteal, dmg); Set_StatusEffect(tData.e_StatusConditionsType, 1f); } break; case eStatusConditionsType.VampirHeal_Mul: { var dmg = (int)(temp.m_TData.Get_StatValue1() * t.Get_ActorStatInfo().Get_TotalStat(eStat.HP)); t.Get_Dmg(dmg); Heal(eHealType.LifeSteal, dmg); Set_StatusEffect(tData.e_StatusConditionsType, 1f); } break; case eStatusConditionsType.Resurrection: case eStatusConditionsType.ATK_SPD_Add: case eStatusConditionsType.ATK_DMG_Add: case eStatusConditionsType.Poison: case eStatusConditionsType.Burn: case eStatusConditionsType.Stun: case eStatusConditionsType.Freezing: case eStatusConditionsType.Blind: case eStatusConditionsType.Slow: t.Set_StatusEffect(temp, t); break; default: t.Run_StatusOptionSet(false, tData, t); break; } } } #endregion #region 장비 protected virtual void Set_Equipment() { var sdata = Get_ServerData(); if (sdata != null) { var setItemData = sdata.Get_EquipSetItemData(m_TableData.n_ID); for (int i = 0; i < setItemData.list_SkillId.Count; i++) InGameInfo.Ins.Add_Card(table_cardlist.Ins.Get_Data(setItemData.list_SkillId[i]), false); } } #endregion #region 상태 이상 protected bool IsCC() { for (int i = 0; i < list_NoUpdateCC.Count; i++) if (dic_StatusEffect[list_NoUpdateCC[i]].IsActive()) return true; return false; } public bool IsCC(eStatusConditionsType type) { return dic_StatusEffect[type].IsActive(); } public bool IsCurse() { return dic_StatusEffect[eStatusConditionsType.Curse].IsActive(); } public void Set_Buff(eStat stat, double v) { m_StatInfo.Set_Buff(stat, v); } public void Set_Buff(bool add, eStat stat, double v) { m_StatInfo.Set_Buff(add, stat, v); } public void Set_DeBuff(bool add, eStat stat, double v) { m_StatInfo.Set_Debuff(add, stat, v); } public void Set_DeBuff(eStat stat, double v) { m_StatInfo.Set_Debuff(stat, v); } public void Set_StatusEffectData(eStatusConditionsType type, StatusEffectData sedata) { if (!dic_StatusEffectData.ContainsKey(type)) dic_StatusEffectData.Add(type, sedata); else dic_StatusEffectData[type] = sedata; } public void Set_ActiveConditionData(eActiveConditions activeCondition, StatusEffectData sedata) { if (!dic_ActiveConditionData.ContainsKey(activeCondition)) dic_ActiveConditionData.Add(activeCondition, new List()); dic_ActiveConditionData[activeCondition].Add(sedata); } public void Set_StatusEffect(StatusOptionSetActorData data, Actor target) { if (!IsDead()) dic_StatusEffect[data.m_TData.e_StatusConditionsType].Set(data, target); } public void Set_StatusEffect(eStatusConditionsType scType, float time, bool ignoredead = false) { if (!IsDead() || ignoredead) dic_StatusEffect[scType].Set_byCard(scType, time, this); } public void RunStatusEffect_Instantly(StatusOptionSetTableData sosdata, Actor target, Action act) { if (target == null || target.IsDead()) return; //if (!IsRole(eRole.PC)) return; switch (sosdata.e_ActiveConditions) { case eActiveConditions.None: case eActiveConditions.Instantly: case eActiveConditions.Sancturay: Run_StatusOptionSet(true, sosdata, target, act); break; } } public void Run_StatusOptionSet(bool checkRate, StatusOptionSetTableData sosdata, Actor target, Action act = null) { if (checkRate && !DSUtil.RandomTrue(sosdata.Get_Rate_orValue())) return; if (sosdata.e_StatusConditionsType != eStatusConditionsType.Invincibility_Time) dic_StatusEffect[sosdata.e_StatusConditionsType].Set_byCard(sosdata.e_StatusConditionsType, 3f, this); var statinfo = target.Get_ActorStatInfo(); switch (sosdata.e_StatusConditionsType) { default: // 기본은 그냥 스탯 추가 if (sosdata.e_Stat1 < eStat.Max) statinfo.Set_Buff(true, sosdata.e_Stat1, sosdata.Get_StatValue1()); if (sosdata.e_Stat2 < eStat.Max) statinfo.Set_Buff(true, sosdata.e_Stat2, sosdata.Get_StatValue2()); target.Set_HUD(); if (target.IsRole(eRole.PC)) InGameInfo.Ins.Set_Texts(); break; case eStatusConditionsType.Recovery_All: target.AllHeal(eHealType.Normal); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Mul, 1f); break; case eStatusConditionsType.LvUp: if (target.IsRole(eRole.PC)) InGameInfo.Ins.PCLvUp_Imm(); break; case eStatusConditionsType.AddResurrection: target.Set_Buff(true, eStat.Resurrection, sosdata.Get_StatValue1()); break; case eStatusConditionsType.GetSkillCard_N: if (target.IsRole(eRole.PC)) InGameInfo.Ins.Add_Card_Random(eGrade.Common); break; case eStatusConditionsType.GetSkillCard_R: if (target.IsRole(eRole.PC)) InGameInfo.Ins.Add_Card_Random(eGrade.UnCommon); break; case eStatusConditionsType.GetSkillCard_SR: if (target.IsRole(eRole.PC)) InGameInfo.Ins.Add_Card_Random(eGrade.Rare); break; case eStatusConditionsType.GetSkillCard_SSR: if (target.IsRole(eRole.PC)) InGameInfo.Ins.Add_Card_Random(eGrade.Hero); break; case eStatusConditionsType.GetSkillCard_UR: if (target.IsRole(eRole.PC)) InGameInfo.Ins.Add_Card_Random(eGrade.Legend); break; case eStatusConditionsType.GetSkillCard_Random: if (target.IsRole(eRole.PC)) InGameInfo.Ins.Add_Card_Random(eGrade.None); break; case eStatusConditionsType.IncreaseEXP_Mul: if (target.IsRole(eRole.PC)) Set_Mul(eStat.EXP_Mul); break; case eStatusConditionsType.IncreaseGold_Mul: if (target.IsRole(eRole.PC)) Set_Mul(eStat.GOLD_Mul); break; case eStatusConditionsType.GetSoul_Add: if (target.IsRole(eRole.PC)) { var soul = Random.Range((int)sosdata.Get_StatValue1(), (int)sosdata.Get_StatValue2() + 1); InGameInfo.Ins.Add_Goods(MyValue.ItemID_Soul, soul); GetItemUI.Ins.Set(new ItemSimpleData { itemid = MyValue.ItemID_Soul, amount = soul }); act?.Invoke(soul); return; } break; case eStatusConditionsType.GetGold_Add: if (target.IsRole(eRole.PC)) { var gold = Random.Range((int)sosdata.Get_StatValue1(), (int)sosdata.Get_StatValue2() + 1); InGameInfo.Ins.Add_Goods(MyValue.ItemID_Gold, gold); GetItemUI.Ins.Set(new ItemSimpleData { itemid = MyValue.ItemID_Gold, amount = gold }); act?.Invoke(gold); return; } break; case eStatusConditionsType.Invincibility_Time: target.Set_StatusEffect(eStatusConditionsType.Invincibility_Time, sosdata.Get_StatValue1()); act?.Invoke(sosdata.Get_StatValue1()); return; case eStatusConditionsType.Heal_Hp_Add: { var heal = (int)sosdata.Get_StatValue1(); if (sosdata.e_ActiveConditions == eActiveConditions.Sancturay && dic_Card.ContainsKey(eCardType.G1_SanctuaryHeal)) heal = (int)(heal * dic_Card[eCardType.G1_SanctuaryHeal].m_Data.Get_FloatValue2()); target.Heal(sosdata.e_ActiveConditions == eActiveConditions.Sancturay ? eHealType.Sactuary : eHealType.Normal, heal); act?.Invoke(heal); return; } case eStatusConditionsType.GetExp_Add: if (target.IsRole(eRole.PC)) { var exp = (int)sosdata.Get_StatValue1(); if (sosdata.e_ActiveConditions == eActiveConditions.Sancturay && dic_Card.ContainsKey(eCardType.G1_SanctuaryHeal)) exp = (int)(exp * dic_Card[eCardType.G1_SanctuaryHeal].m_Data.Get_FloatValue2()); InGameInfo.Ins.Add_Goods(MyValue.ItemID_Exp, exp); act?.Invoke(exp); return; } break; case eStatusConditionsType.Heal_Shield_Add: { var shield = (int)sosdata.Get_StatValue1(); target.Heal_Shield(shield); act?.Invoke(shield); return; } case eStatusConditionsType.Berserker_ATK_DMG_Add: break; case eStatusConditionsType.Berserker_ATK_SPD_Add: break; case eStatusConditionsType.Berserker_ATK_DMG_Mul: break; case eStatusConditionsType.Berserker_ATK_SPD_Mul: break; case eStatusConditionsType.Heal_Hp_Mul: break; case eStatusConditionsType.Heal_Hp_Random: { var heal = Random.Range((int)sosdata.Get_StatValue1(), (int)sosdata.Get_StatValue2()); if (sosdata.e_ActiveConditions == eActiveConditions.Sancturay && dic_Card.ContainsKey(eCardType.G1_SanctuaryHeal)) heal = (int)(heal * dic_Card[eCardType.G1_SanctuaryHeal].m_Data.Get_FloatValue2()); target.Heal(sosdata.e_ActiveConditions == eActiveConditions.Sancturay ? eHealType.Sactuary : eHealType.Normal, heal); act?.Invoke(heal); return; } case eStatusConditionsType.Heal_Shield_Mul: { float heal = sosdata.Get_StatValue1(); var cardtype = eCardType.G1_TripleShieldSpring; if (dic_Card.ContainsKey(cardtype)) heal *= dic_Card[cardtype].m_Data.Get_IntValue1(); target.Heal_Shield(heal); act?.Invoke(heal); return; } case eStatusConditionsType.Heal_Shield_Random: { var heal = Random.Range((int)sosdata.Get_StatValue1(), (int)sosdata.Get_StatValue2()); var cardtype = eCardType.G1_TripleShieldSpring; if (dic_Card.ContainsKey(cardtype)) heal *= dic_Card[cardtype].m_Data.Get_IntValue1(); target.Heal_Shield(heal); act?.Invoke(heal); return; } case eStatusConditionsType.Destruct: break; case eStatusConditionsType.ATK_DMG_Mul: break; case eStatusConditionsType.ATK_SPD_Mul: break; case eStatusConditionsType.Death_ATK_Add: break; case eStatusConditionsType.Death_ATK_Mul: break; case eStatusConditionsType.Death_Growup: break; case eStatusConditionsType.Death_Heal_Add: break; case eStatusConditionsType.Death_Heal_Mul: break; case eStatusConditionsType.HitDamage_Add: break; case eStatusConditionsType.HitDamage_Mul: break; case eStatusConditionsType.HitDamage_Random: break; case eStatusConditionsType.IncreaseSoul_Mul: break; case eStatusConditionsType.Invincibility_Count: break; case eStatusConditionsType.Battle: break; } act?.Invoke(0); void Set_Mul(eStat stat) { var mul = m_StatInfo.Get_BuffStat(stat); if (mul < 1) Set_Buff(stat, 2); else Set_Buff(stat, mul * 2); } } public void Set_SelfDestruct(StatusOptionSetActorData data) { if (data.m_TData.e_StatusConditionsType == eStatusConditionsType.Destruct) { if (m_SelfDestructData.m_Status == eSelfDestructStatus.None) { m_SelfDestructData.Set(data); m_SelfDestructData.Set_Status(eSelfDestructStatus.Check_Rate); } } } void Set_Battle_PreemptiveStrike() { m_AttackCoolTime = Time.deltaTime * 2f; Set_Buff(eStat.PreemptiveStrike, 1); } #endregion #region 스탯 void Refresh_PCUI() { if (IsRole(eRole.PC)) IngameUIManager.Ins.m_PCMainStatUI.Set(m_StatInfo); m_HUD_HPShield.Set(m_StatInfo); } public void Revive_byDefeatUI() { StartCoroutine(Co_Revive()); } IEnumerator Co_Revive() { var scType = eStatusConditionsType.Resurrection; dic_StatusEffect[scType].Set_byCard(scType, 3f, this); yield return new WaitForSeconds(table_GlobalValue.Ins.Get_Float("ReviveTime_byDefeatUI")); AllHeal(eHealType.Normal); Set_StatusEffect(eStatusConditionsType.Heal_Hp_Mul, 1f); Set_Battle(true); } public void Use_Potion(bool ignoreDie, int heal) { var statinfo = m_StatInfo; if ((ignoreDie || !IsDead()) && !statinfo.isFullHP() && statinfo.Get_TotalStat(eStat.Potion) > 0) { var potionheal = heal; statinfo.Set_Stat(false, eStat.Potion, 1); Heal(eHealType.Potion, potionheal); InGameInfo.Ins.Set_Texts(); eCardType cardtype = eCardType.G1_DarkMissileFromPotion; if (dic_Card.ContainsKey(cardtype)) { var mobs = InGameInfo.Ins.Get_LineMobs(eMobBattlePos.Frontline); if (mobs.Count > 0) Shoot_AddProjectiles(cardtype, mobs[Random.Range(0, mobs.Count)]); } cardtype = eCardType.G1_PotionDealHolyDamageRandomEnemy; if (dic_Card.ContainsKey(cardtype)) Shoot_AddProjectiles(cardtype, InGameInfo.Ins.Get_RandomEnemy_orNull(Get_Data().m_Role)); cardtype = eCardType.G3_PotionUseDealsHealAsDamage; if (dic_Card.ContainsKey(cardtype)) Shoot_Projectile_FixedDmg(cardtype, potionheal, InGameInfo.Ins.Get_AllEnemies(eRole.PC).ToArray()); } } public void AllHeal(eHealType healType) { Heal_Shield(1f); Heal(healType, 1f); } void Heal_Common(eHealType healType, int heal) { var add_mul = 0d; if (healType == eHealType.Potion) add_mul += m_StatInfo.Get_TotalStat(eStat.PotionEfficiencyUp); if (healType != eHealType.Potion) add_mul += m_StatInfo.Get_TotalStat(eStat.NonCombatRecoveryEfficiency); if (healType == eHealType.LifeSteal) add_mul += m_StatInfo.Get_TotalStat(eStat.LifeStealEfficiency); heal += (int)(heal * add_mul); var huddmg = IngameUIManager.Ins.Get_HUD_Dmg(); huddmg.Set_Heal(heal, Get_World_Position()); //EffectMgr.Ins.Show_Effect("Regeneration_health", Get_World_Position()); var cardtype = eCardType.G1_HolyDamageOnHeal; if (dic_Card.ContainsKey(cardtype)) Shoot_Projectile_FixedDmg(cardtype, dic_Card[cardtype].m_Data.Get_IntValue1(), InGameInfo.Ins.Get_RandomEnemy_orNull(Get_Data().m_Role)); cardtype = eCardType.G1_ShieldOnFullHeal; if (dic_Card.ContainsKey(cardtype) && m_StatInfo.isFullHP()) { Heal_Shield(dic_Card[cardtype].m_Data.Get_IntValue1()); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Add, 1f); } cardtype = eCardType.G5_ShieldHealWhenHealed; if (dic_Card.ContainsKey(cardtype)) { Heal_Shield(heal); Set_StatusEffect(eStatusConditionsType.Heal_Shield_Add, 1f); } cardtype = eCardType.G1_MaxDodgeWhenHpBelow; if (dic_Card.ContainsKey(cardtype)) { if (m_StatInfo.Get_TotalStat(eStat.HP) > dic_Card[cardtype].m_Data.Get_IntValue1() && m_StatInfo.Get_BuffStat(eStat.Avoid_G1_MaxDodgeWhenHpBelow) > 0) { Set_Buff(eStat.Avoid_G1_MaxDodgeWhenHpBelow, 0); Refresh_PCUI(); } } } public void Heal_Shield(int shield) { m_StatInfo.Set_Stat(true, eStat.Shield, shield); m_HUD_HPShield.Set(m_StatInfo); } public void Heal_Shield(float ratio) { var curshield = m_StatInfo.Get_TotalStat(eStat.Shield); m_StatInfo.Set_Stat(true, eStat.Shield, m_StatInfo.Get_TotalStat(eStat.MaxShield) * ratio); m_HUD_HPShield.Set(m_StatInfo); } public virtual void Heal(eHealType healType, int heal) { m_StatInfo.Set_Stat(true, eStat.HP, heal); m_HUD_HPShield.Set(m_StatInfo); Heal_Common(healType, heal); } public virtual void Heal(eHealType healType, float ratio) { var curhp = m_StatInfo.Get_TotalStat(eStat.HP); m_StatInfo.Set_Stat(true, eStat.HP, m_StatInfo.Get_TotalStat(eStat.MaxHP) * ratio); m_HUD_HPShield.Set(m_StatInfo); Heal_Common(healType, (int)(m_StatInfo.Get_TotalStat(eStat.HP) - curhp)); } public void Refill_AllPotions() { m_StatInfo.Set_Stat(true, eStat.Potion, m_StatInfo.Get_TotalStat(eStat.MaxPotion)); } public void Add_Card_Random(params eGrade[] grade) { var lst = table_cardlist.Ins.Get_DataList(grade); // dic_Card에 없는 카드들만 필터링 var available = lst.FindAll(x => !dic_Card.ContainsKey(x.e_CardType)); if (available.Count > 0) { // 랜덤으로 하나 선택 var randCard = available[Random.Range(0, available.Count)]; InGameInfo.Ins.Add_Card(randCard, false); } } #endregion #region 애니메이션 protected virtual void Play_Attack() { ActorStatus = eActorStatus.Attack; OnEvent_PlayAttack(); } protected virtual void Play_Hit() { } protected virtual void Play_Evasion() { } #endregion public void Off() { gameObject.SetActive(false); } }