using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace vnxbqy.UI { public class AlchemyModel : Model, IBeforePlayerDataInitialize, IPlayerLoginOk { Dictionary m_AlchemyTimes = new Dictionary(); Dictionary> m_AlchemyCounts = new Dictionary>(); Dictionary m_AlchemyQualityLucks = new Dictionary(); Dictionary> m_AlchemyMaterials = new Dictionary>(); Dictionary m_AlchemyDrugUseLimits = new Dictionary(); List m_AlchemyDrugs = new List(); List m_AlchemyDrugQualitys = new List(); List m_AssociationItems = new List(); public readonly Redpoint redpoint = new Redpoint(MainRedDot.RedPoint_key, 110); public readonly Redpoint alchemyDrugRedpoint1 = new Redpoint(110, 11001); public readonly Redpoint alchemyDrugRedpoint2 = new Redpoint(110, 11002); public readonly Redpoint alchemyDrugRedpoint3 = new Redpoint(110, 11003); public readonly Redpoint alchemyDrugRedpoint4 = new Redpoint(110, 11004); Dictionary alchemyRedpoints = new Dictionary(); public static int redpointIndex = 110010000; int m_SelectAlchemy = 0; public int selectAlchemy { get { return m_SelectAlchemy; } set { if (m_SelectAlchemy != value) { m_SelectAlchemy = value; if (selectAlchemyRefresh != null) { selectAlchemyRefresh(); } } } } public AlchemyType selectAlchemyType { get; set; } public int stoveLevel { get; private set; } public int stoveExp { get; private set; } public string alchemySuccRate { get; private set; } public int jumpAlchemy { get; set; } public bool alchemyNormalNotifySymbol { get; set; } public bool alchemyFairyNotifySymbol { get; set; } public int maxBatchAlchemyCount { get; private set; } public int normalBatchAlchemyLevel { get; private set; } Dictionary alchemyRedpointLevelLimits; public int autoFunctionGuideLevel { get; private set; } public bool isServerPrepare { get; private set; } public event Action selectAlchemyRefresh; public event Action alchemyStateRefresh; public event Action alchemyDrugUseRefresh; PackModel packModel { get { return ModelCenter.Instance.GetModel(); } } ReikiRootModel reikiRootModel { get { return ModelCenter.Instance.GetModel(); } } public override void Init() { FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent; PlayerDatas.Instance.playerDataRefreshEvent += PlayerDataRefreshEvent; packModel.refreshItemCountEvent += RefreshItemCountEvent; GlobalTimeEvent.Instance.secondEvent += PerSecond; reikiRootModel.onReikiRootPointRefresh += OnReikiRootPointRefresh; ParseConfig(); } public void OnBeforePlayerDataInitialize() { m_AlchemyTimes.Clear(); stoveLevel = 1; stoveExp = 0; foreach (var item in m_AlchemyDrugUseLimits.Values) { item.SetTimes(0, 0, 0); } isServerPrepare = false; } public void OnPlayerLoginOk() { isServerPrepare = true; CheckRedpoint(); } public override void UnInit() { FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent; PlayerDatas.Instance.playerDataRefreshEvent -= PlayerDataRefreshEvent; packModel.refreshItemCountEvent -= RefreshItemCountEvent; GlobalTimeEvent.Instance.secondEvent -= PerSecond; reikiRootModel.onReikiRootPointRefresh -= OnReikiRootPointRefresh; } private void RefreshItemCountEvent(PackType packType, int arg2, int itemId) { if (m_AssociationItems.Contains(itemId)) { CheckRedpoint(); } if (AttrFruitConfig.Has(itemId)) { CheckRedpoint(); RefreshUseDrugRedpoint(); } } private void OnReikiRootPointRefresh() { if (isServerPrepare) { CheckRedpoint(); } } private void PlayerDataRefreshEvent(PlayerDataType dataType) { if (dataType == PlayerDataType.FreePoint || dataType == PlayerDataType.LV) { CheckRedpoint(); } } private void OnFuncStateChangeEvent(int id) { if (id == (int)FuncOpenEnum.BlastFurnace) { CheckRedpoint(); RefreshUseDrugRedpoint(); } } void ParseConfig() { { var configs = AlchemyCountConfig.GetValues(); foreach (var config in configs) { var intArray = LitJson.JsonMapper.ToObject(config.CntRateList); var min = intArray[0][1]; var max = intArray[intArray.Length - 1][1]; if (!m_AlchemyCounts.ContainsKey(config.AlchemyQuality)) { m_AlchemyCounts[config.AlchemyQuality] = new Dictionary(); } m_AlchemyCounts[config.AlchemyQuality].Add(config.LuckValue, new AlchemyCount() { min = min, max = max, }); } } { var funcConfig = FuncConfigConfig.Get("alchemySuccess"); alchemySuccRate = funcConfig.Numerical3; var json = LitJson.JsonMapper.ToObject(funcConfig.Numerical2); foreach (var key in json.Keys) { var quality = int.Parse(key); m_AlchemyQualityLucks.Add(quality, int.Parse(json[key].ToString())); } funcConfig = FuncConfigConfig.Get("AlchemyRedPoint"); normalBatchAlchemyLevel = int.Parse(funcConfig.Numerical2); alchemyRedpointLevelLimits = ConfigParse.GetDic(funcConfig.Numerical3); autoFunctionGuideLevel = int.Parse(funcConfig.Numerical4); } { var configs = AlchemyConfig.GetValues(); foreach (var config in configs) { m_AlchemyMaterials.Add(config.ID, new List()); var dict = ConfigParse.GetDic(config.Material); foreach (var key in dict.Keys) { m_AlchemyMaterials[config.ID].Add(new Item() { id = key, count = dict[key], }); if (!m_AssociationItems.Contains(key)) { m_AssociationItems.Add(key); } } if (!m_AssociationItems.Contains(config.LearnNeedItemID)) { m_AssociationItems.Add(config.LearnNeedItemID); } } } { var funcConfig = FuncConfigConfig.Get("AlchemyOverLimit"); var itemId = int.Parse(funcConfig.Numerical1); maxBatchAlchemyCount = int.Parse(funcConfig.Numerical2); var configs = AttrFruitConfig.GetValues(); foreach (var config in configs) { if (config.FuncID == 2) { m_AlchemyDrugs.Add(config.ID); var itemConfig = ItemConfig.Get(config.ID); if (!m_AlchemyDrugQualitys.Contains(itemConfig.LV)) { m_AlchemyDrugQualitys.Add(itemConfig.LV); } m_AlchemyDrugUseLimits.Add(config.ID, new AlchemyDrugUseLimit(config.ID, itemId)); } } m_AlchemyDrugQualitys.Sort(); } var alchemys = AlchemyConfig.GetAlchemies((int)AlchemyType.Normal); foreach (var id in alchemys) { alchemyRedpoints.Add(id, new AlchemyRedpoint(alchemyDrugRedpoint1.id)); } alchemys = AlchemyConfig.GetAlchemies((int)AlchemyType.Fairy); foreach (var id in alchemys) { alchemyRedpoints.Add(id, new AlchemyRedpoint(alchemyDrugRedpoint2.id)); } } public bool TryGetAlchemyStartTime(int alchemyId, out AlchemyTime alchemyTime) { return m_AlchemyTimes.TryGetValue(alchemyId, out alchemyTime); } public bool TryGetAlchemyCount(int alchemyId, int luckValue, out AlchemyCount alchemyCount) { var config = AlchemyConfig.Get(alchemyId); alchemyCount = default(AlchemyCount); if (config == null) { return false; } if (config.AlchemType == (int)AlchemyType.Fairy) { alchemyCount = AlchemyCount.one; return true; } var dict = m_AlchemyCounts[config.AlchemyQuality]; foreach (var _luckValue in dict.Keys) { if (luckValue >= _luckValue) { alchemyCount = dict[_luckValue]; } } return !alchemyCount.Equals(default(AlchemyCount)); } public bool TryGetAlchemyMaterials(int alchemyId, out List items) { return m_AlchemyMaterials.TryGetValue(alchemyId, out items); } public bool TryGetAlchemyUseLimit(int id,out AlchemyDrugUseLimit drugUseLimit) { return m_AlchemyDrugUseLimits.TryGetValue(id, out drugUseLimit); } public bool TryLearn(int alchmeyId, out int error) { error = 0; var config = AlchemyConfig.Get(alchmeyId); if (stoveLevel < config.LearnNeedAlchemLV) { error = 2; return false; } if (reikiRootModel.GetReikiRootTotalPointWithFree() < config.LearnNeedLuck) { error = 3; return false; } var count = packModel.GetItemCountByID(PackType.Item, config.LearnNeedItemID); if (count <= 0) { error = 1; return false; } return true; } public bool TryGetAlchemyByStudyMaterial(int id, out int alchemyId) { alchemyId = 0; var configs = AlchemyConfig.GetValues(); foreach (var config in configs) { if (config.LearnNeedItemID == id) { alchemyId = config.ID; return true; } } return false; } public int GetAlchemyRedpointId(int id) { return alchemyRedpoints.ContainsKey(id) ? alchemyRedpoints[id].redpoint.id : 0; } public float GetAlchemySuccRate(int alchemyId) { var config = AlchemyConfig.Get(alchemyId); if (config == null) { return 0f; } if (config.AlchemType == (int)AlchemyType.Fairy) { return 10000f; } var itemConfig = ItemConfig.Get(config.AlchemItemID); var luckValue = PlayerDatas.Instance.extersion.luckValue; return GetAlchemySuccRate(stoveLevel, itemConfig.LV, luckValue); } public float GetAlchemySuccRate(int stoveLevel, int itemLevel, int luck) { Equation.Instance.Clear(); Equation.Instance.AddKeyValue("alchemyLV", stoveLevel); Equation.Instance.AddKeyValue("alchemyQuality", itemLevel); Equation.Instance.AddKeyValue("curLuckValue", luck); var qualityNeedLuck = m_AlchemyQualityLucks.ContainsKey(itemLevel) ? m_AlchemyQualityLucks[itemLevel] : 0; Equation.Instance.AddKeyValue("qualityNeedLuck", qualityNeedLuck); return Equation.Instance.Eval(alchemySuccRate); } public int GetStoveState(int alchemyId) { AlchemyTime alchemyTime; if (TryGetAlchemyStartTime(alchemyId, out alchemyTime) && alchemyTime.startTick > 0) { var config = AlchemyConfig.Get(alchemyId); var startTime = TimeUtility.GetTime(alchemyTime.startTick); var seconds = config.NeedTime * alchemyTime.count - (float)(TimeUtility.ServerNow - startTime).TotalSeconds; return seconds > 0 ? 1 : 2; } return 0; } public ICollection GetDrugQualitys() { return m_AlchemyDrugQualitys; } public ICollection GetAlchemyDrugs() { return m_AlchemyDrugs; } public int GetAlchemyDrugState(int id)//0-可服用丹药 1-达到上限 2-没有丹药 3-没有提升空间 { AlchemyDrugUseLimit drugUseLimit; if (TryGetAlchemyUseLimit(id, out drugUseLimit)) { if (!drugUseLimit.IsReachLimit()) { var count = packModel.GetItemCountByID(PackType.Item, id); return count > 0 ? 0 : 2; } else { return drugUseLimit.CanUpgradeLimit() ? 1 : 3; } } return int.MaxValue; } public int GetAlchemyDrugUseLimit(int id) { AlchemyDrugUseLimit drugUseLimit; if (TryGetAlchemyUseLimit(id, out drugUseLimit)) { return drugUseLimit.GetUseLimit(); } return 0; } public int GetCanAlchemyCount(int alchemyId) { Item item; var count = 0; if (IsAlchemyEnoughMaterial(alchemyId, out item)) { List materials; if (TryGetAlchemyMaterials(alchemyId, out materials)) { for (int i = 0; i < materials.Count; i++) { var mat = materials[i]; var itemCount = packModel.GetItemCountByID(PackType.Item, mat.id); var _count = itemCount / mat.count; if (count == 0) { count = _count; } else { count = Mathf.Min(count, _count); } } } } return count; } public bool IsGraspRecipe(int alchemyId) { return m_AlchemyTimes.ContainsKey(alchemyId); } public bool IsAlchemyEnoughMaterial(int alchemyId, out Item item) { List materials; item = default(Item); if (TryGetAlchemyMaterials(alchemyId, out materials)) { for (int i = 0; i < materials.Count; i++) { var mat = materials[i]; var count = packModel.GetItemCountByID(PackType.Item, mat.id); if (count < mat.count) { item = mat; return false; } } } return true; } public bool IsStoveAlcheming(AlchemyType alchemyType, out int _alchemyId) { _alchemyId = 0; var alchemys = AlchemyConfig.GetAlchemies((int)alchemyType); foreach (var alchemyId in alchemys) { var state = GetStoveState(alchemyId); if (state != 0) { _alchemyId = alchemyId; return true; } } return false; } public void ReceivePackage(HA3BF_tagMCPlayerStoveMsg package) { for (int i = 0; i < package.StoveCnt; i++) { var data = package.InfoList[i]; m_AlchemyTimes[(int)data.AlchemyID] = new AlchemyTime() { startTick = data.StartTime, count = data.AlchemyTimes, }; if (isServerPrepare) { var config = AlchemyConfig.Get((int)data.AlchemyID); if (config != null) { if ((AlchemyType)config.AlchemType == AlchemyType.Normal) { alchemyNormalNotifySymbol = false; } if ((AlchemyType)config.AlchemType == AlchemyType.Fairy) { alchemyFairyNotifySymbol = false; } } } } if (package.StoveCnt == 0) { alchemyNormalNotifySymbol = false; alchemyFairyNotifySymbol = false; } var lastLevel = stoveLevel; var stoveConfig = RefineStoveConfig.Get(stoveLevel); var lastProgress = 0f; if (stoveConfig != null) { lastProgress = Mathf.Clamp01((float)stoveExp / stoveConfig.Exp); } stoveLevel = package.StoveLV; stoveExp = (int)package.StoveExp; if (package.ItemID != 0) { if (isServerPrepare) { if (!NewBieCenter.Instance.inGuiding && WindowCenter.Instance.IsOpen()) { AlchemyResultWin.displayItem = new Item() { id = (int)package.ItemID, count = package.ItemCnt, }; AlchemyResultWin.lastLevel = lastLevel; AlchemyResultWin.lastProgress = lastProgress; WindowCenter.Instance.Open(); } } } CheckRedpoint(); if (alchemyStateRefresh != null) { alchemyStateRefresh(); } } public void ReceivePackage(HA339_tagMCAttrFruitEatCntList vNetData) { for (int i = 0; i < vNetData.count; i++) { var data = vNetData.EatCntList[i]; AlchemyDrugUseLimit drugUseLimit; if (TryGetAlchemyUseLimit((int)data.ItemID, out drugUseLimit)) { drugUseLimit.SetTimes((int)data.EatCnt, (int)data.ItemAddCnt, (int)data.ItemBreakCnt); } } if (alchemyDrugUseRefresh != null) { alchemyDrugUseRefresh(); } CheckRedpoint(); RefreshUseDrugRedpoint(); } private void PerSecond() { if (isServerPrepare) { if (!FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.BlastFurnace)) { return; } var requireCheckRedpoint = false; int alchemyId = 0; if (IsStoveAlcheming(AlchemyType.Normal, out alchemyId) && GetStoveState(alchemyId) == 2 && alchemyRedpoints.ContainsKey(alchemyId) && alchemyRedpoints[alchemyId].endRedpoint.state != RedPointState.Simple) { requireCheckRedpoint = true; } if (IsStoveAlcheming(AlchemyType.Fairy, out alchemyId) && GetStoveState(alchemyId) == 2 && alchemyRedpoints.ContainsKey(alchemyId) && alchemyRedpoints[alchemyId].endRedpoint.state != RedPointState.Simple) { requireCheckRedpoint = true; } if (requireCheckRedpoint) { CheckRedpoint(); } } } static List s_Endables = new List(); static List s_Studyables = new List(); static List s_Alchemyables = new List(); void CheckRedpoint() { s_Endables.Clear(); s_Studyables.Clear(); s_Alchemyables.Clear(); if (!FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.BlastFurnace)) { RefreshRedpoint(); return; } CheckRedpoint(AlchemyType.Normal); CheckRedpoint(AlchemyType.Fairy); RefreshRedpoint(); } void CheckRedpoint(AlchemyType alchemyType) { int alchemyId = 0; if (IsStoveAlcheming(alchemyType, out alchemyId)) { var state = GetStoveState(alchemyId); if (state == 2) { s_Endables.Add(alchemyId); } } else { var hasStudyRed = false; var alchemys = AlchemyConfig.GetAlchemies((int)alchemyType); foreach (var id in alchemys) { if (!IsGraspRecipe(id)) { var config = AlchemyConfig.Get(id); var count = packModel.GetItemCountByID(PackType.Item, config.LearnNeedItemID); if (count <= 0 || stoveLevel < config.LearnNeedAlchemLV || reikiRootModel.GetReikiRootTotalPointWithFree() < config.LearnNeedLuck) { continue; } s_Studyables.Add(id); hasStudyRed = true; } } if (hasStudyRed) { return; } alchemys = AlchemyConfig.GetAlchemies((int)alchemyType); foreach (var id in alchemys) { if (!IsGraspRecipe(id)) { continue; } var config = AlchemyConfig.Get(id); AlchemyDrugUseLimit drugUseLimit; if (TryGetAlchemyUseLimit(config.AlchemItemID, out drugUseLimit)) { if (drugUseLimit.IsReachLimit()) { continue; } var itemCount = packModel.GetItemCountByID(PackType.Item, config.AlchemItemID); if (drugUseLimit.GetUseLimit() - drugUseLimit.eatTimes - itemCount <= 0) { //背包中有足够的灵根丹 continue; } } else { var drugConfig = AttrFruitConfig.Get(config.AlchemItemID); if (drugConfig != null) { if (packModel.GetItemTotalUsedTimes(config.AlchemItemID) >= drugConfig.basicUseLimit) { continue; } } } Item item; if (IsAlchemyEnoughMaterial(id, out item)) { if (alchemyRedpointLevelLimits != null && alchemyRedpointLevelLimits.ContainsKey(id)) { if (PlayerDatas.Instance.baseData.LV >= alchemyRedpointLevelLimits[id]) { continue; } } s_Alchemyables.Add(id); } } } } void RefreshRedpoint() { var alchemys = AlchemyConfig.GetAlchemies((int)AlchemyType.Normal); foreach (var id in alchemys) { var redpoint = alchemyRedpoints[id]; redpoint.studyRedpoint.state = s_Studyables.Contains(id) ? RedPointState.Simple : RedPointState.None; redpoint.endRedpoint.state = s_Endables.Contains(id) ? RedPointState.Simple : RedPointState.None; redpoint.alchemyRedpoint.state = s_Alchemyables.Contains(id) ? RedPointState.Simple : RedPointState.None; } alchemys = AlchemyConfig.GetAlchemies((int)AlchemyType.Fairy); foreach (var id in alchemys) { var redpoint = alchemyRedpoints[id]; redpoint.studyRedpoint.state = s_Studyables.Contains(id) ? RedPointState.Simple : RedPointState.None; redpoint.endRedpoint.state = s_Endables.Contains(id) ? RedPointState.Simple : RedPointState.None; redpoint.alchemyRedpoint.state = s_Alchemyables.Contains(id) ? RedPointState.Simple : RedPointState.None; } } void RefreshUseDrugRedpoint() { var normalUseable = false; var fairyUseable = false; if (FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.BlastFurnace)) { foreach (var itemId in m_AlchemyDrugs) { if (GetAlchemyDrugState(itemId) == 0) { var config = AttrFruitConfig.Get(itemId); if (config.drugType == (int)AlchemyType.Normal) { normalUseable = true; } if (config.drugType == (int)AlchemyType.Fairy) { fairyUseable = true; } if (normalUseable && fairyUseable) { break; } } } } alchemyDrugRedpoint3.state = normalUseable ? RedPointState.Simple : RedPointState.None; alchemyDrugRedpoint4.state = fairyUseable ? RedPointState.Simple : RedPointState.None; } } public enum AlchemyType { Normal = 1, Fairy = 2, } public struct AlchemyCount { public int min; public int max; public static readonly AlchemyCount one = new AlchemyCount() { min = 1, max = 1, }; } public class AlchemyDrugUseLimit { public readonly int id; Dictionary realmLimits = new Dictionary(); Dictionary overLimitItems = new Dictionary(); public int addTimes { get; private set; } public int eatTimes { get; private set; } public int overLimitTimes { get; private set; } public int overLimitMaxTimes { get; private set; } PackModel packModel { get { return ModelCenter.Instance.GetModel(); } } RealmModel realmModel { get { return ModelCenter.Instance.GetModel(); } } public AlchemyDrugUseLimit(int id, int itemId) { this.id = id; var config = AttrFruitConfig.Get(id); foreach (var realmLimit in config.MaxUseCnt) { realmLimits.Add(realmLimit.x, realmLimit.y); } if (!string.IsNullOrEmpty(config.AddItemMaxCnt)) { var array = LitJson.JsonMapper.ToObject(config.AddItemMaxCnt); if (array != null) { for (int i = 0; i < array.Length; i++) { var infoArray = array[i]; overLimitItems.Add(infoArray[0], new OverLimitItem() { itemId = itemId, count = infoArray[1], times = infoArray[2], }); } } overLimitMaxTimes = overLimitItems.Keys.Last(); } } public void SetTimes(int eatTimes, int addTimes, int overLimitTimes) { this.eatTimes = eatTimes; this.addTimes = addTimes; this.overLimitTimes = overLimitTimes; } public int GetUseLimit() { var times = 0; var realmLevel = PlayerDatas.Instance.baseData.realmLevel; foreach (var level in realmLimits.Keys) { if (realmLevel >= level) { times = realmLimits[level]; } } times += addTimes; return times; } public int GetRealmLimit(int realmLevel) { var limit = 0; foreach (var level in realmLimits.Keys) { if (realmLevel >= level) { limit = realmLimits[level]; } } return limit; } public bool IsReachLimit() { var limit = GetUseLimit(); return eatTimes >= limit; } public bool CanUpgradeLimit() { OverLimitItem item; if (CanUpgradeByItem(out item)) { return true; } if (GetNextUpgradeRealm() > 0) { return true; } return false; } public bool CanUpgradeByItem(out OverLimitItem item) { item = default(OverLimitItem); if (overLimitTimes + 1 > overLimitMaxTimes) { return false; } if (overLimitItems.Count > 0) { foreach (var times in overLimitItems.Keys) { if (overLimitTimes + 1 >= times) { item = overLimitItems[times]; } } return !item.Equals(default(OverLimitItem)); } return false; } public int GetNextUpgradeRealm() { var realmLevel = PlayerDatas.Instance.baseData.realmLevel; foreach (var level in realmLimits.Keys) { if (realmLevel < level && level <= realmModel.realmMaxLevel) { return level; } } return 0; } public struct OverLimitItem { public int itemId; public int count; public int times; } } public struct AlchemyTime { public uint startTick; public int count; } public class AlchemyRedpoint { public readonly Redpoint redpoint; public readonly Redpoint studyRedpoint; public readonly Redpoint endRedpoint; public readonly Redpoint alchemyRedpoint; public AlchemyRedpoint(int baseId) { redpoint = new Redpoint(baseId, AlchemyModel.redpointIndex++); studyRedpoint = new Redpoint(redpoint.id, AlchemyModel.redpointIndex++); endRedpoint = new Redpoint(redpoint.id, AlchemyModel.redpointIndex++); alchemyRedpoint = new Redpoint(redpoint.id, AlchemyModel.redpointIndex++); } } }