using System.Collections.Generic; using WingsEmu.DTOs.Items; using WingsEmu.Game._enum; using WingsEmu.Game.Algorithm; using WingsEmu.Game.Buffs; using WingsEmu.Game.Characters; using WingsEmu.Game.Entities; using WingsEmu.Game.EntityStatistics; using WingsEmu.Game.Inventory; using WingsEmu.Game.Items; using WingsEmu.Game.Maps; using WingsEmu.Game.Mates; using WingsEmu.Packets.Enums; namespace WingsEmu.Game.Extensions; public static class AlgorithmExtension { private static readonly HashSet EquipmentTypes = new() { EquipmentType.Sp, EquipmentType.MainWeapon, EquipmentType.SecondaryWeapon, EquipmentType.Armor }; private static readonly HashSet StatsTypes = new() { StatisticType.HITRATE_MAGIC, StatisticType.FIRE, StatisticType.WATER, StatisticType.LIGHT, StatisticType.DARK }; public static byte GetSpeed(this IBattleEntity entity, int speed) { (int firstData, int secondData) increaseSpeedBCard = entity.BCardComponent.GetAllBCardsInformation(BCardType.Move, (byte)AdditionalTypes.Move.MovementSpeedIncreased, entity.Level); (int firstData, int secondData) decreaseSpeedBCard = entity.BCardComponent.GetAllBCardsInformation(BCardType.Move, (byte)AdditionalTypes.Move.MovementSpeedDecreased, entity.Level); int increaseSpeed = increaseSpeedBCard.firstData; increaseSpeed -= decreaseSpeedBCard.firstData; speed += increaseSpeed; switch (entity) { case IPlayerEntity character: switch (character.IsOnVehicle) { case true: return (byte)(character.VehicleSpeed + character.VehicleMapSpeed); case false when character.Specialist != null && character.UseSp: speed += character.Specialist.GameItem.Speed; break; } if (character.IsInvisible()) { speed += character.BCardComponent.GetAllBCardsInformation(BCardType.Move, (byte)AdditionalTypes.Move.InvisibleMovement, entity.Level).firstData; speed -= character.BCardComponent.GetAllBCardsInformation(BCardType.Move, (byte)AdditionalTypes.Move.InvisibleMovementNegated, entity.Level).firstData; } speed += IncreaseByMap(character); break; case IMateEntity mateEntity: if (mateEntity.CanPickUp) { speed += 2; } if (mateEntity.Specialist != null && mateEntity.IsUsingSp) { speed += mateEntity.Specialist.GameItem.Speed; } if (mateEntity.IsTeamMember) { speed += 2; } if (mateEntity.MateType == MateType.Partner && mateEntity.Skin != 0) { speed += 2; } if (mateEntity.Owner.HasBuff(BuffVnums.GUARDIAN_BLESS)) { speed += 2; } break; } double multiplier = 1 + (entity.BCardComponent.GetAllBCardsInformation(BCardType.Move, (byte)AdditionalTypes.Move.MoveSpeedIncreasedPercentage, entity.Level).firstData * 0.01 - entity.BCardComponent.GetAllBCardsInformation(BCardType.Move, (byte)AdditionalTypes.Move.MoveSpeedDecreasedPercentage, entity.Level).firstData * 0.01); speed = (int)(speed * multiplier); if (speed < 0) { speed = 0; } return speed > 59 ? (byte)59 : (byte)speed; } private static int IncreaseByMap(IPlayerEntity character) { int increaseSpeed = 0; IMapInstance mapInstance = character.MapInstance; if (mapInstance == null) { return increaseSpeed; } if (mapInstance.MapInstanceType == MapInstanceType.RainbowBattle) { increaseSpeed += character.BCardComponent .GetAllBCardsInformation(BCardType.IncreaseDamageVersus, (byte)AdditionalTypes.IncreaseDamageVersus.PvpDamageAndSpeedRainbowBattleIncrease, character.Level).secondData; } return increaseSpeed; } public static int GetMaxHp(this IBattleEntity battleEntity, int baseHp) { int hp = baseHp; if (battleEntity is IPlayerEntity character) { hp += character.StatisticsComponent.Passives.GetValueOrDefault(PassiveType.HP); if (character.UseSp) { double multiplier = 1; int point = character.SpecialistComponent.GetSlHp(); if (point <= 50) { multiplier += point * 0.01; } else { multiplier += 0.5 + (point * 0.01 - 0.5) * 2; } hp = (int)(hp * multiplier); hp += character.SpecialistComponent.Hp + character.SpecialistComponent.SpHP * 100; } } int increaseHp = 0; double hpMultiplier = 1; bool bearSpirit = battleEntity.BCardComponent.HasBCard(BCardType.BearSpirit, (byte)AdditionalTypes.BearSpirit.IncreaseMaximumHP); if (bearSpirit) { double bearMultiplier = battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.BearSpirit, (byte)AdditionalTypes.BearSpirit.IncreaseMaximumHP, battleEntity.Level).firstData * 0.01; int bearIncrease = (int)(hp * bearMultiplier); if (bearIncrease > 5000) { bearIncrease = 5000; } hp += bearIncrease; } hpMultiplier += battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.IncreasesMaximumHP, battleEntity.Level).firstData * 0.01; hpMultiplier -= battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.DecreasesMaximumHP, battleEntity.Level).firstData * 0.01; increaseHp += battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.MaximumHPIncreased, battleEntity.Level).firstData; increaseHp += battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.MaximumHPMPIncreased, battleEntity.Level).firstData; increaseHp -= battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.MaximumHPDecreased, battleEntity.Level).firstData; increaseHp -= battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.MaximumHPMPDecreased, battleEntity.Level).firstData; int increaseFinalHp = (int)(hp * hpMultiplier); hp = increaseFinalHp + increaseHp; if (battleEntity is IPlayerEntity playerEntity) { hp += playerEntity.GetJewelsCellonsValue(CellonType.Hp); } return hp; } public static int GetMaxMp(this IBattleEntity battleEntity, int baseMp) { int mp = baseMp; if (battleEntity is IPlayerEntity character) { mp += character.StatisticsComponent.Passives.GetValueOrDefault(PassiveType.MP); if (character.UseSp) { double multiplier = 1; int point = character.SpecialistComponent.GetSlHp(); if (point <= 50) { multiplier += point * 0.01; } else { multiplier += 0.5 + (point * 0.01 - 0.5) * 2; } mp = (int)(mp * multiplier); mp += character.SpecialistComponent.Mp + character.SpecialistComponent.SpHP * 100; } } int increaseMp = 0; double mpMultiplier = 1; bool bearSpirit = battleEntity.BCardComponent.HasBCard(BCardType.BearSpirit, (byte)AdditionalTypes.BearSpirit.IncreaseMaximumMP); double bearMultiplier = battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.BearSpirit, (byte)AdditionalTypes.BearSpirit.IncreaseMaximumMP, battleEntity.Level).Item1 * 0.01; if (bearSpirit) { int bearIncrease = (int)(mp * bearMultiplier); if (bearIncrease > 5000) { bearIncrease = 5000; } mp += bearIncrease; } mpMultiplier += battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.IncreasesMaximumMP, battleEntity.Level).firstData * 0.01; mpMultiplier -= battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.DecreasesMaximumMP, battleEntity.Level).firstData * 0.01; increaseMp += battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.MaximumMPIncreased, battleEntity.Level).firstData; increaseMp += battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.MaximumHPMPIncreased, battleEntity.Level).firstData; increaseMp -= battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.MaximumMPDecreased, battleEntity.Level).firstData; increaseMp -= battleEntity.BCardComponent.GetAllBCardsInformation(BCardType.MaxHPMP, (byte)AdditionalTypes.MaxHPMP.MaximumHPMPDecreased, battleEntity.Level).firstData; int increaseFinalMp = (int)(mp * mpMultiplier); mp = increaseFinalMp + increaseMp; if (battleEntity is IPlayerEntity playerEntity) { mp += playerEntity.GetJewelsCellonsValue(CellonType.Mp); } return mp; } public static void RefreshMaxHpMp(this IBattleEntity entity, IBattleEntityAlgorithmService algorithm) { switch (entity) { case IPlayerEntity character: character.MaxHp = algorithm.GetBasicHpByClass(character.Class, character.Level); character.MaxMp = algorithm.GetBasicMpByClass(character.Class, character.Level); break; case IMateEntity mateEntity: mateEntity.MaxHp = algorithm.GetBasicHp((int)mateEntity.MonsterRaceType, mateEntity.Level, mateEntity.MeleeHpFactor, mateEntity.CleanHp, false); mateEntity.MaxMp = algorithm.GetBasicMp((int)mateEntity.MonsterRaceType, mateEntity.Level, mateEntity.MagicMpFactor, mateEntity.CleanMp, false); break; } } public static long GetLevelXp(this IPlayerEntity character, ICharacterAlgorithm characterAlgorithm) => characterAlgorithm.GetLevelXp(character.Level); public static int GetJobXp(this IPlayerEntity character, ICharacterAlgorithm characterAlgorithm, bool isAdventurer = false) => characterAlgorithm.GetJobXp(character.JobLevel, isAdventurer); public static int GetHeroXp(this IPlayerEntity character, ICharacterAlgorithm characterAlgorithm) => characterAlgorithm.GetHeroLevelXp(character.HeroLevel); public static int GetSpJobXp(this IPlayerEntity character, ICharacterAlgorithm characterAlgorithm, bool isFunSpecialist) => characterAlgorithm.GetSpecialistJobXp(character.Specialist.SpLevel, isFunSpecialist); public static int GetResistance(this IPlayerEntity character, StatisticType type) { int resistance = 0; GameItemInstance specialistInstance = character.Specialist; if (character.UseSp && specialistInstance != null) { resistance += type switch { StatisticType.FIRE => character.SpecialistComponent.FireResistance + specialistInstance.GameItem.FireResistance + character.SpecialistComponent.SpFire, StatisticType.WATER => character.SpecialistComponent.WaterResistance + specialistInstance.GameItem.WaterResistance + character.SpecialistComponent.SpWater, StatisticType.LIGHT => character.SpecialistComponent.LightResistance + specialistInstance.GameItem.LightResistance + character.SpecialistComponent.SpLight, StatisticType.DARK => character.SpecialistComponent.DarkResistance + specialistInstance.GameItem.DarkResistance + character.SpecialistComponent.SpDark }; } resistance += character.FindMoreStats(type); return resistance; } private static int FindMoreStats(this IPlayerEntity character, StatisticType type) { int stats = 0; IReadOnlyDictionary passives = character.StatisticsComponent.Passives; stats += type switch { StatisticType.ATTACK_MELEE => passives.GetValueOrDefault(PassiveType.MELEE_ATTACK), StatisticType.ATTACK_RANGED => passives.GetValueOrDefault(PassiveType.RANGED_ATTACK), StatisticType.ATTACK_MAGIC => passives.GetValueOrDefault(PassiveType.MAGIC_ATTACK), StatisticType.HITRATE_MELEE => passives.GetValueOrDefault(PassiveType.MELEE_HIRATE), StatisticType.HITRATE_RANGED => passives.GetValueOrDefault(PassiveType.RANGED_HIRATE), StatisticType.DEFENSE_MELEE => passives.GetValueOrDefault(PassiveType.MELEE_DEFENCE), StatisticType.DEFENSE_RANGED => passives.GetValueOrDefault(PassiveType.RANGED_DEFENCE), StatisticType.DEFENSE_MAGIC => passives.GetValueOrDefault(PassiveType.MAGIC_DEFENCE), StatisticType.DODGE_MELEE => passives.GetValueOrDefault(PassiveType.MELEE_DODGE), StatisticType.DODGE_RANGED => passives.GetValueOrDefault(PassiveType.RANGED_DODGE), _ => 0 }; foreach (InventoryItem inventoryItem in character.EquippedItems) { GameItemInstance item = inventoryItem?.ItemInstance; if (item == null) { continue; } if (EquipmentTypes.Contains(item.GameItem.EquipmentSlot) && !StatsTypes.Contains(type)) { continue; } if (item.Type == ItemInstanceType.SpecialistInstance) { continue; } stats += type switch { StatisticType.HITRATE_MELEE => item.HitRate + item.GameItem.HitRate, StatisticType.HITRATE_RANGED => item.HitRate + item.GameItem.HitRate, StatisticType.DEFENSE_MELEE => item.CloseDefence + item.GameItem.CloseDefence, StatisticType.DEFENSE_RANGED => item.DistanceDefence + item.GameItem.DistanceDefence, StatisticType.DEFENSE_MAGIC => item.MagicDefence + item.GameItem.MagicDefence, StatisticType.DODGE_MELEE => item.DefenceDodge + item.GameItem.DefenceDodge, StatisticType.DODGE_RANGED => item.DistanceDefenceDodge + item.GameItem.DistanceDefenceDodge, StatisticType.FIRE => item.FireResistance + item.GameItem.FireResistance, StatisticType.WATER => item.WaterResistance + item.GameItem.WaterResistance, StatisticType.LIGHT => item.LightResistance + item.GameItem.LightResistance, StatisticType.DARK => item.DarkResistance + item.GameItem.DarkResistance, _ => 0 }; } return stats; } public static int FindMoreStats(this IMateEntity mateEntity, StatisticType type) { int stats = 0; if (mateEntity.MateType == MateType.Pet) { return stats; } foreach (PartnerInventoryItem inventoryItem in mateEntity.Owner.PartnerGetEquippedItems(mateEntity.PetSlot)) { GameItemInstance item = inventoryItem?.ItemInstance; if (item == null) { continue; } if (item.GameItem.EquipmentSlot == EquipmentType.Sp && !mateEntity.IsUsingSp) { continue; } stats += type switch { StatisticType.HITRATE_MELEE => item.HitRate + item.GameItem.HitRate, StatisticType.HITRATE_RANGED => item.HitRate + item.GameItem.HitRate, StatisticType.DEFENSE_MELEE => item.CloseDefence + item.GameItem.CloseDefence, StatisticType.DEFENSE_RANGED => item.DistanceDefence + item.GameItem.DistanceDefence, StatisticType.DEFENSE_MAGIC => item.MagicDefence + item.GameItem.MagicDefence, StatisticType.DODGE_MELEE => item.DefenceDodge + item.GameItem.DefenceDodge, StatisticType.DODGE_RANGED => item.DistanceDefenceDodge + item.GameItem.DistanceDefenceDodge, StatisticType.FIRE => item.FireResistance + item.GameItem.FireResistance, StatisticType.WATER => item.WaterResistance + item.GameItem.WaterResistance, StatisticType.LIGHT => item.LightResistance + item.GameItem.LightResistance, StatisticType.DARK => item.DarkResistance + item.GameItem.DarkResistance, _ => 0 }; } return stats; } public static int GetHitRate(this IPlayerEntity character, int basic, bool isMainWeapon, StatisticType type) { int hitRate = basic; GameItemInstance mainWeapon = character.MainWeapon; GameItemInstance secondaryWeapon = character.SecondaryWeapon; if (character.UseSp && type != StatisticType.HITRATE_MAGIC) { hitRate += character.SpecialistComponent.HitRate; } hitRate += character.FindMoreStats(type); if (isMainWeapon) { if (mainWeapon == null) { return hitRate; } return hitRate + mainWeapon.HitRate + mainWeapon.GameItem.HitRate; } if (secondaryWeapon == null) { return hitRate; } return hitRate + secondaryWeapon.HitRate + secondaryWeapon.GameItem.HitRate; } public static int GetDodge(this IPlayerEntity character, int basic, StatisticType type) { int dodge = basic; GameItemInstance armorInstance = character.Armor; if (character.UseSp) { dodge += type switch { StatisticType.DODGE_MELEE => character.SpecialistComponent.DefenceDodge, StatisticType.DODGE_RANGED => character.SpecialistComponent.DistanceDefenceDodge }; } dodge += character.FindMoreStats(type); if (armorInstance == null) { return dodge; } dodge += type switch { StatisticType.DODGE_MELEE => armorInstance.DefenceDodge + armorInstance.GameItem.DefenceDodge, StatisticType.DODGE_RANGED => armorInstance.DistanceDefenceDodge + armorInstance.GameItem.DistanceDefenceDodge }; return dodge; } public static int GetCriticalChance(this IPlayerEntity character, int basic, bool isMainWeapon) { int criticalChance = basic; GameItemInstance mainWeapon = character.MainWeapon; GameItemInstance secondaryWeapon = character.SecondaryWeapon; if (character.UseSp) { criticalChance += character.SpecialistComponent.CriticalLuckRate; } if (isMainWeapon) { if (mainWeapon == null) { return criticalChance; } return criticalChance + mainWeapon.GameItem.CriticalLuckRate; } if (secondaryWeapon == null) { return criticalChance; } return criticalChance + secondaryWeapon.GameItem.CriticalLuckRate; } public static int GetCriticalDamage(this IPlayerEntity character, int basic, bool isMainWeapon) { int criticalDamage = basic; GameItemInstance mainWeapon = character.MainWeapon; GameItemInstance secondaryWeapon = character.SecondaryWeapon; if (character.UseSp) { criticalDamage += character.SpecialistComponent.CriticalRate; } if (isMainWeapon) { if (mainWeapon == null) { return criticalDamage; } return criticalDamage + mainWeapon.GameItem.CriticalRate; } if (secondaryWeapon == null) { return criticalDamage; } return criticalDamage + secondaryWeapon.GameItem.CriticalRate; } public static int GetElement(this IPlayerEntity character, bool isSpecialistRate) { int element = 0; GameItemInstance specialist = character.Specialist; if (!isSpecialistRate) { bool isBuffed = character.HasBuff(BuffVnums.FAIRY_BOOSTER); GameItemInstance fairy = character.Fairy; if (fairy == null) { return element; } element += character.BCardComponent.GetAllBCardsInformation(BCardType.IncreaseElementFairy, (byte)AdditionalTypes.IncreaseElementFairy.FairyElementIncrease, character.Level).firstData; element -= character.BCardComponent.GetAllBCardsInformation(BCardType.IncreaseElementFairy, (byte)AdditionalTypes.IncreaseElementFairy.FairyElementDecrease, character.Level).firstData; int finalElement = element + fairy.ElementRate + fairy.GameItem.ElementRate + (isBuffed ? 30 : 0); return finalElement < 0 ? 0 : finalElement; } if (!character.UseSp || specialist == null) { return element; } int point = character.SpecialistComponent.GetSlElement(); int p; if (point <= 50) { p = point; } else { p = 50 + (point - 50) * 2; } return p + character.SpecialistComponent.SpElement; } public static int GetDefence(this IPlayerEntity character, int basic, StatisticType statisticType) { int armor = basic; GameItemInstance armorInstance = character.Armor; GameItemInstance specialist = character.Specialist; if (character.UseSp) { int point = character.SpecialistComponent.GetSlDefense(); int p = point switch { <= 10 => point, <= 20 => 10 + (point - 10) * 2, <= 30 => 30 + (point - 20) * 3, <= 40 => 60 + (point - 30) * 4, <= 50 => 100 + (point - 40) * 5, <= 60 => 150 + (point - 50) * 6, <= 70 => 210 + (point - 60) * 7, <= 80 => 280 + (point - 70) * 8, <= 90 => 360 + (point - 80) * 9, <= 100 => 450 + (point - 90) * 10, _ => 0 }; armor += character.SpecialistComponent.SpDefence * 10; switch (statisticType) { case StatisticType.DEFENSE_MELEE: armor += character.SpecialistComponent.CloseDefence; break; case StatisticType.DEFENSE_RANGED: armor += character.SpecialistComponent.DistanceDefence; break; case StatisticType.DEFENSE_MAGIC: armor += character.SpecialistComponent.MagicDefence; break; } armor += p; } armor += character.FindMoreStats(statisticType); if (armorInstance == null) { return armor; } switch (statisticType) { case StatisticType.DEFENSE_MELEE: return armor + armorInstance.CloseDefence + armorInstance.GameItem.CloseDefence; case StatisticType.DEFENSE_RANGED: return armor + armorInstance.DistanceDefence + armorInstance.GameItem.DistanceDefence; case StatisticType.DEFENSE_MAGIC: return armor + armorInstance.MagicDefence + armorInstance.GameItem.MagicDefence; } return armor; } public static int GetDamage(this IPlayerEntity character, int basic, bool isMin, StatisticType type, bool isMainWeapon = true) { int damage = basic; GameItemInstance mainWeapon = character.MainWeapon; GameItemInstance secondaryWeapon = character.SecondaryWeapon; if (character.UseSp) { int point = character.SpecialistComponent.GetSlHit(); int p = point switch { <= 10 => point * 5, <= 20 => 50 + (point - 10) * 6, <= 30 => 110 + (point - 20) * 7, <= 40 => 180 + (point - 30) * 8, <= 50 => 260 + (point - 40) * 9, <= 60 => 350 + (point - 50) * 10, <= 70 => 450 + (point - 60) * 11, <= 80 => 560 + (point - 70) * 13, <= 90 => 690 + (point - 80) * 14, <= 94 => 830 + (point - 90) * 15, <= 95 => 890 + 16, <= 97 => 906 + (point - 95) * 17, <= 100 => 940 + (point - 97) * 20, _ => 0 }; damage += p; damage += character.SpecialistComponent.SpDamage * 10; if (isMin) { damage += character.SpecialistComponent.DamageMinimum; } else { damage += character.SpecialistComponent.DamageMaximum; } } damage += character.FindMoreStats(type); if (isMainWeapon) { if (mainWeapon == null) { return damage; } if (isMin) { return damage + mainWeapon.DamageMinimum + mainWeapon.GameItem.DamageMinimum; } return damage + mainWeapon.DamageMaximum + mainWeapon.GameItem.DamageMaximum; } if (secondaryWeapon == null) { return damage; } if (isMin) { return damage + secondaryWeapon.DamageMinimum + secondaryWeapon.GameItem.DamageMinimum; } return damage + secondaryWeapon.DamageMaximum + secondaryWeapon.GameItem.DamageMaximum; } public static int SlPoint(this GameItemInstance specialistInstance, short spPoint, SpecialistPointsType type) { try { int point = 0; switch (type) { case SpecialistPointsType.ATTACK: point = spPoint switch { <= 10 => spPoint, <= 28 => 10 + (spPoint - 10) / 2, <= 88 => 19 + (spPoint - 28) / 3, <= 168 => 39 + (spPoint - 88) / 4, <= 268 => 59 + (spPoint - 168) / 5, <= 334 => 79 + (spPoint - 268) / 6, <= 383 => 90 + (spPoint - 334) / 7, <= 391 => 97 + (spPoint - 383) / 8, <= 400 => 98 + (spPoint - 391) / 9, <= 410 => 99 + (spPoint - 400) / 10, _ => point }; break; case SpecialistPointsType.DEFENCE: point = spPoint switch { <= 10 => spPoint, <= 48 => 10 + (spPoint - 10) / 2, <= 81 => 29 + (spPoint - 48) / 3, <= 161 => 40 + (spPoint - 81) / 4, <= 236 => 60 + (spPoint - 161) / 5, <= 290 => 75 + (spPoint - 236) / 6, <= 360 => 84 + (spPoint - 290) / 7, <= 400 => 97 + (spPoint - 360) / 8, <= 410 => 99 + (spPoint - 400) / 10, _ => point }; break; case SpecialistPointsType.ELEMENT: point = spPoint switch { <= 20 => spPoint, <= 40 => 20 + (spPoint - 20) / 2, <= 70 => 30 + (spPoint - 40) / 3, <= 110 => 40 + (spPoint - 70) / 4, <= 210 => 50 + (spPoint - 110) / 5, <= 270 => 70 + (spPoint - 210) / 6, <= 410 => 80 + (spPoint - 270) / 7, _ => point }; break; case SpecialistPointsType.HPMP: point = spPoint switch { <= 10 => spPoint, <= 50 => 10 + (spPoint - 10) / 2, <= 110 => 30 + (spPoint - 50) / 3, <= 150 => 50 + (spPoint - 110) / 4, <= 200 => 60 + (spPoint - 150) / 5, <= 260 => 70 + (spPoint - 200) / 6, <= 330 => 80 + (spPoint - 260) / 7, <= 410 => 90 + (spPoint - 330) / 8, _ => point }; break; } return point; } catch { return 0; } } public static int SpPointsBasic(this GameItemInstance specialistInstance) { short spLevel = specialistInstance.SpLevel; int point = (spLevel - 20) * 3; if (spLevel <= 20) { point = 0; } switch (specialistInstance.Upgrade) { case 1: point += 5; break; case 2: point += 10; break; case 3: point += 15; break; case 4: point += 20; break; case 5: point += 28; break; case 6: point += 36; break; case 7: point += 46; break; case 8: point += 56; break; case 9: point += 68; break; case 10: point += 80; break; case 11: point += 95; break; case 12: point += 110; break; case 13: point += 128; break; case 14: point += 148; break; case 15: point += 173; break; } return point; } }