using System; using System.Collections.Generic; using Cal; using Cal.DataTable; using System.Linq; namespace ET { public class CharacterHelper { public enum MoneyType { UnKnown = 0, YuanBao = 1, Voucher = 2, Coin = 3, Gem = 4, } private readonly static float[] CharacterPointScaleArr = { 0.1f, 0.42f, 1.07f, 1.89f }; internal static void ResetAddNumeric(Unit unit, NumericComponent num) { num ??= unit.GetComponent(); if (num == null) { Log.Error($"num == null where id = {unit?.Id}"); return; } num.ReSetAddNum(); } public static void InitData(NumericComponent num) { Character character = num.Parent.GetComponent(); num.Set(NumericType.Level, 1); num.Set(NumericType.Exp, 0); character.Set(AttributeType.力量, 1); character.Set(AttributeType.敏捷, 1); character.Set(AttributeType.智慧, 1); character.Set(AttributeType.精神, 1); character.Set(AttributeType.体质, 1); character.Set(AttributeType.耐力, 1); } public static void RecoverUnit(Unit unit) { NumericComponent num = unit.GetComponent(); num.Set(NumericType.Hp, num.Get(NumericType.MaxHp)); num.Set(NumericType.Mp, num.Get(NumericType.MaxMp)); } private static NumericType[] numTypeArr; public static M2C_SyncUnitAttributeList GetSyncUnitAttributeList(Unit unit) { NumericComponent num = unit.GetComponent(); if (numTypeArr == null) { Array arr = Enum.GetValues(typeof(NumericType)); numTypeArr = (NumericType[])arr; } M2C_SyncUnitAttributeList list = new M2C_SyncUnitAttributeList(); foreach (NumericType type in numTypeArr) { if (type < NumericType.Max) { float value = num.Get(type); if (value != 0) list.NumericMap.Add(new AttributeMap { Key = (int)type, Value = value, }); } } return list; } public static void SyncAttribute(Unit unit) { if (!unit) return; NumericComponent num = unit.GetComponent(); DelaySendSyncAttributeComponent component = DelaySendSyncAttributeComponent.instance; if (numTypeArr == null) { Array arr = Enum.GetValues(typeof(NumericType)); numTypeArr = (NumericType[])arr; } foreach (NumericType type in numTypeArr) { if (type < NumericType.Max) { float value = num.Get(type); if (value != 0) component.Add(unit, type, value); } } } public static void SyncNumeric(Unit unit) { NumericComponent num = unit.GetComponent(); Combat combat = unit.GetComponent(); if (combat) SyncNumeric(num, combat); } public static void SyncNumeric(NumericComponent num, Combat combat) { foreach (AttributeType type in Enum.GetValues(typeof(AttributeType))) { SetNumValue(num, combat, type); } } private static void SetNumValue(NumericComponent num, Combat combat, AttributeType type) { switch (type) { case AttributeType.最大生命: num.Set(NumericType.MaxHpBase, combat.GetAtribute(type)); break; case AttributeType.最大精力: num.Set(NumericType.MaxMpBase, combat.GetAtribute(type)); break; case AttributeType.力量: num.Set(NumericType.StrBase, combat.GetAtribute(type)); break; case AttributeType.敏捷: num.Set(NumericType.QukBase, combat.GetAtribute(type)); break; case AttributeType.精神: num.Set(NumericType.SpiBase, combat.GetAtribute(type)); break; case AttributeType.智慧: num.Set(NumericType.WimBase, combat.GetAtribute(type)); break; case AttributeType.物理攻击: num.Set(NumericType.PhyAtkBase, combat.GetAtribute(type)); break; case AttributeType.精神攻击: num.Set(NumericType.SpiAtkBase, combat.GetAtribute(type)); break; case AttributeType.物理防御: num.Set(NumericType.PhyDefBase, combat.GetAtribute(type)); break; case AttributeType.精神防御: num.Set(NumericType.SpiDefBase, combat.GetAtribute(type)); break; case AttributeType.物理暴击系数: num.Set(NumericType.PcrirBase, combat.GetAtribute(type)); break; case AttributeType.精神暴击系数: num.Set(NumericType.McrirBase, combat.GetAtribute(type)); break; case AttributeType.物理暴击效果: num.Set(NumericType.PcriBase, combat.GetAtribute(type)); break; case AttributeType.精神暴击效果: num.Set(NumericType.McriBase, combat.GetAtribute(type)); break; case AttributeType.抗物理暴击系数: num.Set(NumericType.RpcrirBase, combat.GetAtribute(type)); break; case AttributeType.抗精神暴击系数: num.Set(NumericType.RmcrirBase, combat.GetAtribute(type)); break; case AttributeType.抗物理暴击效果: num.Set(NumericType.RpcriBase, combat.GetAtribute(type)); break; case AttributeType.抗精神暴击效果: num.Set(NumericType.RmcriBase, combat.GetAtribute(type)); break; case AttributeType.辅助值: num.Set(NumericType.DvoBase, combat.GetAtribute(type)); break; case AttributeType.体质: num.Set(NumericType.PhyBase, combat.GetAtribute(type)); break; case AttributeType.耐力: num.Set(NumericType.StaBase, combat.GetAtribute(type)); break; case AttributeType.物理免伤: num.Set(NumericType.NphyiBase, combat.GetAtribute(type)); break; case AttributeType.精神免伤: num.Set(NumericType.NmeniBase, combat.GetAtribute(type)); break; case AttributeType.速度: num.Set(NumericType.SpdBase, combat.GetAtribute(type)); break; case AttributeType.命中: num.Set(NumericType.HitBase, combat.GetAtribute(type)); break; case AttributeType.抵抗: num.Set(NumericType.ResBase, combat.GetAtribute(type)); break; case AttributeType.无: break; case AttributeType.吸血率: num.Set(NumericType.SuckRBase, combat.GetAtribute(type)); break; case AttributeType.吸血量: num.Set(NumericType.SuckVBase, combat.GetAtribute(type)); break; case AttributeType.生命回复: num.Set(NumericType.HpRecoverBase, combat.GetAtribute(type)); break; case AttributeType.物理增伤: num.Set(NumericType.PhyDABase, combat.GetAtribute(type)); break; case AttributeType.精神增伤: num.Set(NumericType.MicDABase, combat.GetAtribute(type)); break; default: break; } } public static int GetCharacterPoint(int oldLevel, int level, int perLevel) { if (perLevel == 0) { Log.Error($"perLevel == 0"); return 0; } // 9->10 10->11 11->30 30->40 // 0,1 1,1 1,3 3->4 int oldTimes = oldLevel / perLevel; int newTimes = level / perLevel; return newTimes - oldTimes; } public static float GetCharacterPoint(float oldLevel, float level, float perLevel) { if (perLevel == 0) { Log.Error($"perLevel == 0"); return 0; } int oldTimes = (int)(oldLevel / perLevel); int newTimes = (int)(level / perLevel); return newTimes - oldTimes; } public static float GetAttributeByPoint(Combat combat, AttributeType attributeType, float str, float wim, float quk, float spi, float phy, float sta) { User user = UserComponent.Instance.Get(combat.Id); if (user == null) return 0; int job = (user.JobId + 1) / 2; CharacterGrowth growth = DataTableHelper.Get((int)attributeType * 10 + job); if (growth == null) { Log.Error($"growth = null where id = {(int)attributeType * 10 + job}"); } return growth.Str * str + growth.Wim * wim + growth.Quk * quk + growth.Spi * spi + growth.Phy * phy + growth.Sta * sta; } public static void AddPoint(Character num, AttributeType type, int value) { num.AddPoint(type, value); } public static void ResetPoint(Unit unit) { Character character = unit.GetComponent(); int point = character.RemovePoint(); PlayerData data = unit.GetComponent(); data.CharacterPointKV.Deconstruct(out int canUse, out int total); canUse += point; data.CharacterPointKV = KeyValuePair.Create(canUse, total); } public static void AddExp(Unit unit, long exp) { NumericComponent num = unit.GetComponent(); num.AddSet(NumericType.Exp, exp); } public static void AddLevel(Unit unit, int _level) { NumericComponent num = unit.GetComponent(); int level = num.GetAsInt(NumericType.Level); int trans = num.GetAsInt(NumericType.Transmigration); long needExp = 0; int currLevel = level; for (int i = level; i < level + _level; i++) { long need = GetUpgradeLevelExp(trans, currLevel++); if (need == -1) continue; needExp += need; } AddExp(unit, needExp); } public static int GetLargerAtk(NumericComponent num) { int phyAtk = num.GetAsInt(NumericType.PhyAtk); int spiAtk = num.GetAsInt(NumericType.SpiAtk); return phyAtk > spiAtk ? phyAtk : spiAtk; } public static AttributeType GetAtkType(int jobId) { if (jobId <= 4) return AttributeType.物理攻击; else return AttributeType.精神攻击; } private const int MaxSpeed = 7000; public static float GetSpeed(int value) { return (float)(MaxSpeed * Math.Atan(value / 10000f) * 2 / MathF.PI); } /// /// 1-(x/7000)^2 1 -> 0 /// 6000 -> 4000 /// 4000 + 2000*(1-(x/7000)^2) /// /// /// public static float GetSkillCD(float spd) { float cd = 4000 + 2000 * (1 - MathF.Pow(spd / MaxSpeed, 2)); if (cd < 4000) cd = 4000; return cd; } public static bool CheckCanTransmigrate(NumericComponent num, int level) { int trans = GetTransmigrationByLevel(level); int transNum = num.GetAsInt(NumericType.Transmigration); if (transNum >= trans) return true; return false; } private readonly static int[] levelArr = { 0, 6000, 13000, 21500, 31500 }; public static int GetTransmigrationLevel(int level) { for (int i = 0; i < levelArr.Length - 1; i++) { if (level < levelArr[i]) { return levelArr[i]; } } return levelArr[0]; } public static int GetTransmigrationLevelByTrans(int trans) { return levelArr[trans + 1]; } public static int GetCurrBaseLevel(int level) { for (int i = 0; i < levelArr.Length - 1; i++) { if (level <= levelArr[i]) { if (i == 0) return levelArr[0]; return levelArr[i - 1]; } } return levelArr[0]; } public static int GetTransmigrationByLevel(int level) { for (int i = 0; i < levelArr.Length - 1; i++) { if (level < levelArr[i]) { if (i == 0) return 0; return i - 1; } } return 0; } public static async ETTask GetUnitCharacter(Unit unit, User user = null, NumericComponent num = null) { user ??= await UserComponent.Instance.Query(unit.Id); if (user == null) { Log.Error($"user == null where id= {unit?.Id}"); return new UnitCharacter(); } PlayerData data = unit.GetComponent(); num ??= unit.GetComponent(); Pet pet = unit.GetComponent(); UnitCharacter unitCharacter = new UnitCharacter { Id = unit.Id, NickName = user.NickName, JobId = user.JobId, Title = num.GetAsInt(NumericType.Title), CampType = user.CampType, Family = user.Family, SkinId = user.SkinId, Level = user.Level, LeaderId = unit.TeamLeaderId, Trans = num.GetAsInt(NumericType.Transmigration), Hp = num.GetAsInt(NumericType.Hp), MaxHp = num.GetAsInt(NumericType.MaxHp), Mp = num.GetAsInt(NumericType.Mp), MaxMp = num.GetAsInt(NumericType.MaxMp), PetId = pet.petId , isShowPet = pet.isShow, PetLevel = pet.level, PetName = pet.name, }; unitCharacter.CharacterPoint = data.CharacterPointKV.Key; unitCharacter.SkillPoint = data.SkillPointKV.Key; return unitCharacter; } /// /// 支付 /// /// /// /// /// null is correct public static string ReduceMoney(Unit unit, MoneyType moneyType, long price) { NumericComponent num = unit.GetComponent(); switch (moneyType) { case MoneyType.Coin: { if (num.GetAsLong(NumericType.Coin) < price) return "您的金币不足,无法购买!"; num.ReduceSet(NumericType.Coin, price); } break; case MoneyType.YuanBao: { if (num.GetAsInt(NumericType.YuanBao) < price) return "您的元宝不足,无法购买!"; num.ReduceSet(NumericType.YuanBao, (int)price); } break; case MoneyType.Voucher: { if (num.GetAsInt(NumericType.Voucher) < price) return "您的代金券不足,无法购买!"; num.ReduceSet(NumericType.Voucher, (int)price); } break; case MoneyType.Gem: { if (num.GetAsLong(NumericType.Gem) < price) return "您的星币不足,无法购买!"; num.ReduceSet(NumericType.Gem, price); } break; } return null; } public static void AddMoney(Unit unit, MoneyType moneyType, long price) { NumericComponent num = unit.GetComponent(); switch (moneyType) { case MoneyType.Coin: num.AddSet(NumericType.Coin, price); break; case MoneyType.YuanBao: num.AddSet(NumericType.YuanBao, (int)price); break; case MoneyType.Voucher: num.AddSet(NumericType.Voucher, (int)price); break; case MoneyType.Gem: num.AddSet(NumericType.Gem, price); break; } } public static void AddAutoCharacterPoint(NumericComponent num, PlayerData data, int oldLevel, int level) { //!10级一个自动属性 int dLevel = GetRelationLevel(level); int point = CharacterHelper.GetCharacterPoint(oldLevel, level, ConstDefine.AutoAddCharacterPointPerLevel); if (point > 0) { Unit unit = num.GetParent(); Character character = unit.GetComponent(); character.AddAllPoint(point); CharacterHelper.SyncNumeric(unit); } KeyValuePair kp = data.CharacterPointKV; int totalPoint = dLevel / ConstDefine.AddCharacterPointPerLevel; kp.Deconstruct(out int key, out int value); int dPoint = totalPoint - value; value = totalPoint; key += dPoint; data.CharacterPointKV = KeyValuePair.Create(key, value); } public static void AddSkillPoint(PlayerData data, int level) { int trans = data.Parent.GetComponent().GetAsInt(NumericType.Transmigration); int totalPoint = 0; for (int i = 0; i < trans; i++) { totalPoint += GetRelationLevel(levelArr[i + 1]) / ConstDefine.AddSkillPointPerLevelArr[i]; } totalPoint += GetRelationLevel(level) / ConstDefine.AddSkillPointPerLevelArr[trans]; data.SkillPointKV.Deconstruct(out int key, out int value); int dPoint = totalPoint - value; value = totalPoint; key += dPoint; data.SkillPointKV = KeyValuePair.Create(key, value); } public static async ETTask ReSetCharacter(Unit unit) { if (unit == null) { return; } Character character = unit.GetComponent(); character.ReSet(); NumericComponent num = unit.GetComponent(); CharacterHelper.InitData(num); num.Set(NumericType.Transmigration, 0); PlayerData data = unit.GetComponent(); data.CharacterPointKV = KeyValuePair.Create(0, 0); data.SkillPointKV = KeyValuePair.Create(0, 0); UnitSkillComponent unitSkillComponent = unit.GetComponent(); await unitSkillComponent.ResetSkill(); CharacterHelper.SyncNumeric(unit); UnitHelper.SaveComponenet(character).Coroutine(); UnitHelper.SaveComponenet(data).Coroutine(); UnitHelper.SaveComponenet(num).Coroutine(); CharacterHelper.SyncAttribute(unit); } public static long GetUpgradeLevelExp(Unit unit) { NumericComponent num = unit.GetComponent(); int trans = num.GetAsInt(NumericType.Transmigration); int level = num.GetAsInt(NumericType.Level); long needExp = GetUpgradeLevelExp(trans, level); return needExp; } public static long GetUpgradeLevelExp(int trans, int level) { int trans_ = GetTransmigrationByLevel(level); if (trans_ != trans) return -1; level = GetRelationLevel(level); long needExp = (long)(ConstDefine.ExpBaseArr[trans] * MathF.Pow(level, ConstDefine.ExpPowerArr[trans])); return needExp; } /// /// 获取相对于转生等级的等级差,0-5999->0 /// /// /// public static int GetRelationLevel(int level) { int transLevel = GetCurrBaseLevel(level); return level - transLevel; } public static async ETTask Transmigration(Unit unit) { NumericComponent num = unit.GetComponent(); int trans = num.GetAsInt(NumericType.Transmigration); int level = num.GetAsInt(NumericType.Level); int transLevel = GetTransmigrationLevelByTrans(trans); if (level != transLevel) { Log.Info($"【{UserComponent.Instance.Get(unit.Id)?.NickName}({unit.Id})】level = {level} not equals transLevel = {transLevel}"); return "等级不符合"; } if (++trans >= levelArr.Length) return "达到上限"; User user = await UserComponent.Instance.Query(unit.Id); if (user == null) return "玩家不存在"; int id = (user.JobId + 1) / 2 * 10 + trans; TransmigrationAddConfig addConfig = TransmigrationAddConfigCategory.Instance.Get(id); if (addConfig == null) return $"配置不存在 {id}"; //重置等级,属性点 Character character = unit.GetComponent(); num.Set(NumericType.Exp, 0, false); num.AddSet(NumericType.Level, 1); character.Set(AttributeType.力量, 1); character.Set(AttributeType.敏捷, 1); character.Set(AttributeType.智慧, 1); character.Set(AttributeType.精神, 1); character.Set(AttributeType.体质, 1); character.Set(AttributeType.耐力, 1); character.ReSet(); PlayerData data = unit.GetComponent(); data.CharacterPointKV = KeyValuePair.Create(0, 0); //增加永久属性 foreach (TransmigrationAddConfig.AddAttribute addAttribute in addConfig.AddAttributeArr) { character.SetAdd((AttributeType)addAttribute.Key, addAttribute.Value); } num.Set(NumericType.Transmigration, trans); //计算结果,同步 CharacterHelper.SyncNumeric(unit); UnitHelper.SaveComponenet(character).Coroutine(); UnitHelper.SaveComponenet(data).Coroutine(); UnitHelper.SaveComponenet(num).Coroutine(); CharacterHelper.SyncAttribute(unit); return null; } /// /// 转职 /// /// /// 1,2,3,4 public static async ETTask TransferJob(Unit unit, int jobType, bool isFree) { User user = await UserComponent.Instance.Query(unit.Id); int jobId = user.JobId; SexType sexType = JobHelper.GetSexType(jobId); user.JobId = (int)(sexType + jobType * 2 - 1); UnitSkillComponent unitSkillComponent = unit.GetComponent(); unitSkillComponent.TransferJob(jobType); await UserComponent.Instance.Save(user); } } }