using System.Collections.Generic; namespace ET.Server { [FriendOf(typeof(Hero))] public static class HeroService { private const int HeroLevelCap = 60; private const int HeroSkillCap = 10; public static Hero SummonHero(Player player, int configId) { HeroComponent heroComp = player.GetComponent() ?? player.AddComponent(); Hero hero = heroComp.AddHero(configId); player.SetDirty(); LogExtensions.Audit("Hero", "SummonHero", $"{{\"playerId\":{player.Id},\"heroId\":{hero.Id},\"configId\":{configId}}}"); return hero; } public static bool TryAddExp(Player player, Hero hero, int itemId, int itemCount, out string reason) { reason = string.Empty; BagComponent bag = player.GetComponent() ?? player.AddComponent(); var costs = new List { new() { ItemId = itemId, Count = itemCount } }; if (!bag.RemoveItems(costs)) { reason = "item_not_enough"; return false; } int beforeLevel = hero.Level; hero.Exp += itemCount * 100; while (hero.Exp >= hero.Level * 100 && hero.Level < HeroLevelCap) { hero.Exp -= hero.Level * 100; hero.Level += 1; } LogExtensions.Audit("Hero", "HeroAddExp", $"{{\"playerId\":{player.Id},\"heroId\":{hero.Id},\"itemId\":{itemId},\"count\":{itemCount},\"beforeLevel\":{beforeLevel},\"afterLevel\":{hero.Level}}}"); TryAuditFirstMaxLevel(player, hero, beforeLevel); player.SetDirty(); return true; } public static bool TrySkillUp(Player player, Hero hero, int skillIndex, int costItemId, int costCount, out string reason) { reason = string.Empty; if (skillIndex < 0 || skillIndex >= hero.Skills.Count) { reason = "invalid_index"; return false; } if (hero.Skills[skillIndex] >= HeroSkillCap) { reason = "skill_max"; return false; } BagComponent bag = player.GetComponent() ?? player.AddComponent(); var costs = new List { new() { ItemId = costItemId, Count = costCount } }; if (!bag.RemoveItems(costs)) { reason = "item_not_enough"; return false; } int beforeLevel = hero.Skills[skillIndex]; hero.Skills[skillIndex] += 1; LogExtensions.Audit("Hero", "HeroSkillUp", $"{{\"playerId\":{player.Id},\"heroId\":{hero.Id},\"skillIndex\":{skillIndex},\"before\":{beforeLevel},\"after\":{hero.Skills[skillIndex]}}}"); TryAuditFirstMaxSkill(player, hero); player.SetDirty(); return true; } private static void TryAuditFirstMaxLevel(Player player, Hero hero, int beforeLevel) { if (hero.MaxLevelAudited || beforeLevel >= HeroLevelCap || hero.Level < HeroLevelCap) { return; } hero.MaxLevelAudited = true; LogExtensions.Audit("Hero", "HeroFirstMaxLevel", $"{{\"playerId\":{player.Id},\"heroId\":{hero.Id},\"level\":{hero.Level}}}"); } private static void TryAuditFirstMaxSkill(Player player, Hero hero) { if (hero.MaxSkillAudited) { return; } int skillCount = hero.Skills.Count > 4 ? 4 : hero.Skills.Count; for (int i = 0; i < skillCount; ++i) { if (hero.Skills[i] < HeroSkillCap) { return; } } hero.MaxSkillAudited = true; LogExtensions.Audit("Hero", "HeroFirstFullSkill", $"{{\"playerId\":{player.Id},\"heroId\":{hero.Id}}}"); } } }