OneShotOneKill/Assets/Script/My/MyValue.cs

638 lines
25 KiB
C#

using CodeStage.AntiCheat.ObscuredTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Random = UnityEngine.Random;
public static class MyValue
{
public static string OnestoreURL = "https://onesto.re/0000759501";
public static int UTC = 9;
public static int ItemID_Gem = 101, ItemID_Gold = 201, ItemID_Soul = 301, ItemID_Potion = 401, ItemID_Exp = 501,
ItemID_EvolutionMaxStone = 601;
public static Dictionary<eEquipmentParts, int> dic_NeedEvolution = new Dictionary<eEquipmentParts, int>
{ { eEquipmentParts.Ring, 1 }, { eEquipmentParts.Necklace, 2 }, { eEquipmentParts.SubWeapon, 3 } };
public static int PCEvolutionMaxLv = 6, SealMixCount = 3;
public static float MaxAvoid = 0.9f, MaxCri = 0.9f;
public static string OptionKey_UserType = "Option_UserType"; // 0 구글, 1 애플, 2 게스트
public static string OptionKey_UserID = "Option_UserID";
public static string SaveDataFileName = "SaveData";
public static ServerData sdata => ServerInfo.Ins.m_ServerData;
public static MyStageData m_MyStageData = new MyStageData();
public static void Set_StageData(int chapter, int stage)
{
// 정인호 : 난이도, 챕터 정보도 필요
m_MyStageData.m_Diff = 1;
m_MyStageData.m_Chapter = chapter;
m_MyStageData.m_Stage = stage;
m_MyStageData.m_NodeIndex = -1;
m_MyStageData.m_GameMode = eGameMode.Stage;
}
public static ActorStatInfo Get_PCActorStatInfo(int pcid)
{
var pc = InGameInfo.Ins.m_PCActor;
var pctdata = table_pclist.Ins.Get_Data_orNull(pcid);
pc.Set(0, pctdata, IngameUIManager.Ins.PC_HUD_HPShield, sdata);
return Get_ActorStatInfo(pc, pctdata);
}
public static ActorStatInfo Get_ActorStatInfo(Actor actor, ActorTableDataBase actordata)
{
var stat = new ActorStatInfo(actor, true);
stat.Set_Stat(eStat.AttackCoolTime, actordata.f_AttackCoolTime);
stat.Set_Stat(eStat.Attack_Min, actordata.n_AttackMin);
stat.Set_Stat(eStat.Attack_Max, actordata.n_AttackMax);
stat.Set_Stat(eStat.Cri, actordata.f_Cri);
stat.Set_Stat(eStat.CriDmg, actordata.f_CriDmg);
stat.Set_Stat(eStat.HitRate, 100);
if (actor.IsRole(eRole.Mob))
{
stat.Set_Stat(eStat.HP, actordata.n_HP, true);
stat.Set_Stat(eStat.Shield, actordata.n_Shield, true);
stat.Set_Stat(eStat.Avoid_Melee, actordata.n_Avoid_Meele * 100);
stat.Set_Stat(eStat.Avoid_Range, actordata.n_Avoid_Range * 100);
}
else
{
var sdata = actor.Get_ServerData();
var pcid = actor.Get_Data().n_ID;
var addstats = new Dictionary<eStat, float>
{
{ eStat.Attack_Min, 0 }, { eStat.Attack_Max, 0 }, { eStat.MaxHP, 0 }, { eStat.MaxShield, 0 },
{ eStat.HitRate, 0 }, { eStat.Avoid_Melee, 0 }, { eStat.Avoid_Range, 0 }, { eStat.Cri, 0 }, { eStat.CriDmg, 0 },
};
// 2025. 12. 08 : 진화값 추가
var evolution = sdata.Get_PCEvolution(pcid);
for (int i = 1; i < evolution; i++)
{
var evolutionTdata = table_PCEvolution.Ins.Get_Data(pcid, i);
addstats[eStat.Attack_Min] += evolutionTdata.n_AttackValue;
addstats[eStat.Attack_Max] += evolutionTdata.n_AttackValue;
addstats[eStat.MaxHP] += evolutionTdata.n_MaxHPValue;
addstats[eStat.MaxShield] += evolutionTdata.n_MaxShieldValue;
addstats[eStat.HitRate] += evolutionTdata.n_HitRateValue;
}
// 2025. 12. 09 : 한계돌파값 추가
foreach (var key in addstats.Keys.ToList())
{
var lv = sdata.Get_PCEvolutionMax(pcid, key);
if (lv > 0)
{
var tData = table_PCEvolutionMax.Ins.Get_Data(key);
addstats[key] += lv *
(tData.e_Stat == eStat.Avoid_Melee || tData.e_Stat == eStat.Avoid_Range ? tData.f_Value * 100 :
tData.f_Value);
}
}
// 2025.12.27 : 장비값 추가
var equipitems = sdata.Get_EquipItems(pcid);
for (int i = 0; i < equipitems.Count; i++)
{
var equip = equipitems[i];
if (equip == null || equip.ID == 0)
continue;
var tdata = table_EquipmentList.Ins.Get_Data(equip.TableID);
if (tdata == null)
continue;
int lv = equip.Lv;
// ===== Main Option =====
if (tdata.n_MainOtion > 0)
{
var mainOpt = table_StatusOptionSet.Ins.Get_Data(tdata.n_MainOtion);
if (mainOpt != null)
{
ApplyStat(stat, addstats, mainOpt.e_Stat1, tdata.Get_Value(eEquipmentStat.Main1, actordata.n_ID, lv));
ApplyStat(stat, addstats, mainOpt.e_Stat2, tdata.Get_Value(eEquipmentStat.Main2, actordata.n_ID, lv));
}
}
// ===== Sub Options =====
ApplyStat(stat, addstats, tdata, tdata.n_SubOtion1, eEquipmentStat.Sub1, actordata.n_ID, lv);
ApplyStat(stat, addstats, tdata, tdata.n_SubOtion2, eEquipmentStat.Sub2, actordata.n_ID, lv);
ApplyStat(stat, addstats, tdata, tdata.n_SubOtion3, eEquipmentStat.Sub3, actordata.n_ID, lv);
ApplyStat(stat, addstats, tdata, tdata.n_SubOtion4, eEquipmentStat.Sub4, actordata.n_ID, lv);
}
// 2026. 01. 02 : 장비 세트 옵션값 추가
var setitemData = sdata.Get_EquipSetItemData(actordata.n_ID);
if (setitemData != null)
foreach (var item in setitemData.dic_Stat)
ApplyStat(stat, addstats, item.Key, item.Value);
stat.Set_Stat(true, eStat.Attack_Min, addstats[eStat.Attack_Min]);
stat.Set_Stat(true, eStat.Attack_Max, addstats[eStat.Attack_Max]);
stat.Set_Stat(true, eStat.HitRate, addstats[eStat.HitRate]);
stat.Set_Stat(true, eStat.Cri, addstats[eStat.Cri]);
stat.Set_Stat(true, eStat.CriDmg, addstats[eStat.CriDmg]);
stat.Set_Stat(eStat.HP, actordata.n_HP + addstats[eStat.MaxHP], true);
stat.Set_Stat(eStat.Shield, actordata.n_Shield + addstats[eStat.MaxShield], true);
stat.Set_Stat(eStat.Avoid_Melee, actordata.n_Avoid_Meele + addstats[eStat.Avoid_Melee]);
stat.Set_Stat(eStat.Avoid_Range, actordata.n_Avoid_Range + addstats[eStat.Avoid_Range]);
}
// 테스트 : 포션 임의 세팅
stat.Set_Stat(eStat.Potion, 5, true);
return stat;
}
static void ApplyStat(ActorStatInfo stat, Dictionary<eStat, float> addstats, eStat statType, float value)
{
if (addstats.ContainsKey(statType))
addstats[statType] += value;
else
stat.Set_Stat(true, statType, value);
}
static void ApplyStat(ActorStatInfo stat, Dictionary<eStat, float> addstats, EquipmentListTableData tdata,
int optionId, eEquipmentStat estat, int pcid, int lv)
{
if (optionId <= 0) return;
var optData = table_StatusOptionSet.Ins.Get_Data(optionId);
if (optData == null) return;
ApplyStat(stat, addstats, optData.e_Stat1, tdata.Get_Value(estat, pcid, lv));
}
public static Dictionary<eGrade, Color> dic_GradeColor = new Dictionary<eGrade, Color>
{
{ eGrade.None, new Color32(161,152,148,255) },
{ eGrade.Common, new Color32(161,152,148,255) },
{ eGrade.UnCommon, new Color32(158,215,35,255) },
{ eGrade.Rare, new Color32(25,197,240,255) },
{ eGrade.Hero, new Color32(191,106,219,255) },
{ eGrade.Legend, new Color32(252,218,32,255) },
{ eGrade.Grade6, new Color32(240,65,65,255) },
};
}
public enum eStageEnterType { Normal, Tool, Tool_Mob }
public class MyStageData
{
public eStageEnterType m_EnterType = eStageEnterType.Normal;
public eGameMode m_GameMode;
ObscuredInt _diff = 1; public int m_Diff { get { return _diff; } set { _diff = value; _diff.RandomizeCryptoKey(); } }
ObscuredInt _chapter = 1; public int m_Chapter { get { return _chapter; } set { _chapter = value; _chapter.RandomizeCryptoKey(); } }
ObscuredInt _stage; public int m_Stage { get { return _stage; } set { _stage = value; _stage.RandomizeCryptoKey(); } }
ObscuredInt _node; public int m_NodeIndex { get { return _node; }
set
{
_node = value;
_node.RandomizeCryptoKey();
// 스테이지 진행 상황 UI 갱신
if (_node > -1) IngameUIManager.Ins.m_DungeonInfo.m_DungeonProcess.Set();
}
}
public IngameStageData m_StageData;
StageNodeData m_CurNode;
public void Set_CurNodeData()
{
m_CurNode = m_StageData.list_Nodedata.Count > m_NodeIndex ? m_StageData.list_Nodedata[m_NodeIndex] : null;
if (m_CurNode != null && m_CurNode.m_Type == eStageNodeType.Random)
{
var rdnnodedata = m_CurNode.Get_Data<StageNodeData_Random>();
var tabledata = table_RandomPatternConfig.Ins.Get_Data(rdnnodedata.RandomID);
int pick = -1;
int safety = 20; // 무한루프 방지
while (safety-- > 0)
{
var tmp = DSUtil.WeightedPickIndex(tabledata.list_Weight, x => x);
var type = eStageNodeType.Nothing;
switch (tmp)
{
case 1: type = eStageNodeType.Mob; break;
case 2: type = eStageNodeType.BuffDebuff; break;
case 3: type = eStageNodeType.Merchant; break;
case 4: type = eStageNodeType.Treasure; break;
case 5: type = eStageNodeType.NPC; break;
case 6: type = eStageNodeType.Sanctuary; break;
case 7: type = eStageNodeType.TwoWay; break;
}
// 제한 걸린 타입이면 다시 뽑기
if (m_StageData.Use_RandomNodeLimit(type))
{
pick = tmp;
break;
}
}
switch (pick)
{
default: // 없음
m_CurNode.Set_Data(eStageNodeType.Nothing, new StageNodeData_Nothing());
break;
case 1: // 몬스터 등장
{
var mobnodedata = new StageNodeData_Mob();
var patternindex = DSUtil.WeightedPickIndex(m_StageData.list_PatternData, x => x.m_Weight);
var patterndata = m_StageData.list_PatternData[patternindex];
mobnodedata.PatternID = patterndata.m_PatternID;
mobnodedata.MobCount = Mathf.Max(1, patterndata.m_MobCount);
mobnodedata.list_MobID = new List<int>();
var moblst = m_StageData.Get_MonsterList(false);
for (int i = 0; i < mobnodedata.MobCount; i++)
{
var mobindex = DSUtil.WeightedPickIndex(moblst, x => x.m_Weight);
mobnodedata.list_MobID.Add(moblst[mobindex].m_MobID);
}
m_CurNode.Set_Data(eStageNodeType.Mob, mobnodedata);
}
break;
case 2: // 버프/디버프
{
var nodedata = new StageNodeData_BuffDebuff();
nodedata.BuffID = table_BuffPatternConfig.Ins.Get_RandomData().n_BuffOptionID;
m_CurNode.Set_Data(eStageNodeType.BuffDebuff, nodedata);
}
break;
case 3: // 암상인
{
var nodedata = new StageNodeData_Merchant();
nodedata.MerchantID = table_MerchantConfig.Ins.Get_RandomData().n_MerchantID;
m_CurNode.Set_Data(eStageNodeType.Merchant, nodedata);
}
break;
case 4: // 보물 상자
{
var nodedata = new StageNodeData_Treasure();
var tdata = table_TreasureBoxConfig.Ins.Get_RandomData();
nodedata.BoxID = tdata.n_TreasureID;
nodedata.MimicRate = tdata.f_TreasureMimicRate;
m_CurNode.Set_Data(eStageNodeType.Treasure, nodedata);
}
break;
case 5: // NPC
{
var nodedata = new StageNodeData_NPC();
var tdata = table_NPCConfig.Ins.Get_RandomData();
nodedata.NPCID = tdata.n_NPCID;
m_CurNode.Set_Data(eStageNodeType.NPC, nodedata);
}
break;
case 6: // 성소
{
var nodedata = new StageNodeData_Mine();
var tdata = table_SanctuaryConfig.Ins.Get_RandomData();
nodedata.SanctuaryID = tdata.n_BuffOptionID;
m_CurNode.Set_Data(eStageNodeType.Sanctuary, nodedata);
}
break;
case 7: // 갈림길
{ // TODO 정인호 : 갈림길 세부적인 건 추후에...
var nodedata = new StageNodeData_TwoWay();
nodedata.MapConfig1 = "";
nodedata.MapConfig2 = "";
nodedata.ChangeRate = 0.2f;
m_CurNode.Set_Data(eStageNodeType.TwoWay, nodedata);
}
break;
}
}
}
public StageNodeData Get_CurNodeData() { return m_CurNode; }
public int Get_MobID_onStage(eToolMobType type)
{
List<StageMonsterData> candidates = new List<StageMonsterData>();
if (type == eToolMobType.Melee)
{
foreach (var temp in m_StageData.list_MobData)
{
var mobdata = table_monsterlist.Ins.Get_Data_orNull(temp.m_MobID);
if (mobdata != null && mobdata.Get_AttackType() == eAttackType.Melee)
candidates.Add(temp);
}
}
else if (type == eToolMobType.Range)
{
foreach (var temp in m_StageData.list_MobData)
{
var mobdata = table_monsterlist.Ins.Get_Data_orNull(temp.m_MobID);
if (mobdata != null && mobdata.Get_AttackType() == eAttackType.Range)
candidates.Add(temp);
}
}
if (candidates.Count == 0)
return 0; // 없을 때는 0 반환
// 가중치 합계
int totalWeight = 0;
foreach (var c in candidates)
totalWeight += c.m_Weight;
// 랜덤 뽑기
int rand = UnityEngine.Random.Range(1, totalWeight + 1);
int cumulative = 0;
foreach (var c in candidates)
{
cumulative += c.m_Weight;
if (rand <= cumulative)
return c.m_MobID;
}
return candidates[0].m_MobID; // fallback
}
}
public class ActorStatInfo
{
public Actor m_Actor;
Dictionary<eStat, ObscuredDouble> dic_StatValue = new Dictionary<eStat, ObscuredDouble>();
Dictionary<eStat, ObscuredDouble> dic_StatValue_Buff = new Dictionary<eStat, ObscuredDouble>();
Dictionary<eStat, ObscuredDouble> dic_StatValue_Debuff = new Dictionary<eStat, ObscuredDouble>();
bool bInit = false;
public bool IsMainAttack;
void Init()
{
if (!bInit)
{
bInit = true;
for (eStat i = 0; i < eStat.Max; i++)
dic_StatValue.Add(i, 0d);
}
}
public void Clear_All()
{
var keys = new List<eStat>(dic_StatValue.Keys);
foreach (var key in keys) dic_StatValue[key] = 0d;
Clear_BuffDebuff();
}
public void Clear_BuffDebuff()
{
dic_StatValue_Buff.Clear();
dic_StatValue_Debuff.Clear();
}
public ActorStatInfo(Actor actor, bool mainattack)
{
Init();
m_Actor = actor;
IsMainAttack = mainattack;
}
public double Get_Stat(eStat key)
{
if (dic_StatValue.ContainsKey(key))
return dic_StatValue[key].GetDecrypted();
return 0d;
}
public double Get_TotalStat(eStat stat)
{
var rtn = Get_Stat(stat) + Get_BuffStat(stat) - Get_DebuffStat(stat);
switch (stat)
{
// 정수
case eStat.HP:
case eStat.Shield:
case eStat.Potion:
case eStat.HitRate:
return (int)rtn;
case eStat.MaxHP:
{
rtn += Get_BuffStat(eStat.MaxHP_Add);
var mul = Get_BuffStat(eStat.MaxHP_Mul);
return (int)(rtn + (rtn * mul));
}
case eStat.MaxShield:
{
rtn += Get_BuffStat(eStat.MaxShield_Add);
var mul = Get_BuffStat(eStat.MaxShield_Mul);
return (int)(rtn + (rtn * mul));
}
case eStat.Attack_Min:
{
rtn += Get_Stat(eStat.Attack) + Get_BuffStat(eStat.Attack) - Get_DebuffStat(eStat.Attack);
var card = m_Actor.Get_CardSkillData_orNull(eCardType.G5_FlatDamageMinMaxEqual);
if (card != null)
{
var comparestat = eStat.Attack_Max;
var maxdmg = Get_Stat(comparestat) + Get_BuffStat(comparestat) - Get_DebuffStat(comparestat);
rtn = Mathf.Max((int)rtn, (int)maxdmg);
}
var mul = Get_BuffStat(eStat.DmgMul);
return (int)(rtn + (rtn * mul));
}
case eStat.Attack_Max:
{
rtn += Get_Stat(eStat.Attack) + Get_BuffStat(eStat.Attack) - Get_DebuffStat(eStat.Attack);
var card = m_Actor.Get_CardSkillData_orNull(eCardType.G5_FlatDamageMinMaxEqual);
if (card != null)
{
var comparestat = eStat.Attack_Min;
var maxdmg = Get_Stat(comparestat) + Get_BuffStat(comparestat) - Get_DebuffStat(comparestat);
rtn = Mathf.Max((int)rtn, (int)maxdmg);
}
var mul = Get_BuffStat(eStat.DmgMul);
return (int)(rtn + (rtn * mul) + Get_BuffStat(eStat.MaxAttack_byShield));
}
// 정수 분기 (캐릭터 실수, 몬스터 정수)
case eStat.Avoid_Melee:
case eStat.Avoid_Range:
if (m_Actor.IsRole(eRole.PC))
{
var totalavoid = rtn * 0.01f + Get_BuffStat(eStat.AvoidAll_1Time);
totalavoid += Get_BuffStat(eStat.Avoid_G1_MaxDodgeWhenHpBelow);
totalavoid += Get_TotalStat(eStat.AllEvasion);
Set_Buff(eStat.AvoidAll_1Time, 0);
return Math.Min(MyValue.MaxAvoid, totalavoid);
}
return (int)rtn;
// 백분율
case eStat.Cri:
if (IsMainAttack)
{
rtn += Get_BuffStat(eStat.AddCri_1Time) + Get_BuffStat(eStat.AddCri_Once);
Set_Buff(eStat.AddCri_1Time, 0);
Set_Buff(eStat.AddCri_Once, 0);
}
rtn = Math.Min(MyValue.MaxCri, rtn);
break;
case eStat.CriDmg:
{
rtn += Get_BuffStat(eStat.AddCriDmg_1Time);
Set_Buff(eStat.AddCriDmg_1Time, 0);
}
return rtn;
case eStat.AttackCoolTime:
{
var slow = Get_DebuffStat(eStat.Slow);
rtn += rtn * slow;
var past = Get_BuffStat(eStat.AttackCoolTimeMul);
rtn -= rtn * past;
if (rtn <= 0) rtn = 0.1f;
}
break;
}
return rtn;
}
public void Set_Stat(bool _add, eStat key, double _val)
{
if (key >= eStat.Max) return;
if (_add) dic_StatValue[key] += _val;
else dic_StatValue[key] -= _val;
if (key == eStat.HP)
{
var maxhp = Get_TotalStat(eStat.MaxHP);
if (dic_StatValue[key] > maxhp)
dic_StatValue[key] = maxhp;
else if (dic_StatValue[key] < 0)
dic_StatValue[key] = 0;
//if (m_Actor) m_Actor.Set_HUD();
}
else if (key == eStat.Shield)
{
var maxshield = Get_TotalStat(eStat.MaxShield);
if (dic_StatValue[key] > maxshield)
dic_StatValue[key] = maxshield;
else if (dic_StatValue[key] < 0)
dic_StatValue[key] = 0;
//if (m_Actor) m_Actor.Set_HUD();
}
else if (key == eStat.Potion)
{
var maxpotion = Get_TotalStat(eStat.MaxPotion);
if (dic_StatValue[key] > maxpotion)
dic_StatValue[key] = maxpotion;
else if (dic_StatValue[key] < 0)
dic_StatValue[key] = 0;
}
dic_StatValue[key].RandomizeCryptoKey();
}
public void Set_Stat(eStat key, double _val, bool setmax = false)
{
dic_StatValue[key] = _val;
dic_StatValue[key].RandomizeCryptoKey();
if (setmax)
{
if (key == eStat.HP)
{
dic_StatValue[eStat.MaxHP] = _val;
dic_StatValue[eStat.MaxHP].RandomizeCryptoKey();
//if (m_Actor) m_Actor.Set_HUD();
}
else if (key == eStat.Shield)
{
dic_StatValue[eStat.MaxShield] = _val;
dic_StatValue[eStat.MaxShield].RandomizeCryptoKey();
//if (m_Actor) m_Actor.Set_HUD();
}
else if (key == eStat.Potion)
{
dic_StatValue[eStat.MaxPotion] = _val;
dic_StatValue[eStat.MaxPotion].RandomizeCryptoKey();
}
}
}
public double Get_BuffStat(eStat stat) { return dic_StatValue_Buff.ContainsKey(stat) ? dic_StatValue_Buff[stat] : 0d; }
public void Set_Buff(eStat stat, double v)
{
if (stat >= eStat.Max) return;
if (!dic_StatValue_Buff.ContainsKey(stat))
dic_StatValue_Buff.Add(stat, v);
else
dic_StatValue_Buff[stat] = v;
dic_StatValue_Buff[stat].RandomizeCryptoKey();
}
public void Set_Buff(bool add, eStat stat, double v)
{
if (stat >= eStat.Max) return;
if (!dic_StatValue_Buff.ContainsKey(stat))
{
if (add) dic_StatValue_Buff.Add(stat, v);
}
else
{
if (add) dic_StatValue_Buff[stat] += v;
else dic_StatValue_Buff[stat] -= v;
}
dic_StatValue_Buff[stat].RandomizeCryptoKey();
}
public double Get_DebuffStat(eStat stat) { return dic_StatValue_Debuff.ContainsKey(stat) ? dic_StatValue_Debuff[stat] : 0d; }
public void Set_Debuff(eStat stat, double v)
{
if (stat >= eStat.Max) return;
if (!dic_StatValue_Debuff.ContainsKey(stat))
dic_StatValue_Debuff.Add(stat, v);
else
dic_StatValue_Debuff[stat] = v;
dic_StatValue_Debuff[stat].RandomizeCryptoKey();
}
public void Set_Debuff(bool add, eStat stat, double v)
{
if (!dic_StatValue_Debuff.ContainsKey(stat))
{
if (add) dic_StatValue_Debuff.Add(stat, v);
}
else
{
if (add) dic_StatValue_Debuff[stat] += v;
else dic_StatValue_Debuff[stat] -= v;
}
dic_StatValue_Debuff[stat].RandomizeCryptoKey();
}
public void Set_BuffDebuff(ActorStatInfo statinfo)
{
foreach (var item in dic_StatValue_Buff) statinfo.Set_Buff(item.Key, item.Value);
foreach (var item in dic_StatValue_Debuff) statinfo.Set_Debuff(item.Key, item.Value);
}
public int Get_Damage()
{
var dmg = Random.Range((int)Get_TotalStat(eStat.Attack_Min), (int)Get_TotalStat(eStat.Attack_Max) + 1);
return Mathf.Max(dmg, 1); // 최소 데미지 1 보장
}
public bool isFullHP() { return Get_TotalStat(eStat.HP) >= Get_TotalStat(eStat.MaxHP); }
}