using System.Text; using Milimoe.FunGame.Core.Api.Transmittal; using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Library.Constant; using Oshima.Core.Constant; using Oshima.FunGame.OshimaModules.Characters; using Oshima.FunGame.OshimaModules.Effects.OpenEffects; using Oshima.FunGame.OshimaModules.Items; using Oshima.FunGame.OshimaModules.Models; using Oshima.FunGame.OshimaModules.Regions; using Oshima.FunGame.OshimaModules.Skills; using Oshima.FunGame.OshimaModules.Units; using Oshima.FunGame.OshimaServers.Model; using ProjectRedbud.FunGame.SQLQueryExtension; namespace Oshima.FunGame.OshimaServers.Service { public class FunGameService { public static Dictionary> UserExploreCharacterCache { get; } = []; public static Dictionary> UserExploreItemCache { get; } = []; public static Dictionary> UserExploreEventCache { get; } = []; public static HashSet Activities { get; } = []; public static List ActivitiesCharacterCache { get; } = []; public static List ActivitiesItemCache { get; } = []; public static List ActivitiesEventCache { get; } = []; public static Dictionary> UserNotice { get; } = []; public static Dictionary Bosses { get; } = []; public static ServerPluginLoader? ServerPluginLoader { get; set; } = null; public static WebAPIPluginLoader? WebAPIPluginLoader { get; set; } = null; public static EntityModuleConfig Notices { get; } = new("notices", "notice"); public static void InitFunGame() { FunGameConstant.Characters.Add(new OshimaShiya()); FunGameConstant.Characters.Add(new XinYin()); FunGameConstant.Characters.Add(new Yang()); FunGameConstant.Characters.Add(new NanGanYu()); FunGameConstant.Characters.Add(new NiuNan()); FunGameConstant.Characters.Add(new DokyoMayor()); FunGameConstant.Characters.Add(new MagicalGirl()); FunGameConstant.Characters.Add(new QingXiang()); FunGameConstant.Characters.Add(new QWQAQW()); FunGameConstant.Characters.Add(new ColdBlue()); FunGameConstant.Characters.Add(new dddovo()); FunGameConstant.Characters.Add(new Quduoduo()); FunGameConstant.Skills.AddRange([new 疾风步()]); FunGameConstant.SuperSkills.AddRange([new 嗜血本能(), new 平衡强化(), new 绝对领域(), new 精准打击(), new 三重叠加(), new 变幻之心(), new 力量爆发(), new 能量毁灭(), new 血之狂欢(), new 迅捷之势(), new 天赐之力(), new 魔法涌流()]); FunGameConstant.PassiveSkills.AddRange([new META马(), new 心灵之火(), new 魔法震荡(), new 灵能反射(), new 智慧与力量(), new 致命打击(), new 毁灭之势(), new 枯竭打击(), new 破釜沉舟(), new 累积之压(), new 敏捷之刃(), new 弱者猎手()]); FunGameConstant.Magics.AddRange([new 冰霜攻击(), new 火之矢(), new 水之矢(), new 风之轮(), new 石之锤(), new 心灵之霞(), new 次元上升(), new 暗物质(), new 回复术(), new 治愈术(), new 复苏术(), new 圣灵术(), new 时间加速(), new 时间减速(), new 反魔法领域(), new 沉默十字(), new 虚弱领域(), new 混沌烙印(), new 凝胶稠絮(), new 大地之墙(), new 盖亚之盾(), new 风之守护(), new 结晶防护(), new 强音之力(), new 神圣祝福(), new 根源屏障(), new 灾难冲击波(), new 银色荆棘(), new 等离子之波(), new 地狱之门(), new 钻石星尘(), new 死亡咆哮(), new 鬼魅之痛(), new 导力停止(), new 冰狱冥嚎(), new 火山咆哮(), new 水蓝轰炸(), new 岩石之息(), new 弧形日珥(), new 苍白地狱(), new 破碎虚空(), new 弧光消耗(), new 回复术改(), new 回复术复(), new 治愈术复(), new 风之守护复(), new 强音之力复(), new 结晶防护复(), new 神圣祝福复(), new 时间加速改(), new 时间减速改(), new 时间加速复(), new 时间减速复()]); Dictionary exItems = Factory.GetGameModuleInstances(OshimaGameModuleConstant.General, OshimaGameModuleConstant.Item); FunGameConstant.Equipment.AddRange(exItems.Values.Where(i => (int)i.ItemType >= 0 && (int)i.ItemType < 5)); FunGameConstant.Equipment.AddRange([new 攻击之爪10(), new 攻击之爪25(), new 攻击之爪40(), new 攻击之爪55(), new 攻击之爪70(), new 攻击之爪85()]); FunGameConstant.Items.AddRange(exItems.Values.Where(i => (int)i.ItemType > 4)); FunGameConstant.Items.AddRange([new 小经验书(), new 中经验书(), new 大经验书(), new 升华之印(), new 流光之印(), new 永恒之印(), new 技能卷轴(), new 智慧之果(), new 奥术符文(), new 混沌之核(), new 小回复药(), new 中回复药(), new 大回复药(), new 魔力填充剂1(), new 魔力填充剂2(), new 魔力填充剂3(), new 能量饮料1(), new 能量饮料2(), new 能量饮料3(), new 年夜饭(), new 蛇年大吉(), new 新春快乐(), new 毕业礼包(), new 复苏药1(), new 复苏药2(), new 复苏药3(), new 全回复药(), new 魔法卡礼包(), new 奖券(), new 十连奖券(), new 改名卡(), new 原初之印(), new 创生之印(), new 法则精粹(), new 大师锻造券() ]); FunGameConstant.AllItems.AddRange(FunGameConstant.Equipment); FunGameConstant.AllItems.AddRange(FunGameConstant.Items); foreach (OshimaRegion region in FunGameConstant.Regions) { List items = [.. region.Crops.Select(i => i.Copy())]; FunGameConstant.ExploreItems.Add(region, items); } FunGameConstant.DrawCardItems.AddRange(FunGameConstant.AllItems.Where(i => !FunGameConstant.ItemCanNotDrawCard.Contains(i.ItemType))); FunGameConstant.CharacterLevelBreakItems.AddRange([new 升华之印(), new 流光之印(), new 永恒之印(), new 原初之印(), new 创生之印()]); FunGameConstant.SkillLevelUpItems.AddRange([new 技能卷轴(), new 智慧之果(), new 奥术符文(), new 混沌之核(), new 法则精粹()]); FunGameConstant.AllItems.AddRange(FunGameConstant.ExploreItems.Values.SelectMany(list => list)); foreach (OshimaRegion region in FunGameConstant.Regions) { FunGameConstant.RegionsName[region.Id] = region.Name; FunGameConstant.RegionsDifficulty[region.Id] = region.Difficulty; IEnumerable items = FunGameConstant.AllItems.Where(i => i.Others.TryGetValue("region", out object? value) && int.TryParse(value.ToString(), out int rid) && rid == region.Id).Select(i => i.Copy()).OrderByDescending(i => i.QualityType); foreach (Item item in items) { region.Items.Add(item); } } foreach (OshimaRegion region in FunGameConstant.PlayerRegions) { FunGameConstant.RegionsName[region.Id] = region.Name; FunGameConstant.RegionsDifficulty[region.Id] = region.Difficulty; IEnumerable items; if (region.Id == 0) { items = FunGameConstant.Equipment.Where(i => !i.Others.ContainsKey("region")).Select(i => i.Copy()).OrderByDescending(i => i.QualityType); } else { items = FunGameConstant.AllItems.Where(i => i.Others.TryGetValue("region", out object? value) && int.TryParse(value.ToString(), out int rid) && rid == region.Id).Select(i => i.Copy()).OrderByDescending(i => i.QualityType); } foreach (Item item in items) { region.Items.Add(item); } } Skill?[] activeSkills = [.. FunGameConstant.Equipment.Select(i => i.Skills.Active), .. FunGameConstant.Items.Select(i => i.Skills.Active)]; foreach (Skill? skill in activeSkills) { if (skill != null) { FunGameConstant.ItemSkills.Add(skill); } } FunGameConstant.ItemSkills.AddRange([.. FunGameConstant.Equipment.SelectMany(i => i.Skills.Passives), .. FunGameConstant.Items.SelectMany(i => i.Skills.Passives)]); FunGameConstant.AllSkills.AddRange(FunGameConstant.Magics); FunGameConstant.AllSkills.AddRange(FunGameConstant.Skills); FunGameConstant.AllSkills.AddRange(FunGameConstant.PassiveSkills); FunGameConstant.AllSkills.AddRange(FunGameConstant.ItemSkills); FunGameConstant.AllSkills.AddRange(FunGameConstant.SuperSkills); } public static List GenerateMagicCards(int count, QualityType? qualityType = null, long[]? magicIds = null, (int str, int agi, int intelligence)[]? values = null) { List items = []; for (int i = 0; i < count; i++) { long magicId = 0; if (magicIds != null && magicIds.Length > i) magicId = magicIds[i]; (int str, int agi, int intelligence) = (0, 0, 0); if (values != null && values.Length > i) { str = values[i].str; agi = values[i].agi; intelligence = values[i].intelligence; } items.Add(GenerateMagicCard(qualityType, magicId, str, agi, intelligence)); } return items; } public static Item GenerateMagicCard(QualityType? qualityType = null, long magicId = 0, int str = 0, int agi = 0, int intelligence = 0) { Item item = Factory.GetItem(); item.Id = Convert.ToInt64("16" + Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 8)); item.Name = GenerateRandomChineseName(); item.ItemType = ItemType.MagicCard; item.RemainUseTimes = 1; GenerateAndAddSkillToMagicCard(item, qualityType, magicId, str, agi, intelligence); return item; } public static void GenerateAndAddSkillToMagicCard(Item item, QualityType? qualityType = null, long magicId = 0, int str = 0, int agi = 0, int intelligence = 0) { int total = str + agi + intelligence; if (total == 0) { if (qualityType != null) { item.QualityType = qualityType.Value; total = item.QualityType switch { QualityType.Green => Random.Shared.Next(7, 13), QualityType.Blue => Random.Shared.Next(13, 19), QualityType.Purple => Random.Shared.Next(19, 25), QualityType.Orange => Random.Shared.Next(25, 31), QualityType.Red => Random.Shared.Next(31, 37), QualityType.Gold => Random.Shared.Next(37, 43), _ => Random.Shared.Next(1, 7) }; } else total = Random.Shared.Next(1, 43); // 随机决定将多少个属性赋给其中一个属性,确保至少一个不为零 int nonZeroAttributes = Random.Shared.Next(1, Math.Min(4, total + 1)); // 随机决定非零属性的数量,确保在 total = 1 时最多只有1个非零属性 // 根据非零属性数量分配属性点 if (nonZeroAttributes == 1) { // 只有一个属性不为零 int attribute = Random.Shared.Next(0, 3); if (attribute == 0) str = total; else if (attribute == 1) agi = total; else intelligence = total; } else if (nonZeroAttributes == 2 && total >= 2) { // 两个属性不为零 int first = Random.Shared.Next(1, total); // 第一个属性的值 int second = total - first; // 第二个属性的值 int attribute = Random.Shared.Next(0, 3); if (attribute == 0) { str = first; } else if (attribute == 1) { agi = first; } else { intelligence = first; } attribute = Random.Shared.Next(0, 3); while ((attribute == 0 && str > 0) || (attribute == 1 && agi > 0) || (attribute == 2 && intelligence > 0)) { attribute = Random.Shared.Next(0, 3); } if (attribute == 0) { str = second; } else if (attribute == 1) { agi = second; } else { intelligence = second; } } else if (total >= 3) { // 三个属性都不为零 str = Random.Shared.Next(1, total - 1); // 第一个属性的值 agi = Random.Shared.Next(1, total - str); // 第二个属性的值 intelligence = total - str - agi; // 剩下的值给第三个属性 } } if (item.QualityType == QualityType.White) { if (total > 6 && total <= 12) { item.QualityType = QualityType.Green; } else if (total > 12 && total <= 18) { item.QualityType = QualityType.Blue; } else if (total > 18 && total <= 24) { item.QualityType = QualityType.Purple; } else if (total > 24 && total <= 30) { item.QualityType = QualityType.Orange; } else if (total > 30 && total <= 36) { item.QualityType = QualityType.Red; } else if (total > 36) { item.QualityType = QualityType.Gold; } } Skill? magic = null; if (magicId != 0) { magic = FunGameConstant.Magics.FirstOrDefault(m => m.Id == magicId); } magic ??= FunGameConstant.Magics[Random.Shared.Next(FunGameConstant.Magics.Count)].Copy(); magic.Guid = item.Guid; magic.Level = (int)item.QualityType switch { 2 => 2, 3 => 2, 4 => 3, 5 => 4, 6 => 5, _ => 1 }; if (magic.Level > 1) { item.Name += $" +{magic.Level - 1}"; } item.Skills.Active = magic; Skill skill = Factory.OpenFactory.GetInstance(item.Id, item.Name, []); GenerateAndAddEffectsToMagicCard(skill, str, agi, intelligence); skill.Level = 1; List strings = []; if (str > 0) strings.Add($"{str:0.##} 点力量"); if (agi > 0) strings.Add($"{agi:0.##} 点敏捷"); if (intelligence > 0) strings.Add($"{intelligence:0.##} 点智力"); item.Description = $"包含魔法:{item.Skills.Active.Name + (item.Skills.Active.Level > 1 ? $" +{item.Skills.Active.Level - 1}" : "")}\r\n" + $"增加角色属性:{string.Join(",", strings)}"; item.Skills.Passives.Add(skill); } public static void GenerateAndAddEffectsToMagicCard(Skill skill, int str, int agi, int intelligence) { if (str > 0) { skill.Effects.Add(Factory.OpenFactory.GetInstance((long)EffectID.ExSTR, "", new() { { "skill", skill }, { "values", new Dictionary() { { "exstr", str } } } })); } if (agi > 0) { skill.Effects.Add(Factory.OpenFactory.GetInstance((long)EffectID.ExAGI, "", new() { { "skill", skill }, { "values", new Dictionary() { { "exagi", agi } } } })); } if (intelligence > 0) { skill.Effects.Add(Factory.OpenFactory.GetInstance((long)EffectID.ExINT, "", new() { { "skill", skill }, { "values", new Dictionary() { { "exint", intelligence } } } })); } } public static Item? ConflateMagicCardPack(IEnumerable magicCards) { if (magicCards.Any()) { List magics = [.. magicCards.Where(i => i.Skills.Active != null).Select(i => i.Skills.Active)]; List passives = [.. magicCards.SelectMany(i => i.Skills.Passives)]; Item item = Factory.GetItem(); item.Id = Convert.ToInt64("10" + Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 8)); item.Name = GenerateRandomChineseName(); item.ItemType = ItemType.MagicCardPack; double str = 0, agi = 0, intelligence = 0; foreach (Skill skill in passives) { Skill newSkill = skill.Copy(); foreach (Effect effect in newSkill.Effects) { switch ((EffectID)effect.Id) { case EffectID.ExSTR: if (effect is ExSTR exstr) { str += exstr.Value; } break; case EffectID.ExAGI: if (effect is ExAGI exagi) { agi += exagi.Value; } break; case EffectID.ExINT: if (effect is ExINT exint) { intelligence += exint.Value; } break; } } newSkill.Level = skill.Level; newSkill.Item = item; item.Skills.Passives.Add(newSkill); } List strings = []; if (str > 0) strings.Add($"{str:0.##} 点力量"); if (agi > 0) strings.Add($"{agi:0.##} 点敏捷"); if (intelligence > 0) strings.Add($"{intelligence:0.##} 点智力"); foreach (Skill skill in magics) { IEnumerable has = item.Skills.Magics.Where(m => m.Id == skill.Id); if (has.Any() && has.First() is Skill s) { s.Level += skill.Level; if (s.Level > 1) s.Name = s.Name.Split(' ')[0] + $" +{s.Level - 1}"; } else { Skill magic = skill.Copy(); magic.Guid = item.Guid; magic.Level = skill.Level; item.Skills.Magics.Add(magic); } } item.Description = $"包含魔法:{string.Join(",", item.Skills.Magics.Select(m => m.Name + (m.Level > 1 ? $" +{m.Level - 1}" : "")))}\r\n" + $"增加角色属性:{string.Join(",", strings)}"; double total = str + agi + intelligence; if (total > 18 && total <= 36) { item.QualityType = QualityType.Green; } else if (total > 36 && total <= 54) { item.QualityType = QualityType.Blue; } else if (total > 54 && total <= 72) { item.QualityType = QualityType.Purple; } else if (total > 72 && total <= 90) { item.QualityType = QualityType.Orange; } else if (total > 90 && total <= 108) { item.QualityType = QualityType.Red; } else if (total > 108) { item.QualityType = QualityType.Gold; } return item; } return null; } public static Item? GenerateMagicCardPack(int magicCardCount, QualityType? qualityType = null, long[]? magicIds = null, (int str, int agi, int intelligence)[]? values = null) { List magicCards = GenerateMagicCards(magicCardCount, qualityType, magicIds, values); Item? magicCardPack = ConflateMagicCardPack(magicCards); return magicCardPack; } public static void Reload() { FunGameConstant.Characters.Clear(); FunGameConstant.Equipment.Clear(); FunGameConstant.Skills.Clear(); FunGameConstant.SuperSkills.Clear(); FunGameConstant.PassiveSkills.Clear(); FunGameConstant.Magics.Clear(); FunGameConstant.DrawCardItems.Clear(); FunGameConstant.ExploreItems.Clear(); FunGameConstant.AllItems.Clear(); FunGameConstant.ItemSkills.Clear(); FunGameConstant.AllSkills.Clear(); InitFunGame(); } public static string GenerateRandomChineseName() { // 随机生成名字长度,2到5个字 int nameLength = Random.Shared.Next(2, 6); StringBuilder name = new(); for (int i = 0; i < nameLength; i++) { // 从常用汉字集中随机选择一个汉字 char chineseCharacter = FunGameConstant.CommonChineseCharacters[Random.Shared.Next(FunGameConstant.CommonChineseCharacters.Length)]; name.Append(chineseCharacter); } return name.ToString(); } public static string GenerateRandomChineseUserName() { StringBuilder name = new(); // 随机姓 string lastname = FunGameConstant.CommonSurnames[Random.Shared.Next(FunGameConstant.CommonSurnames.Length)]; name.Append(lastname); // 随机生成名字长度,2到5个字 int nameLength = Random.Shared.Next(1, 2); for (int i = 0; i < nameLength; i++) { // 从常用汉字集中随机选择一个汉字 char chineseCharacter = FunGameConstant.CommonChineseCharacters[Random.Shared.Next(FunGameConstant.CommonChineseCharacters.Length)]; name.Append(chineseCharacter); } return name.ToString(); } public static User GetUser(PluginConfig pc) { User user = pc.Get("user") ?? Factory.GetUser(); List characters = [.. user.Inventory.Characters]; List items = [.. user.Inventory.Items]; Character mc = user.Inventory.MainCharacter; List squad = [.. user.Inventory.Squad]; Dictionary training = user.Inventory.Training.ToDictionary(kv => kv.Key, kv => kv.Value); user.Inventory.Characters.Clear(); user.Inventory.Items.Clear(); user.Inventory.Squad.Clear(); user.Inventory.Training.Clear(); foreach (Item inventoryItem in items) { Item realItem = inventoryItem.Copy(true, true, true, true, FunGameConstant.AllItems, FunGameConstant.AllSkills); realItem.User = user; user.Inventory.Items.Add(realItem); } foreach (Character inventoryCharacter in characters) { Character tempCharacter = Factory.OpenFactory.GetInstance(inventoryCharacter.Id, inventoryCharacter.Name, []); if (tempCharacter.Id != 0) { inventoryCharacter.InitialATK = tempCharacter.InitialATK; inventoryCharacter.InitialDEF = tempCharacter.InitialDEF; inventoryCharacter.InitialHP = tempCharacter.InitialHP; inventoryCharacter.InitialMP = tempCharacter.InitialMP; inventoryCharacter.InitialSTR = tempCharacter.InitialSTR; inventoryCharacter.STRGrowth = tempCharacter.STRGrowth; inventoryCharacter.InitialAGI = tempCharacter.InitialAGI; inventoryCharacter.AGIGrowth = tempCharacter.AGIGrowth; inventoryCharacter.InitialINT = tempCharacter.InitialINT; inventoryCharacter.INTGrowth = tempCharacter.INTGrowth; inventoryCharacter.InitialSPD = tempCharacter.InitialSPD; inventoryCharacter.InitialHR = tempCharacter.InitialHR; inventoryCharacter.InitialMR = tempCharacter.InitialMR; } Character realCharacter = CharacterBuilder.Build(inventoryCharacter, false, true, user.Inventory, FunGameConstant.AllItems, FunGameConstant.AllSkills, false); // 自动回血 DateTime now = DateTime.Now; int seconds = (int)(now - user.LastTime).TotalSeconds; // 死了不回,要去治疗 if (realCharacter.HP > 0) { double recoveryHP = realCharacter.HR * seconds; double recoveryMP = realCharacter.MR * seconds; double recoveryEP = realCharacter.ER * seconds; realCharacter.HP += recoveryHP; realCharacter.MP += recoveryMP; realCharacter.EP += recoveryEP; } // 减少所有技能的冷却时间 foreach (Skill skill in realCharacter.Skills) { skill.CurrentCD -= seconds; if (skill.CurrentCD <= 0) { skill.CurrentCD = 0; skill.Enable = true; } } // 移除到时间的特效 List effects = [.. realCharacter.Effects]; foreach (Effect effect in effects) { if (effect.Level == 0) { realCharacter.Effects.Remove(effect); continue; } effect.OnTimeElapsed(realCharacter, seconds); // 自身被动不会考虑 if (effect.EffectType == EffectType.None && effect.Skill.SkillType == SkillType.Passive) { continue; } if (effect.Durative) { effect.RemainDuration -= seconds; if (effect.RemainDuration <= 0) { effect.RemainDuration = 0; realCharacter.Effects.Remove(effect); effect.OnEffectLost(realCharacter); } } } realCharacter.User = user; user.Inventory.Characters.Add(realCharacter); } if (user.Inventory.Characters.FirstOrDefault(c => c.Id == mc.Id) is Character newMC) { user.Inventory.MainCharacter = newMC; } foreach (long id in squad) { if (user.Inventory.Characters.FirstOrDefault(c => c.Id == id) is Character s) { user.Inventory.Squad.Add(id); } } foreach (long cid in training.Keys) { if (user.Inventory.Characters.FirstOrDefault(c => c.Id == cid) is Character t) { user.Inventory.Training[t.Id] = training[cid]; } } return user; } public static void AddNotice(long userId, params string[] notices) { if (UserNotice.TryGetValue(userId, out HashSet? list) && list != null) { foreach (string notice in notices) { list.Add(notice); } } else UserNotice[userId] = [.. notices]; } public static IEnumerable GetPage(IEnumerable list, int showPage, int pageSize) { return [.. list.Skip((showPage - 1) * pageSize).Take(pageSize)]; } public static List DrawCards(User user, bool is10 = false, bool useCurrency = true) { List msgs = []; int reduce; string reduceUnit; IEnumerable? items = null; if (useCurrency) { if (is10) { items = user.Inventory.Items.Where(i => i is 十连奖券); } else { items = user.Inventory.Items.Where(i => i is 奖券); } if (items.Any()) { reduceUnit = items.First().Name; reduce = 1; user.Inventory.Items.Remove(items.First()); } else { reduceUnit = General.GameplayEquilibriumConstant.InGameCurrency; reduce = is10 ? FunGameConstant.DrawCardReduce * 10 : FunGameConstant.DrawCardReduce; if (user.Inventory.Credits < reduce) { msgs.Add($"你的{reduceUnit}不足 {reduce} 呢,无法抽卡!"); return msgs; } user.Inventory.Credits -= reduce; } } else { reduceUnit = General.GameplayEquilibriumConstant.InGameMaterial; reduce = is10 ? FunGameConstant.DrawCardReduce_Material * 10 : FunGameConstant.DrawCardReduce_Material; if (user.Inventory.Materials < reduce) { msgs.Add($"你的{reduceUnit}不足 {reduce} 呢,无法抽卡!"); return msgs; } user.Inventory.Materials -= reduce; } if (is10) { int count = 0; for (int i = 1; i <= 10; i++) { double dice = Random.Shared.NextDouble(); if (dice > 0.8) { count++; msgs.Add(GetDrawCardResult(reduce, reduceUnit, user, is10, count)); } } if (msgs.Count == 0) { msgs.Add($"消耗 {reduce} {reduceUnit},你什么也没抽中……"); } else { msgs.Insert(0, $"消耗 {reduce} {reduceUnit},恭喜你抽到了:"); } } else { double dice = Random.Shared.NextDouble(); if (dice > 0.8) { msgs.Add(GetDrawCardResult(reduce, reduceUnit, user)); } else { msgs.Add($"消耗 {reduce} {reduceUnit},你什么也没抽中……"); } } if (items != null && items.Any()) { msgs.Insert(0, $"本次抽卡使用{reduceUnit}代替金币抽卡!你的库存剩余 {items.Count()} 张{reduceUnit}。"); } return msgs; } public static string GetDrawCardResult(int reduce, string reduceUnit, User user, bool isMulti = false, int multiCount = 1) { string msg = ""; if (!isMulti) { msg = $"消耗 {reduce} {reduceUnit},恭喜你抽到了:"; } int r = Random.Shared.Next(8); double q = Random.Shared.NextDouble() * 100; QualityType type = QualityType.White; QualityType[] types = [.. FunGameConstant.DrawCardProbabilities.Keys.OrderByDescending(o => (int)o)]; foreach (QualityType typeTemp in types) { if (q <= FunGameConstant.DrawCardProbabilities[typeTemp]) { type = typeTemp; break; } } switch (r) { case 1: Item[] 武器 = [.. FunGameConstant.Equipment.Where(i => i.ItemType == ItemType.Weapon && i.QualityType == type)]; Item a = 武器[Random.Shared.Next(武器.Length)].Copy(); if (a.QualityType >= QualityType.Orange) a.IsLock = true; SetSellAndTradeTime(a); user.Inventory.Items.Add(a); msg += ItemSet.GetQualityTypeName(a.QualityType) + ItemSet.GetItemTypeName(a.ItemType) + "【" + a.Name + "】!\r\n" + a.Description; break; case 2: Item[] 防具 = [.. FunGameConstant.Equipment.Where(i => i.ItemType == ItemType.Armor && i.QualityType == type)]; Item b = 防具[Random.Shared.Next(防具.Length)].Copy(); if (b.QualityType >= QualityType.Orange) b.IsLock = true; SetSellAndTradeTime(b); user.Inventory.Items.Add(b); msg += ItemSet.GetQualityTypeName(b.QualityType) + ItemSet.GetItemTypeName(b.ItemType) + "【" + b.Name + "】!\r\n" + b.Description; break; case 3: Item[] 鞋子 = [.. FunGameConstant.Equipment.Where(i => i.ItemType == ItemType.Shoes && i.QualityType == type)]; Item c = 鞋子[Random.Shared.Next(鞋子.Length)].Copy(); if (c.QualityType >= QualityType.Orange) c.IsLock = true; SetSellAndTradeTime(c); user.Inventory.Items.Add(c); msg += ItemSet.GetQualityTypeName(c.QualityType) + ItemSet.GetItemTypeName(c.ItemType) + "【" + c.Name + "】!\r\n" + c.Description; break; case 4: Item[] 饰品 = [.. FunGameConstant.Equipment.Where(i => i.ItemType == ItemType.Accessory && i.QualityType == type)]; Item d = 饰品[Random.Shared.Next(饰品.Length)].Copy(); if (d.QualityType >= QualityType.Orange) d.IsLock = true; SetSellAndTradeTime(d); user.Inventory.Items.Add(d); msg += ItemSet.GetQualityTypeName(d.QualityType) + ItemSet.GetItemTypeName(d.ItemType) + "【" + d.Name + "】!\r\n" + d.Description; break; case 5: Character character = FunGameConstant.Characters[Random.Shared.Next(FunGameConstant.Characters.Count)].Copy(); AddCharacterSkills(character, 1, 0, 0); if (user.Inventory.Characters.Any(c => c.Id == character.Id)) { user.Inventory.Materials += 50; msg += "【" + character.ToStringWithOutUser() + "】!\r\n但是你已经拥有此角色,转换为【50】" + General.GameplayEquilibriumConstant.InGameMaterial + "!"; } else { user.Inventory.Characters.Add(character); msg += "【" + character.ToStringWithOutUser() + "】!\r\n输入【查角色" + character.Id + "】可以获取此角色完整信息。"; } break; case 6: Item mfk = GenerateMagicCard(type); if (mfk.QualityType >= QualityType.Orange) mfk.IsLock = true; SetSellAndTradeTime(mfk); user.Inventory.Items.Add(mfk); msg += ItemSet.GetQualityTypeName(mfk.QualityType) + ItemSet.GetItemTypeName(mfk.ItemType) + "【" + mfk.Name + "】!\r\n" + mfk.Description; break; case 7: Item 物品 = FunGameConstant.DrawCardItems[Random.Shared.Next(FunGameConstant.DrawCardItems.Count)].Copy(); if (物品.QualityType >= QualityType.Orange) 物品.IsLock = true; SetSellAndTradeTime(物品); user.Inventory.Items.Add(物品); msg += ItemSet.GetQualityTypeName(物品.QualityType) + ItemSet.GetItemTypeName(物品.ItemType) + "【" + 物品.Name + "】!\r\n" + 物品.Description; // 连接到任务系统 AddExploreItemCache(user.Id, 物品.Name); // 连接到活动系统 ActivitiesItemCache.Add(物品.Name); break; case 0: default: Item? mfkb = GenerateMagicCardPack(3, type); if (mfkb != null) { if (mfkb.QualityType >= QualityType.Orange) mfkb.IsLock = true; SetSellAndTradeTime(mfkb); user.Inventory.Items.Add(mfkb); msg += ItemSet.GetQualityTypeName(mfkb.QualityType) + ItemSet.GetItemTypeName(mfkb.ItemType) + "【" + mfkb.Name + "】!\r\n" + mfkb.Description; } break; } if (isMulti) msg = $"{multiCount}. \r\n{msg}"; return msg; } public static string GetSignInResult(User user, int days) { string msg = $"签到成功,你已连续签到 {days + 1} 天!\r\n本次签到获得:"; int currency = Random.Shared.Next(1000, 3000) + 10 * days; msg += $"{currency} {General.GameplayEquilibriumConstant.InGameCurrency} 和 "; int material = Random.Shared.Next(5, 15) + days / 7; msg += $"{material} {General.GameplayEquilibriumConstant.InGameMaterial}!额外获得:"; user.Inventory.Credits += currency; user.Inventory.Materials += material; int r = Random.Shared.Next(6); double q = Random.Shared.NextDouble() * 100; // 根据签到天数调整概率 double daysFactor = Math.Min(days * 0.03, 30); Dictionary adjustedProbabilities = new(FunGameConstant.DrawCardProbabilities); foreach (QualityType typeTemp in adjustedProbabilities.Keys) { adjustedProbabilities[typeTemp] += daysFactor; } // 生成随机数并确定品质 double randomValue = Random.Shared.NextDouble() * 100; QualityType type = QualityType.White; QualityType[] types = [.. adjustedProbabilities.Keys.OrderByDescending(o => (int)o)]; foreach (QualityType typeTemp in types) { if (randomValue <= adjustedProbabilities[typeTemp]) { type = typeTemp; break; } } switch (r) { case 1: Item[] 武器 = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("11") && i.QualityType == type)]; Item a = 武器[Random.Shared.Next(武器.Length)].Copy(); if (a.QualityType >= QualityType.Orange) a.IsLock = true; SetSellAndTradeTime(a); user.Inventory.Items.Add(a); msg += ItemSet.GetQualityTypeName(a.QualityType) + ItemSet.GetItemTypeName(a.ItemType) + "【" + a.Name + "】!\r\n" + a.Description; break; case 2: Item[] 防具 = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("12") && i.QualityType == type)]; Item b = 防具[Random.Shared.Next(防具.Length)].Copy(); if (b.QualityType >= QualityType.Orange) b.IsLock = true; SetSellAndTradeTime(b); user.Inventory.Items.Add(b); msg += ItemSet.GetQualityTypeName(b.QualityType) + ItemSet.GetItemTypeName(b.ItemType) + "【" + b.Name + "】!\r\n" + b.Description; break; case 3: Item[] 鞋子 = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("13") && i.QualityType == type)]; Item c = 鞋子[Random.Shared.Next(鞋子.Length)].Copy(); if (c.QualityType >= QualityType.Orange) c.IsLock = true; SetSellAndTradeTime(c); user.Inventory.Items.Add(c); msg += ItemSet.GetQualityTypeName(c.QualityType) + ItemSet.GetItemTypeName(c.ItemType) + "【" + c.Name + "】!\r\n" + c.Description; break; case 4: Item[] 饰品 = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("14") && i.QualityType == type)]; Item d = 饰品[Random.Shared.Next(饰品.Length)].Copy(); if (d.QualityType >= QualityType.Orange) d.IsLock = true; SetSellAndTradeTime(d); user.Inventory.Items.Add(d); msg += ItemSet.GetQualityTypeName(d.QualityType) + ItemSet.GetItemTypeName(d.ItemType) + "【" + d.Name + "】!\r\n" + d.Description; break; case 5: Item mfk = GenerateMagicCard(type); if (mfk.QualityType >= QualityType.Orange) mfk.IsLock = true; SetSellAndTradeTime(mfk); user.Inventory.Items.Add(mfk); msg += ItemSet.GetQualityTypeName(mfk.QualityType) + ItemSet.GetItemTypeName(mfk.ItemType) + "【" + mfk.Name + "】!\r\n" + mfk.Description; break; case 0: default: Item? mfkb = GenerateMagicCardPack(3, type); if (mfkb != null) { if (mfkb.QualityType >= QualityType.Orange) mfkb.IsLock = true; SetSellAndTradeTime(mfkb); user.Inventory.Items.Add(mfkb); msg += ItemSet.GetQualityTypeName(mfkb.QualityType) + ItemSet.GetItemTypeName(mfkb.ItemType) + "【" + mfkb.Name + "】!\r\n" + mfkb.Description; } break; } return msg; } public static void SetSellAndTradeTime(Item item, bool sell = false, bool trade = true, DateTime? nextSell = null, DateTime? nextTrade = null) { if (sell) { item.IsSellable = false; item.NextSellableTime = DateTimeUtility.GetTradableTime(nextSell); } if (trade) { item.IsTradable = false; item.NextTradableTime = DateTimeUtility.GetTradableTime(nextTrade); } } public static async Task AllowSellAndTrade() { string msg; string dpath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/saved"; if (Directory.Exists(dpath)) { string[] jsonFiles = Directory.GetFiles(dpath, "*.json"); List tasks = []; foreach (string file in jsonFiles) { tasks.Add(Task.Run(() => { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file); PluginConfig pc = GetUserConfig(fileNameWithoutExtension, out _); if (pc.Count > 0) { User user = GetUser(pc); foreach (Item item in user.Inventory.Items) { if (!item.IsSellable && item.NextSellableTime != DateTime.MinValue && DateTime.Now >= item.NextSellableTime) { item.NextSellableTime = DateTime.MinValue; item.IsSellable = true; } if (!item.IsTradable && item.NextTradableTime != DateTime.MinValue && DateTime.Now >= item.NextTradableTime) { item.NextTradableTime = DateTime.MinValue; item.IsTradable = true; } } SetUserConfigAndReleaseSemaphoreSlim(user.Id, pc, user, false); } else { ReleaseUserSemaphoreSlim(fileNameWithoutExtension); } })); } await Task.WhenAll(tasks); msg = "已清理所有玩家的物品交易时间。"; } else { msg = "存档目录不存在,无法清理交易时间。"; } return msg; } public static void AddCharacterSkills(Character character, int passiveLevel, int skillLevel, int superLevel) { long id = character.Id; Math.Sign(skillLevel); if (id == 1) { Skill META马 = new META马(character) { Level = passiveLevel }; character.Skills.Add(META马); Skill 力量爆发 = new 力量爆发(character) { Level = superLevel }; character.Skills.Add(力量爆发); } if (id == 2) { Skill 心灵之火 = new 心灵之火(character) { Level = passiveLevel }; character.Skills.Add(心灵之火); Skill 天赐之力 = new 天赐之力(character) { Level = superLevel }; character.Skills.Add(天赐之力); } if (id == 3) { Skill 魔法震荡 = new 魔法震荡(character) { Level = passiveLevel }; character.Skills.Add(魔法震荡); Skill 魔法涌流 = new 魔法涌流(character) { Level = superLevel }; character.Skills.Add(魔法涌流); } if (id == 4) { Skill 灵能反射 = new 灵能反射(character) { Level = passiveLevel }; character.Skills.Add(灵能反射); Skill 三重叠加 = new 三重叠加(character) { Level = superLevel }; character.Skills.Add(三重叠加); } if (id == 5) { Skill 智慧与力量 = new 智慧与力量(character) { Level = passiveLevel }; character.Skills.Add(智慧与力量); Skill 变幻之心 = new 变幻之心(character) { Level = superLevel }; character.Skills.Add(变幻之心); } if (id == 6) { Skill 致命打击 = new 致命打击(character) { Level = passiveLevel }; character.Skills.Add(致命打击); Skill 精准打击 = new 精准打击(character) { Level = superLevel }; character.Skills.Add(精准打击); } if (id == 7) { Skill 毁灭之势 = new 毁灭之势(character) { Level = passiveLevel }; character.Skills.Add(毁灭之势); Skill 绝对领域 = new 绝对领域(character) { Level = superLevel }; character.Skills.Add(绝对领域); } if (id == 8) { Skill 枯竭打击 = new 枯竭打击(character) { Level = passiveLevel }; character.Skills.Add(枯竭打击); Skill 能量毁灭 = new 能量毁灭(character) { Level = superLevel }; character.Skills.Add(能量毁灭); } if (id == 9) { Skill 破釜沉舟 = new 破釜沉舟(character) { Level = passiveLevel }; character.Skills.Add(破釜沉舟); Skill 迅捷之势 = new 迅捷之势(character) { Level = superLevel }; character.Skills.Add(迅捷之势); } if (id == 10) { Skill 累积之压 = new 累积之压(character) { Level = passiveLevel }; character.Skills.Add(累积之压); Skill 嗜血本能 = new 嗜血本能(character) { Level = superLevel }; character.Skills.Add(嗜血本能); } if (id == 11) { Skill 敏捷之刃 = new 敏捷之刃(character) { Level = passiveLevel }; character.Skills.Add(敏捷之刃); Skill 平衡强化 = new 平衡强化(character) { Level = superLevel }; character.Skills.Add(平衡强化); } if (id == 12) { Skill 弱者猎手 = new 弱者猎手(character) { Level = passiveLevel }; character.Skills.Add(弱者猎手); Skill 血之狂欢 = new 血之狂欢(character) { Level = superLevel }; character.Skills.Add(血之狂欢); } } public static bool UseItem(Item item, int times, User user, IEnumerable targets, out string msg) { msg = ""; Dictionary args = new() { { "targets", targets.ToArray() } }; bool result = item.UseItem(user, times, args); if (item.EntityState == EntityState.Deleted) { user.Inventory.Items.Remove(item); } string key = args.Keys.FirstOrDefault(s => s.Equals("msg", StringComparison.CurrentCultureIgnoreCase)) ?? ""; if (key != "" && args.TryGetValue(key, out object? value) && value is string str) { msg = str; } if (msg.Trim() == "" && !result) { result = UseItemCustom(item, user, targets, out msg); } return result; } public static bool UseItems(IEnumerable items, User user, IEnumerable targets, List msgs) { Dictionary args = new() { { "targets", targets.ToArray() }, { "useCount", items.Count() } }; bool result = true; foreach (Item item in items) { if (!result) { break; } if (FunGameConstant.ItemCanUsed.Contains(item.ItemType)) { if (item.RemainUseTimes <= 0) { msgs.Add($"{item.Name} 的剩余使用次数为 0,无法使用!"); result = false; } if (!result) { continue; } bool tempResult = item.UseItem(user, 1, args); if (item.EntityState == EntityState.Deleted) { user.Inventory.Items.Remove(item); } string tempStr = ""; string key = args.Keys.FirstOrDefault(s => s.Equals("msg", StringComparison.CurrentCultureIgnoreCase)) ?? ""; if (key != "" && args.TryGetValue(key, out object? value) && value is string str) { if (str != "") msgs.Add(str); tempStr = str; } if (tempStr.Trim() == "" && !tempResult) { // 使用自定义使用方法 tempResult = UseItemCustom(item, user, targets, out tempStr); } if (!tempResult) { result = false; } msgs.Add(tempStr); // 这个参数会覆盖掉原消息 key = args.Keys.FirstOrDefault(s => s.Equals("truemsg", StringComparison.CurrentCultureIgnoreCase)) ?? ""; if (key != "" && args.TryGetValue(key, out value) && value is string truemsg) { msgs.Clear(); msgs.Add(truemsg); } } else { msgs.Add($"这个物品无法使用!"); } } return result; } public static bool UseItemCustom(Item item, User user, IEnumerable targets, out string msg) { msg = ""; if (item.ItemType == ItemType.GiftBox) { if (item is 魔法卡礼包 cardBox) { List cards = []; for (int i = 0; i < cardBox.Count; i++) { Item newItem = GenerateMagicCard(item.QualityType); AddItemToUserInventory(user, newItem, false); cards.Add($"[{ItemSet.GetQualityTypeName(item.QualityType)}|魔法卡] {newItem.Name}\r\n{newItem.ToStringInventory(false)}"); } msg = "打开礼包成功!获得了以下物品:\r\n" + string.Join("\r\n", cards); item.RemainUseTimes--; if (item.RemainUseTimes < 0) item.RemainUseTimes = 0; if (item.RemainUseTimes == 0) { user.Inventory.Items.Remove(item); } return true; } else if (item is 礼包.GiftBox box && box.Gifts.Count > 0) { foreach (string name in box.Gifts.Keys) { if (name == General.GameplayEquilibriumConstant.InGameCurrency) { user.Inventory.Credits += box.Gifts[name]; } if (name == General.GameplayEquilibriumConstant.InGameMaterial) { user.Inventory.Materials += box.Gifts[name]; } if (FunGameConstant.AllItems.FirstOrDefault(i => i.Name == name) is Item currentItem) { for (int i = 0; i < box.Gifts[name]; i++) { AddItemToUserInventory(user, currentItem, toExploreCache: false, toActivitiesCache: false); } } } msg = "打开礼包成功!获得了以下物品:\r\n" + string.Join(",", box.Gifts.Select(kv => $"{kv.Key} * {kv.Value}")); if (item.Name == nameof(年夜饭)) { msg += "\r\n" + "热腾腾的除夕年夜饭,祝您阖家团圆,年味浓浓!"; } else if (item.Name == nameof(蛇年大吉)) { msg += "\r\n" + "金蛇送福,好运连连!!"; } else if (item.Name == nameof(新春快乐)) { msg += "\r\n" + "新春纳福,喜乐安康!!"; } else if (item.Name == nameof(毕业礼包)) { msg += "\r\n" + "咦?!!啊咧!!!"; } item.RemainUseTimes--; if (item.RemainUseTimes < 0) item.RemainUseTimes = 0; if (item.RemainUseTimes == 0) { user.Inventory.Items.Remove(item); } return true; } } switch (item.Name) { default: break; } return false; } public static string GetLevelBreakNeedy(int levelBreak, User user) { if (FunGameConstant.LevelBreakNeedyList.TryGetValue(levelBreak, out Dictionary? needy) && needy != null && needy.Count > 0) { List strings = []; foreach (string key in needy.Keys) { int value = needy[key]; int count = 0; if (key == General.GameplayEquilibriumConstant.InGameCurrency) { count = (int)user.Inventory.Credits; } else if (key == General.GameplayEquilibriumConstant.InGameMaterial) { count = (int)user.Inventory.Materials; } else { count = user.Inventory.Items.Count(i => i.Name == key); } strings.Add($"{key} * {value}({count} / {value})"); } return string.Join(",", strings); } return ""; } public static string UseMagicCard(User user, Item magicCard, Item magicCardPack) { if (magicCard.QualityType != magicCardPack.QualityType) { return $"只能对相同品质的魔法卡包使用魔法卡!"; } if (magicCard.Skills.Active != null) { string msg = ""; Skill magic = magicCard.Skills.Active; if (magicCardPack.Skills.Magics.FirstOrDefault(m => m.GetIdName() == magic.GetIdName()) is Skill has && has.Level < 8) { int original = has.Level; // 添加技能等级 has.Level += magic.Level; // 补偿钻石,1级10钻石 int diff = magic.Level - (has.Level - original); if (diff != 0) { user.Inventory.Materials += diff * 10; msg = $"由于魔法卡的技能等级数尚未用完,技能便已经升至满级,特此补偿 {diff * 10} {General.GameplayEquilibriumConstant.InGameMaterial}!\r\n"; } } else { if (magicCardPack.Skills.Magics.Count < 3) { // 添加技能 magicCardPack.Skills.Magics.Add(magic); magic.Guid = magicCard.Guid; msg = $"此魔法卡的技能已经添加到未满三个魔法的卡包上。\r\n"; } else return $"魔法【{magic.Name}】在此魔法卡包中不存在或是已经升至满级!"; } string containMagics = magicCardPack.Description.Split("增加角色属性")[0]; magicCardPack.Description = $"包含魔法:{string.Join(",", magicCardPack.Skills.Magics.Select(m => m.Name + (m.Level > 1 ? $" +{m.Level - 1}" : "")))}\r\n" + magicCardPack.Description.Replace(containMagics, ""); magicCard.RemainUseTimes--; if (magicCard.RemainUseTimes < 0) magicCard.RemainUseTimes = 0; if (magicCard.RemainUseTimes == 0) { user.Inventory.Items.Remove(magicCard); } return $"目标魔法卡包的力量已经被此魔法卡显著地提升了!!!\r\n{msg}{magicCardPack.ToStringInventory(true)}"; } else { return "此魔法卡不存在任何魔法!"; } } public static string GetTrainingInfo(TimeSpan diff, Character character, bool isPre, out int totalExperience, out int smallBookCount, out int mediumBookCount, out int largeBookCount) { int totalMinutes = (int)diff.TotalMinutes; // 每分钟经验 int experiencePerMinute = 2; // 最大练级时间 int dailyTrainingMinutes = 2880; // 计算总经验奖励 totalExperience = Math.Min(totalMinutes, dailyTrainingMinutes) * experiencePerMinute; // 计算经验书奖励 smallBookCount = 0; mediumBookCount = 0; largeBookCount = 0; // 计算总训练小时数 int trainingHours = totalMinutes / 60; if (trainingHours >= 8) { smallBookCount = Math.Min(2, trainingHours); } if (trainingHours >= 16) { mediumBookCount = Math.Min(2, (trainingHours - 16) / 1); } if (trainingHours >= 24) { largeBookCount = Math.Min(2, (trainingHours - 24) / 1); } double TotalHR = Math.Min(character.MaxHP, character.HR * 60 * (int)diff.TotalMinutes); double TotalMR = Math.Min(character.MaxMP, character.MR * 60 * (int)diff.TotalMinutes); return $"练级时长:{totalMinutes} 分钟,{(isPre ? "预计可" : "")}获得:{totalExperience} 点经验值,{smallBookCount} 本小经验书,{mediumBookCount} 本中经验书,{largeBookCount} 本大经验书。" + $"回复角色 {TotalHR:0.##} 点生命值和 {TotalMR:0.##} 点魔法值。" + $"{(isPre ? "练级时间上限 2880 分钟(48小时),超时将不会再产生收益,请按时领取奖励!" : "")}"; } public static string GetSkillLevelUpNeedy(int level, User user, Character character) { if (FunGameConstant.SkillLevelUpList.TryGetValue(level, out Dictionary? needy) && needy != null && needy.Count > 0) { return GetNeedyInfo(needy, user, character); } return ""; } public static string GetNormalAttackLevelUpNeedy(int level, User user, Character character) { if (FunGameConstant.NormalAttackLevelUpList.TryGetValue(level, out Dictionary? needy) && needy != null && needy.Count > 0) { return GetNeedyInfo(needy, user, character); } return ""; } public static string GetNeedyInfo(Dictionary needy, User user, Character character) { string str = ""; foreach (string key in needy.Keys) { int needCount = needy[key]; if (str != "") { str += ","; } if (key == "角色等级") { str += $"角色等级 {needCount} 级({character.Level} / {needCount})"; } else if (key == "角色突破进度") { str += $"角色突破进度 {needCount} 等阶({character.LevelBreak + 1} / {needCount})"; } else if (key == General.GameplayEquilibriumConstant.InGameCurrency) { str += $"{key} * {needCount}({(int)user.Inventory.Credits} / {needCount})"; } else if (key == General.GameplayEquilibriumConstant.InGameMaterial) { str += $"{key} * {needCount}({(int)user.Inventory.Materials} / {needCount})"; } else { int count = user.Inventory.Items.Count(i => i.Name == key); str += $"{key} * {needCount}({count} / {needCount})"; } } return str; } public static void GenerateBoss() { if (Bosses.Count < 10) { int genCount = 10 - Bosses.Count; Item[] weapons = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("11") && (int)i.QualityType == 5)]; Item[] armors = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("12") && (int)i.QualityType == 5)]; Item[] shoes = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("13") && (int)i.QualityType == 5)]; Item[] accessory = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("14") && (int)i.QualityType == 5)]; Item[] consumables = [.. FunGameConstant.AllItems.Where(i => i.ItemType == ItemType.Consumable && i.IsInGameItem)]; string[] regionsBossName = [.. FunGameConstant.Regions.SelectMany(r => r.Characters).Select(c => c.Name)]; for (int i = 0; i < genCount; i++) { int nowIndex = Bosses.Count > 0 ? Bosses.Keys.Max() + 1 : 1; string bossName = regionsBossName[Random.Shared.Next(regionsBossName.Length)]; CustomCharacter boss = new(nowIndex, bossName, "", bossName); int cutRate = Random.Shared.Next(3) switch { 0 => 1, 1 => 2, _ => 4, }; int cLevel = General.GameplayEquilibriumConstant.MaxLevel / cutRate; int sLevel = General.GameplayEquilibriumConstant.MaxSkillLevel / cutRate; int mLevel = General.GameplayEquilibriumConstant.MaxMagicLevel / cutRate; int naLevel = General.GameplayEquilibriumConstant.MaxNormalAttackLevel / cutRate; boss.NormalAttack.ExHardnessTime = -4; EnhanceBoss(boss, weapons, armors, shoes, accessory, consumables, cLevel, sLevel, mLevel, naLevel); Bosses[nowIndex] = boss; } } } private static void EnhanceBoss(Character boss, Item[] weapons, Item[] armors, Item[] shoes, Item[] accessory, Item[] consumables, int cLevel, int sLevel, int mLevel, int naLevel, bool enhanceHPMP = true, bool enhanceCRCRD = true, bool isUnit = false) { boss.Level = cLevel; boss.NormalAttack.Level = naLevel; Item? a = null, b = null, c = null, d = null, d2 = null; if (weapons.Length > 0) { a = weapons[Random.Shared.Next(weapons.Length)]; } if (armors.Length > 0) { b = armors[Random.Shared.Next(armors.Length)]; } if (shoes.Length > 0) { c = shoes[Random.Shared.Next(shoes.Length)]; } if (accessory.Length > 0) { d = accessory[Random.Shared.Next(accessory.Length)]; } if (accessory.Length > 0) { d2 = accessory[Random.Shared.Next(accessory.Length)]; } List dropItems = []; if (a != null) dropItems.Add(a); if (b != null) dropItems.Add(b); if (c != null) dropItems.Add(c); if (d != null) dropItems.Add(d); if (d2 != null) dropItems.Add(d2); Item? magicCardPack = GenerateMagicCardPack(5, (QualityType)4); if (magicCardPack != null) { magicCardPack.QualityType = QualityType.Gold; foreach (Skill magic in magicCardPack.Skills.Magics) { magic.Level = mLevel; } boss.Equip(magicCardPack); } foreach (Item item in dropItems) { Item realItem = item.Copy(); boss.Equip(realItem); } if (consumables.Length > 0 && boss.Items.Count < 5) { for (int j = 0; j < 2; j++) { Item consumable = consumables[Random.Shared.Next(consumables.Length)].Copy(); boss.Items.Add(consumable); } } Skill bossSkill = Factory.OpenFactory.GetInstance(0, "BOSS专属被动", []); bossSkill.Level = 1; bossSkill.Character = boss; double exHP2 = 1.5; double exMP2 = 0.8; if (!enhanceHPMP) { if (isUnit) exHP2 = 0.15; else exHP2 = 0.01; exMP2 = 0.2; } double exCR = 0.35; double exCRD = 0.9; if (!enhanceCRCRD) { exCR = 0.15; exCRD = 0.4; } Effect effect = Factory.OpenFactory.GetInstance((long)EffectID.DynamicsEffect, "", new() { { "skill", bossSkill }, { "values", new Dictionary() { { "exatk", isUnit ? 1.4 * cLevel : 3.4 * cLevel }, { "exdef", isUnit ? 1.4 * cLevel : 3.4 * cLevel }, { "exhp2", exHP2 }, { "exmp2", exMP2 }, { "exhr", 0.15 * cLevel }, { "exmr", 0.1 * cLevel }, { "excr", exCR }, { "excrd", exCRD }, { "excdr", isUnit ? 0.2 : 0.25 }, { "exacc", isUnit ? 0.15 : 0.25 } } } }); effect.OnEffectGained(boss); bossSkill.Effects.Add(effect); boss.Skills.Add(bossSkill); effect = Factory.OpenFactory.GetInstance((long)EffectID.ExMDF, "", new() { { "skill", bossSkill }, { "values", new Dictionary() { { "mdftype", 0 }, { "mdfvalue", 0.15 } } } }); effect.OnEffectGained(boss); bossSkill.Effects.Add(effect); boss.Skills.Add(bossSkill); Skill passive = Factory.OpenFactory.GetInstance(Random.Shared.Next(4001, 4013), "", []); passive.Character = boss; passive.Level = 1; boss.Skills.Add(passive); Skill super = Factory.OpenFactory.GetInstance(Random.Shared.Next(3001, 3013), "", []); super.Character = boss; super.Level = sLevel; boss.Skills.Add(super); boss.Recovery(); SetCharacterPrimaryAttribute(boss); } public static Dictionary> GenerateRoundRewards(int maxRound) { Dictionary> roundRewards = []; int currentRound = 1; while (currentRound <= maxRound) { currentRound += Random.Shared.Next(1, 9); if (currentRound <= maxRound) { List skills = []; // 添加回合奖励特效 long effectID = (long)FunGameConstant.RoundRewards.Keys.ToArray()[Random.Shared.Next(FunGameConstant.RoundRewards.Count)]; Dictionary args = []; if (effectID > (long)EffectID.Active_Start) { args.Add("active", true); args.Add("self", true); args.Add("enemy", false); } skills.Add(Factory.OpenFactory.GetInstance(effectID, "回合奖励", args)); roundRewards[currentRound] = skills; } } return roundRewards; } public static double CalculateRating(CharacterStatistics stats, Team? team = null, CharacterStatistics[]? teammateStats = null) { // 基础得分 double baseScore = (stats.Kills + stats.Assists) / (stats.Kills + stats.Assists + stats.Deaths + 0.01); if (team is null) { baseScore += stats.Kills * 0.1; baseScore -= stats.Deaths * 0.05; } else { baseScore = baseScore * 0.6 + 0.4 * (stats.Kills / (stats.Kills + stats.Deaths + 0.01)); } // 伤害贡献 double damageContribution = Math.Log(1 + Math.Min(2, (stats.TotalDamage / (stats.TotalTakenDamage + 1.75)))); if (team != null && teammateStats != null) { // 考虑团队伤害排名,优先高伤害的 int damageRank = teammateStats.OrderByDescending(s => s.TotalDamage).ToList().IndexOf(stats) + 1; if (damageRank > 1) { double d = 1 - (0.1 * (damageRank - 1)); if (d < 0.1) d = 0.1; damageContribution *= d; } } // 存活时间贡献 double liveTimeContribution = Math.Log(1 + (stats.LiveTime / (stats.TotalTakenDamage + 0.01) * 100)); // 团队模式参团率加成 double teamContribution = 0; if (team != null) { if (stats.Assists > team.Score) stats.Assists = team.Score; teamContribution = (stats.Kills + stats.Assists) / (team.Score + 0.01); if (team.IsWinner) { teamContribution += 0.15; } } // 权重设置 double k = stats.Deaths > 0 ? 0.2 : 0.075; // 伤害贡献权重 double l = stats.Deaths > 0 ? 0.2 : 0.05; // 存活时间权重 double t = stats.Deaths > 0 ? 0.2 : 0.075; // 参团率权重 // 计算最终评分 double rating = baseScore + k * damageContribution + l * liveTimeContribution + t * teamContribution; // 确保评分在合理范围内 return Math.Max(0.01, rating); } public static void GetCharacterRating(Dictionary statistics, bool isTeam, List teams) { foreach (Character character in statistics.Keys) { Team? team = null; CharacterStatistics[]? teammateStats = null; if (isTeam) { team = teams.Where(t => t.IsOnThisTeam(character)).FirstOrDefault(); if (team != null) { teammateStats = [.. statistics.Where(kv => team.Members.Contains(kv.Key)).Select(kv => kv.Value)]; } } statistics[character].Rating = CalculateRating(statistics[character], team, teammateStats); } } public static string CheckQuestList(EntityModuleConfig quests) { if (quests.Count == 0) { // 生成任务 for (int i = 0; i < 6; i++) { QuestType type = (QuestType)Random.Shared.Next(3); long id = quests.Count > 0 ? quests.Values.Max(q => q.Id) + 1 : 1; // 定义概率 Dictionary pE = new() { { QualityType.Blue, 0.5 }, { QualityType.Purple, 0.37 }, { QualityType.Orange, 0.1 }, { QualityType.Red, 0.03 }, }; // 生成任务奖励物品 QualityType qualityType = QualityType.Blue; QualityType[] types = [.. pE.Keys.OrderByDescending(q => (int)q)]; foreach (QualityType qt in types) { if (Random.Shared.NextDouble() <= pE[qt]) { qualityType = qt; break; } } HashSet items = []; Dictionary itemsCount = []; Item? item = FunGameConstant.DrawCardItems.Where(i => qualityType == QualityType.Blue ? (int)i.QualityType <= (int)qualityType : (int)i.QualityType == (int)qualityType).OrderBy(o => Random.Shared.Next()).FirstOrDefault(); item ??= FunGameConstant.DrawCardItems.OrderBy(o => Random.Shared.Next()).First(); items.Add(item); itemsCount[item.Name] = 1; types = [.. pE.Keys.OrderByDescending(q => (int)q)]; foreach (QualityType qt in types) { if (Random.Shared.NextDouble() <= pE[qt]) { qualityType = qt; break; } } Item? item2 = FunGameConstant.DrawCardItems.Where(i => qualityType == QualityType.Blue ? (int)i.QualityType <= (int)qualityType : (int)i.QualityType == (int)qualityType).OrderBy(o => Random.Shared.Next()).FirstOrDefault(); item2 ??= FunGameConstant.DrawCardItems.OrderBy(o => Random.Shared.Next()).First(); items.Add(item2); if (!itemsCount.TryAdd(item2.Name, 1)) { itemsCount[item2.Name]++; } // 随机筛选地区 OshimaRegion region = FunGameConstant.Regions.OrderBy(o => Random.Shared.Next()).First(); Quest quest; if (type == QuestType.Continuous) { string name = region.ContinuousQuestList.Keys.OrderBy(o => Random.Shared.Next()).First(); QuestExploration exploration = region.ContinuousQuestList[name]; int minutes = Random.Shared.Next(10, 41); quest = new() { Id = id, Name = name, Description = exploration.Description, RegionId = region.Id, NeedyExploreItemName = exploration.Item, QuestType = QuestType.Continuous, EstimatedMinutes = minutes, CreditsAward = minutes * 40, MaterialsAward = minutes / 4, Awards = items, AwardsCount = itemsCount }; } else if (type == QuestType.Immediate) { string name = region.ImmediateQuestList.Keys.OrderBy(o => Random.Shared.Next()).First(); QuestExploration exploration = region.ImmediateQuestList[name]; int difficulty = Random.Shared.Next(3, 11); quest = new() { Id = id, Name = name, Description = exploration.Description, RegionId = region.Id, NeedyExploreItemName = exploration.Item, QuestType = QuestType.Immediate, CreditsAward = difficulty * 160, MaterialsAward = difficulty, Awards = items, AwardsCount = itemsCount }; } else { string name = region.ProgressiveQuestList.Keys.OrderBy(o => Random.Shared.Next()).First(); QuestExploration exploration = region.ProgressiveQuestList[name]; int maxProgress = Random.Shared.Next(3, 11); quest = new() { Id = id, Name = name, Description = string.Format(exploration.Description, maxProgress), RegionId = region.Id, NeedyExploreItemName = exploration.Item, QuestType = QuestType.Progressive, Progress = 0, MaxProgress = maxProgress, CreditsAward = maxProgress * 160, MaterialsAward = maxProgress, Awards = items, AwardsCount = itemsCount, Status = QuestState.InProgress }; } quests.Add(quest.GetIdName(), quest); } return "☆--- 今日任务列表 ---☆\r\n" + string.Join("\r\n", quests.Values.Select(q => q.ToString())) + "\r\n温馨提示:使用【做任务+任务序号】指令来进行任务。\r\n请务必在次日 4:00 前完成任务结算,未结算的任务都会被取消!"; } else { if (quests.Count > 0) { return "☆--- 今日任务列表 ---☆\r\n" + string.Join("\r\n", quests.Values.Select(q => q.ToString())) + "\r\n温馨提示:使用【做任务+任务序号】指令来进行任务。\r\n请务必在次日 4:00 前完成任务结算,未结算的任务都会被取消!"; } else { return "任务列表为空,请使用【任务列表】指令来获取任务列表!"; } } } public static bool SettleQuest(User user, EntityModuleConfig quests) { bool result = false; IEnumerable workingQuests = quests.Values.Where(q => q.QuestType == QuestType.Continuous && q.Status == QuestState.InProgress); foreach (Quest quest in workingQuests) { if (quest.StartTime.HasValue && quest.StartTime.Value.AddMinutes(quest.EstimatedMinutes) <= DateTime.Now) { quest.Status = QuestState.Completed; result = true; } } if (UserExploreItemCache.TryGetValue(user.Id, out List? value) && value != null && value.Count > 0) { // 从缓存中获取收集的物品 List willRemove = []; string[] itemsLoop = [.. value.Distinct()]; foreach (string item in itemsLoop) { IEnumerable items = value.Where(str => str == item); IEnumerable progressiveQuests = quests.Values.Where(q => q.QuestType == QuestType.Progressive && q.Status == QuestState.InProgress); foreach (Quest quest in progressiveQuests) { if (quest.NeedyExploreItemName == item) { result = true; quest.Progress += items.Count(); if (quest.Progress >= quest.MaxProgress) { quest.Progress = quest.MaxProgress; quest.Status = QuestState.Completed; } } } willRemove.Add(item); } value.RemoveAll(willRemove.Contains); } IEnumerable finishQuests = quests.Values.Where(q => q.Status == QuestState.Completed); foreach (Quest quest in finishQuests) { quest.Status = QuestState.Settled; quest.SettleTime = DateTime.Now; if (quest.CreditsAward > 0) { user.Inventory.Credits += quest.CreditsAward; } if (quest.MaterialsAward > 0) { user.Inventory.Materials += quest.MaterialsAward; } foreach (Item item in quest.Awards) { if (quest.AwardsCount.TryGetValue(item.Name, out int qty)) { for (int i = 0; i < qty; i++) { if (FunGameConstant.AllItems.FirstOrDefault(i => i.Name == item.Name) != null) { AddItemToUserInventory(user, item); } } } } TaskUtility.NewTask(async () => await AnonymousServer.PushMessageToClients(user.AutoKey, $"FunGame Web API 推送:你的任务【{quest.Name}】已结算," + $"获得奖励:【{quest.AwardsString}】!")); result = true; } return result; } public static void AddExploreItemCache(long userid, string item) { if (UserExploreItemCache.TryGetValue(userid, out List? value) && value != null) { value.Add(item); } else { UserExploreItemCache[userid] = [item]; } } public static string CheckDailyStore(EntityModuleConfig stores, User user) { Store? daily = stores.Get("daily"); if (daily is null) { // 生成每日商店 daily = new($"{user.Username}的每日商店") { AutoRefresh = true, RefreshInterval = 1 }; if (DateTime.Now > DateTime.Today.AddHours(4)) { daily.NextRefreshDate = DateTime.Today.AddDays(1).AddHours(4); } else { daily.NextRefreshDate = DateTime.Today.AddHours(4); } for (int i = 0; i < 4; i++) { Item item; if (Random.Shared.Next(3) < 1) { item = GenerateMagicCard((QualityType)Random.Shared.Next((int)QualityType.Gold + 1)); } else { int index = Random.Shared.Next(FunGameConstant.AllItems.Count); item = FunGameConstant.AllItems[index].Copy(); } item.Character = null; (int min, int max) = (0, 0); if (FunGameConstant.PriceRanges.TryGetValue(item.QualityType, out (int Min, int Max) range)) { (min, max) = (range.Min, range.Max); } double price = Random.Shared.Next(min, max); int stock = Random.Shared.Next(1, 3); if (item.ItemType == ItemType.MagicCard) { price *= 0.7; stock = 1; } else if (item.ItemType == ItemType.Consumable) { int prev = (int)item.QualityType - 1; int current = (int)item.QualityType; min = 300 * (1 + (prev * prev - prev)); max = 300 * (1 + (current * current - current)); price = Random.Shared.Next(min, max); stock += 3; } if (price == 0) { price = (Random.Shared.NextDouble() + 0.1) * Random.Shared.Next(1000, 5000) * Random.Shared.Next((int)item.QualityType + 2, 6 + ((int)item.QualityType)); } item.Price = (int)price; daily.AddItem(item, stock); } stores.Add("daily", daily); SetLastStore(user, true, "", ""); return daily.ToString(user) + $"\r\n☆--- {user.Inventory.Name} ---☆\r\n现有{General.GameplayEquilibriumConstant.InGameCurrency}:{user.Inventory.Credits:0.##}\r\n现有{General.GameplayEquilibriumConstant.InGameMaterial}:{user.Inventory.Materials:0.##}"; } else { SetLastStore(user, true, "", ""); return daily.ToString(user) + $"\r\n☆--- {user.Inventory.Name} ---☆\r\n现有{General.GameplayEquilibriumConstant.InGameCurrency}:{user.Inventory.Credits:0.##}\r\n现有{General.GameplayEquilibriumConstant.InGameMaterial}:{user.Inventory.Materials:0.##}"; } } public static void SetLastStore(User? user, bool isDaily, string storeRegion, string storeName) { if (user != null && FunGameConstant.UserLastVisitStore.TryGetValue(user.Id, out LastStoreModel? value) && value != null) { value.LastTime = DateTime.Now; value.IsDaily = isDaily; value.StoreRegion = storeRegion; value.StoreName = storeName; } else if (user != null) { FunGameConstant.UserLastVisitStore[user.Id] = new() { LastTime = DateTime.Now, IsDaily = isDaily, StoreRegion = storeRegion, StoreName = storeName }; } } public static string StoreBuyItem(Store store, Goods goods, PluginConfig pc, User user, int count) { string msg = ""; DateTime now = DateTime.Now; if (store.StartTime > now || store.EndTime < now) { return "商店未处于营业时间内。"; } if (goods.Stock != -1 && goods.Stock - count < 0) { return $"此商品【{goods.Name}】库存不足,无法购买!\r\n你想要购买 {count} 件,但库存只有 {goods.Stock} 件。"; } goods.UsersBuyCount.TryGetValue(user.Id, out int buyCount); if (goods.Quota > 0 && (buyCount + count > goods.Quota)) { return $"此商品【{goods.Name}】限量购买 {goods.Quota} 件!\r\n你已经购买了 {buyCount} 件,想要购买 {count} 件,超过了购买限制。"; } foreach (string needy in goods.Prices.Keys) { if (needy == General.GameplayEquilibriumConstant.InGameCurrency) { double reduce = Calculation.Round2Digits(goods.Prices[needy] * count); if (user.Inventory.Credits >= reduce) { user.Inventory.Credits -= reduce; } else { return $"你的{General.GameplayEquilibriumConstant.InGameCurrency}不足 {reduce} 呢,无法购买【{goods.Name}】!"; } } else if (needy == General.GameplayEquilibriumConstant.InGameMaterial) { double reduce = Calculation.Round2Digits(goods.Prices[needy] * count); if (user.Inventory.Materials >= reduce) { user.Inventory.Materials -= reduce; } else { return $"你的{General.GameplayEquilibriumConstant.InGameMaterial}不足 {reduce} 呢,无法购买【{goods.Name}】!"; } } else if (needy == "锻造积分") { double reduce = Calculation.Round2Digits(goods.Prices[needy] * count); if (pc.TryGetValue("forgepoints", out object? value) && double.TryParse(value.ToString(), out double points) && points >= reduce) { points -= reduce; pc.Add("forgepoints", points); } else { return $"你的{needy}不足 {reduce} 呢,无法购买【{goods.Name}】!"; } } else { return $"不支持的货币类型:{needy},无法购买【{goods.Name}】!"; } } foreach (Item item in goods.Items) { if (item.Id == (long)SpecialItemID.探索许可) { int exploreTimes = FunGameConstant.MaxExploreTimes + count; if (pc.TryGetValue("exploreTimes", out object? value) && int.TryParse(value.ToString(), out exploreTimes)) { exploreTimes += count; } pc.Add("exploreTimes", exploreTimes); } else { for (int i = 0; i < count; i++) { if (goods.GetPrice(General.GameplayEquilibriumConstant.InGameCurrency, out double price)) { price = Calculation.Round2Digits(price * 0.35); } AddItemToUserInventory(user, item, copyLevel: true, price: price); } } } if (goods.Stock != -1) { goods.Stock -= count; if (goods.Stock < 0) goods.Stock = 0; } if (!goods.UsersBuyCount.TryAdd(user.Id, count)) { goods.UsersBuyCount[user.Id] += count; } msg += $"恭喜你成功购买 {count} 件【{goods.Name}】!\r\n" + (goods.Quota > 0 ? $"此商品限购 {goods.Quota} 件,你还可以再购买 {goods.Quota - count - buyCount} 件。\r\n" : "") + $"总计消费:{(goods.Prices.Count > 0 ? string.Join("、", goods.Prices.Select(kv => $"{kv.Value * count:0.##} {kv.Key}")) : "免单")}\r\n" + $"包含物品:{string.Join("、", goods.Items.Select(i => $"[{ItemSet.GetQualityTypeName(i.QualityType)}|{ItemSet.GetItemTypeName(i.ItemType)}] {i.Name} * {count}"))}\r\n" + $"{store.Name}期待你的下次光临。"; return msg; } public static string MarketBuyItem(Market market, MarketItem item, PluginConfig pc, User user, int count, out bool result) { result = false; string msg = ""; DateTime now = DateTime.Now; if (market.StartTime > now || market.EndTime < now) { return "铎京集市未处于营业时间内。"; } if (item.Status != MarketItemState.Listed) { return $"无法购买此商品,原因:该商品的状态是:{CommonSet.GetMarketItemStatus(item.Status)}。"; } if (item.User == user.Id) { return $"不能购买自己上架的商品!如需下架,请使用【市场下架+序号】指令。"; } if (item.Stock != -1 && item.Stock - count < 0) { return $"此商品【{item.Name}】库存不足,无法购买!\r\n你想要购买 {count} 件,但库存只有 {item.Stock} 件。"; } double reduce = Calculation.Round2Digits(item.Price * count); if (user.Inventory.Credits >= reduce) { user.Inventory.Credits -= reduce; } else { return $"你的{General.GameplayEquilibriumConstant.InGameCurrency}不足 {reduce} 呢,无法购买【{item.Name}】!"; } if (item.Item.Id == (long)SpecialItemID.探索许可) { int exploreTimes = FunGameConstant.MaxExploreTimes + count; if (pc.TryGetValue("exploreTimes", out object? value) && int.TryParse(value.ToString(), out exploreTimes)) { exploreTimes += count; } pc.Add("exploreTimes", exploreTimes); } else { for (int i = 0; i < count; i++) { AddItemToUserInventory(user, item.Item, copyLevel: true, useOriginalPrice: true, toExploreCache: false, toActivitiesCache: false); } } if (item.Stock != -1) { item.Stock -= count; if (item.Stock < 0) item.Stock = 0; if (item.Stock == 0) { item.Status = MarketItemState.Purchased; item.FinishTime = DateTime.Now; } } item.Buyers.Add(user.Id); result = true; msg += $"恭喜你成功购买 {count} 件【{item.Name}】!\r\n" + $"总计消费:{(item.Price > 0 ? item.Price : "免单")}\r\n" + $"包含物品:[{ItemSet.GetQualityTypeName(item.Item.QualityType)}|{ItemSet.GetItemTypeName(item.Item.ItemType)}] {item.Item.Name} * {count}\r\n" + $"铎京集市期待你的下次光临。"; return msg; } public static string Select_CheckAutoKey(SQLHelper SQLHelper, string AutoKey) { SQLHelper.Parameters["@AutoKey"] = AutoKey; return $"{Milimoe.FunGame.Core.Library.SQLScript.Entity.UserQuery.Select_Users} {Milimoe.FunGame.Core.Library.SQLScript.Constant.Command_Where} {Milimoe.FunGame.Core.Library.SQLScript.Entity.UserQuery.Column_AutoKey} = @AutoKey"; } public static void SetCharacterPrimaryAttribute(Character character, PrimaryAttribute? value = null) { if (value != null && value.HasValue) { character.PrimaryAttribute = value.Value; } else { double max = Math.Max(Math.Max(character.STR, character.AGI), character.INT); if (max == character.STR) { character.PrimaryAttribute = PrimaryAttribute.STR; } else if (max == character.AGI) { character.PrimaryAttribute = PrimaryAttribute.AGI; } else if (max == character.INT) { character.PrimaryAttribute = PrimaryAttribute.INT; } } } public static async Task UpdateRegionWeather() { Region[] regions = [.. FunGameConstant.Regions.Union(FunGameConstant.PlayerRegions)]; foreach (Region region in regions) { region.ChangeRandomWeather(); } await Task.CompletedTask; } public static string GetEventCenter() { EntityModuleConfig activities = new("activities", "activities"); activities.LoadConfig(); if (activities.Count == 0) { return "当前没有任何活动,敬请期待。"; } lock (Activities) { Activities.Clear(); foreach (Activity activity in activities.Values) { Activities.Add(activity); } bool update = false; if (ActivitiesCharacterCache.Count > 0) { List willRemove = []; IEnumerable activityList = Activities.Where(a => a.Status == ActivityState.InProgress); IEnumerable itemsLoop = ActivitiesCharacterCache.Distinct(); foreach (string item in itemsLoop) { IEnumerable items = ActivitiesCharacterCache.Where(str => str == item); IEnumerable quests = activityList.SelectMany(a => a.Quests).Where(q => q.Status == QuestState.InProgress); foreach (Quest quest in quests) { if (quest.NeedyExploreCharacterName == item) { update = true; quest.Progress += items.Count(); if (quest.Progress >= quest.MaxProgress) { quest.Progress = quest.MaxProgress; quest.Status = QuestState.Completed; } } } willRemove.Add(item); } ActivitiesCharacterCache.RemoveAll(willRemove.Contains); } if (ActivitiesItemCache.Count > 0) { List willRemove = []; IEnumerable activityList = Activities.Where(a => a.Status == ActivityState.InProgress); IEnumerable itemsLoop = ActivitiesItemCache.Distinct(); foreach (string item in itemsLoop) { IEnumerable items = ActivitiesItemCache.Where(str => str == item); IEnumerable quests = activityList.SelectMany(a => a.Quests).Where(q => q.Status == QuestState.InProgress); foreach (Quest quest in quests) { if (quest.NeedyExploreItemName == item) { update = true; quest.Progress += items.Count(); if (quest.Progress >= quest.MaxProgress) { quest.Progress = quest.MaxProgress; quest.Status = QuestState.Completed; } } } willRemove.Add(item); } ActivitiesItemCache.RemoveAll(willRemove.Contains); } if (ActivitiesEventCache.Count > 0) { List willRemove = []; IEnumerable activityList = Activities.Where(a => a.Status == ActivityState.InProgress); IEnumerable itemsLoop = ActivitiesEventCache.Distinct(); foreach (string item in itemsLoop) { IEnumerable items = ActivitiesEventCache.Where(str => str == item); IEnumerable quests = activityList.SelectMany(a => a.Quests).Where(q => q.Status == QuestState.InProgress); foreach (Quest quest in quests) { if (quest.NeedyExploreEventName == item) { update = true; quest.Progress += items.Count(); if (quest.Progress >= quest.MaxProgress) { quest.Progress = quest.MaxProgress; quest.Status = QuestState.Completed; } } } willRemove.Add(item); } ActivitiesEventCache.RemoveAll(willRemove.Contains); } if (update) { foreach (Activity activity in Activities) { activities.Add(activity.Id.ToString(), activity); } activities.SaveConfig(); } } StringBuilder builder = new(); builder.AppendLine("★☆★ 活动中心 ★☆★"); ActivityState[] status = [ActivityState.InProgress, ActivityState.Upcoming, ActivityState.Future, ActivityState.Ended]; foreach (ActivityState state in status) { IEnumerable filteredActivities = activities.Values.Where(a => a.Status == state); if (filteredActivities.Any()) { builder.AppendLine($"【{CommonSet.GetActivityStatus(state)}】"); builder.AppendLine($"{string.Join("\r\n", filteredActivities.Select(a => a.GetIdName() + $"({a.GetTimeString(false)})"))}"); } } builder.AppendLine("请使用【查活动+活动序号】指令查询活动详细信息。"); return builder.ToString().Trim(); } public static string GetEvents(ActivityState status = ActivityState.InProgress) { GetEventCenter(); IEnumerable filteredActivities = Activities.Where(a => a.Status == status); if (!filteredActivities.Any()) { return $"当前没有任何{CommonSet.GetActivityStatus(status)}的活动,敬请期待。"; } return $"★☆★ {CommonSet.GetActivityStatus(status)}活动列表 ★☆★\r\n" + $"{string.Join("\r\n", filteredActivities.Select(a => a.GetIdName() + $"({a.GetTimeString(false)})"))}\r\n" + $"请使用【查活动+活动序号】指令查询活动详细信息。"; } public static string GetEvent(long id) { GetEventCenter(); if (Activities.FirstOrDefault(a => a.Id == id) is Activity activity) { return $"{activity}"; } return "该活动不存在。"; } public static string AddEvent(Activity activity) { EntityModuleConfig activities = new("activities", "activities"); activities.LoadConfig(); activity.UpdateState(); activities.Add(activity.Id.ToString(), activity); activities.SaveConfig(); return "该活动已添加!"; } public static string RemoveEvent(Activity activity) { EntityModuleConfig activities = new("activities", "activities"); activities.LoadConfig(); activities.Remove(activity.Id.ToString()); activities.SaveConfig(); return "该活动已删除!"; } public static string GetSquadInfo(IEnumerable inventory, IEnumerable squadIds, string separator = "\r\n") { Character[] squad = [.. inventory.Where(c => squadIds.Contains(c.Id))]; Dictionary characters = inventory .Select((character, index) => new { character, index }) .ToDictionary(x => x.character, x => x.index + 1); return $"{(squad.Length > 0 ? string.Join(separator, squad.Select(c => $"#{characters[c]}. {c.ToStringWithLevelWithOutUser()}")) : "空")}"; } public static string GetCharacterGroupInfoByInventorySequence(IEnumerable inventory, IEnumerable characterIds, string separator = "\r\n") { Dictionary characters = []; Character[] loop = [.. inventory]; for (int i = 1; i <= loop.Length; i++) { if (characterIds.Contains(i)) { characters[loop[i - 1]] = i; } } return $"{(characters.Count > 0 ? string.Join(separator, characters.Keys.Select(c => $"#{characters[c]}. {c.ToStringWithLevelWithOutUser()}")) : "空")}"; } public static async Task GenerateExploreModel(ExploreModel model, OshimaRegion region, long[] characterIds, User user) { QualityType[] types = []; int characterCount = characterIds.Length; int diff = region.Difficulty switch { RarityType.OneStar => 1, RarityType.TwoStar => 2, RarityType.ThreeStar => 3, RarityType.FourStar => 4, _ => 5 }; // 直接保存探索奖励,但是要等到探索结束后发放 double randomDouble = Random.Shared.NextDouble(); Dictionary probabilities = new(FunGameConstant.ExploreResultProbabilities); switch (diff) { case 2: probabilities[ExploreResult.General] -= 0.1; probabilities[ExploreResult.Fight] += 0.1; break; case 3: probabilities[ExploreResult.General] -= 0.15; probabilities[ExploreResult.Earned] -= 0.05; probabilities[ExploreResult.Nothing] += 0.05; probabilities[ExploreResult.Fight] += 0.15; break; case 4: probabilities[ExploreResult.General] -= 0.3; probabilities[ExploreResult.Earned] -= 0.05; probabilities[ExploreResult.Fight] += 0.35; break; case 5: probabilities[ExploreResult.General] -= 0.35; probabilities[ExploreResult.Earned] -= 0.05; probabilities[ExploreResult.Nothing] -= 0.05; probabilities[ExploreResult.Fight] += 0.45; break; default: break; } double cumulative = 0; model.Result = ExploreResult.Nothing; foreach (ExploreResult key in probabilities.Keys) { cumulative += probabilities[key]; if (randomDouble <= cumulative) { model.Result = key; break; } } string exploreString = FunGameConstant.ExploreString[model.Result].OrderBy(o => Random.Shared.Next()).First(); // 出现的NPC int random = Random.Shared.Next(region.NPCs.Count + 1); string npc = random == region.NPCs.Count ? GenerateRandomChineseUserName() : region.NPCs[random]; // 探索的子区域 random = Random.Shared.Next(region.Areas.Count); string area1 = region.Areas[random]; random = Random.Shared.Next(region.Areas.Count); string area2 = region.Areas[random]; // 出现的物品 List items = [.. region.Crops.Union(region.Items)]; random = Random.Shared.Next(items.Count); string item1 = items[random].Name; random = Random.Shared.Next(items.Count); string item2 = items[random].Name; // 筛选敌人 List enemys = []; Character enemy; bool isUnit = Random.Shared.Next(2) != 0; if (region.Characters.Count > 0 && region.Units.Count > 0) { if (!isUnit) { enemy = region.Characters.OrderBy(o => Random.Shared.Next()).First().Copy(); enemy.ExHPPercentage += 0.5; enemys.Add(enemy); } else { switch (diff) { case 1: case 2: enemy = region.Units.OrderBy(o => Random.Shared.Next()).First().Copy(); enemys.Add(enemy); break; case 3: case 4: enemy = region.Units.OrderBy(o => Random.Shared.Next()).First().Copy(); enemys.Add(enemy); enemy = region.Units.OrderBy(o => Random.Shared.Next()).First().Copy(); enemy.FirstName = enemys.Any(e => e.Name == enemy.Name) ? "2" : ""; enemys.Add(enemy); break; case 5: default: enemy = region.Units.OrderBy(o => Random.Shared.Next()).First().Copy(); enemys.Add(enemy); enemy = region.Units.OrderBy(o => Random.Shared.Next()).First().Copy(); enemy.FirstName = enemys.Any(e => e.Name == enemy.Name) ? "α" : ""; enemys.Add(enemy); enemy = region.Units.OrderBy(o => Random.Shared.Next()).First().Copy(); enemy.FirstName = enemys.Any(e => e.Name == enemy.Name) ? "β" : ""; enemys.Add(enemy); break; } } } else { if (!isUnit) { enemy = new RegionCharacter(long.Parse(Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 8)), GenerateRandomChineseUserName()); enemys.Add(enemy); } else { switch (diff) { case 1: case 2: enemy = new RegionUnit(long.Parse(Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 8)), GenerateRandomChineseUserName()); enemys.Add(enemy); break; case 3: case 4: enemy = new RegionUnit(long.Parse(Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 8)), GenerateRandomChineseUserName()); enemys.Add(enemy); enemy = new RegionUnit(long.Parse(Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 8)), GenerateRandomChineseUserName()); enemys.Add(enemy); break; case 5: default: enemy = new RegionUnit(long.Parse(Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 8)), GenerateRandomChineseUserName()); enemys.Add(enemy); enemy = new RegionUnit(long.Parse(Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 8)), GenerateRandomChineseUserName()); enemys.Add(enemy); enemy = new RegionUnit(long.Parse(Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 8)), GenerateRandomChineseUserName()); enemys.Add(enemy); break; } } } // 初始化掉落装备的概率 Dictionary pE = new() { { QualityType.Blue, 0.5 }, { QualityType.Purple, 0.37 + (0.01 * (characterCount - 1)) }, { QualityType.Orange, 0.1 + (0.01 * (characterCount - 1)) }, { QualityType.Red, 0.03 + (0.0075 * (characterCount - 1)) }, }; // 生成奖励 string award = ""; switch (model.Result) { case ExploreResult.General: switch (Random.Shared.Next(3)) { case 0: int credits = 0; for (int i = 0; i < characterCount; i++) { credits += Random.Shared.Next(250, 400) * diff; } model.CreditsAward = credits; award = $" {credits} {General.GameplayEquilibriumConstant.InGameCurrency}"; break; case 1: int materials = 0; for (int i = 0; i < characterCount; i++) { materials += 2 * diff; } model.MaterialsAward = materials; award = $" {materials} {General.GameplayEquilibriumConstant.InGameMaterial}"; break; case 2: Item item = FunGameConstant.ExploreItems[region][Random.Shared.Next(FunGameConstant.ExploreItems[region].Count)]; int count = 0; for (int i = 0; i < characterCount; i++) { count += Math.Max(1, Random.Shared.Next(1, 4) * diff / 2); } model.Awards[item.Name] = count; award = $" {count} 个{item.Name}"; break; default: break; } int exp = 0; for (int i = 0; i < characterCount; i++) { exp += Random.Shared.Next(300, 750) * diff; } model.Awards["exp"] = exp; exploreString += $"额外获得了:{exp} 点经验值(探索队员们平分)!"; break; case ExploreResult.Fight: // 小队信息 Character[] squad = [.. user.Inventory.Characters.Where((c, index) => characterIds.Contains(index + 1)).Select(c => CharacterBuilder.Build(c, true, true, null, FunGameConstant.AllItems, FunGameConstant.AllSkills, false))]; if (squad.All(c => c.HP <= 0)) { model.Result = ExploreResult.Nothing; exploreString = $"探索小队遭遇强大的敌人{enemy.Name}偷袭,狼狈而逃!(什么也没有获得,请检查角色的状态)"; } else { // 生成敌人 Item[] weapons = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("11") && (int)i.QualityType == 5)]; Item[] armors = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("12") && (int)i.QualityType == 5)]; Item[] shoes = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("13") && (int)i.QualityType == 5)]; Item[] accessory = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("14") && (int)i.QualityType == 5)]; Item[] consumables = [.. FunGameConstant.AllItems.Where(i => i.ItemType == ItemType.Consumable && i.IsInGameItem)]; int cLevel = diff * 12; int sLevel = diff + 1; int mLevel = region.Difficulty switch { RarityType.OneStar => 1, RarityType.TwoStar => 2, RarityType.ThreeStar => 4, RarityType.FourStar => 6, _ => 8 }; int naLevel = mLevel; foreach (Character enemy_loop in enemys) { EnhanceBoss(enemy_loop, weapons, armors, shoes, accessory, consumables, cLevel, sLevel, mLevel, naLevel, false, false, isUnit); } // 开始战斗 Team team1 = new($"{user.Username}的探索小队", squad); Team team2 = new($"{region.Name}", enemys); FunGameActionQueue actionQueue = new(); List msgs = await actionQueue.StartTeamGame([team1, team2], showAllRound: true); if (msgs.Count > 2) { msgs = msgs[^2..]; } if (enemys.All(c => c.HP <= 0)) { model.FightWin = true; int credits = 0; for (int i = 0; i < characterCount; i++) { credits += Random.Shared.Next(400, 650) * diff; } if (actionQueue.GamingQueue.EarnedMoney.Count > 0) { credits += actionQueue.GamingQueue.EarnedMoney.Where(kv => squad.Contains(kv.Key)).Sum(kv => kv.Value); } model.CreditsAward = credits; exp = 0; for (int i = 0; i < characterCount; i++) { exp += Random.Shared.Next(370, 860) * diff; } model.Awards["exp"] = exp; int materials = 0; for (int i = 0; i < characterCount; i++) { materials += Random.Shared.Next(3, 7) * diff; } model.MaterialsAward = materials; Item item = FunGameConstant.ExploreItems[region][Random.Shared.Next(FunGameConstant.ExploreItems[region].Count)]; int count = 0; for (int i = 0; i < characterCount; i++) { count += Math.Max(1, Random.Shared.Next(1, 4) * diff / 2); } model.Awards[item.Name] = count; award = $"{credits} {General.GameplayEquilibriumConstant.InGameCurrency}(包含战斗中击杀奖励)," + $"{exp} 点经验值(探索队员们平分)," + $"{materials} {General.GameplayEquilibriumConstant.InGameMaterial}," + $"以及 {count} 个{item.Name}"; if (Random.Shared.NextDouble() > 0.6) { QualityType qualityType = QualityType.Blue; types = [.. pE.Keys.OrderByDescending(q => (int)q)]; foreach (QualityType type in types) { if (Random.Shared.NextDouble() <= pE[type]) { qualityType = type; break; } } Item? itemDrop = region.Items.Where(i => qualityType == QualityType.Blue ? (int)i.QualityType <= (int)qualityType : (int)i.QualityType == (int)qualityType).OrderBy(o => Random.Shared.Next()).FirstOrDefault(); if (itemDrop != null) { model.Awards[itemDrop.Name] = 1; string itemquality = ItemSet.GetQualityTypeName(itemDrop.QualityType); string itemtype = ItemSet.GetItemTypeName(itemDrop.ItemType) + (itemDrop.ItemType == ItemType.Weapon && itemDrop.WeaponType != WeaponType.None ? "-" + ItemSet.GetWeaponTypeName(itemDrop.WeaponType) : ""); if (itemtype != "") itemtype = $"|{itemtype}"; award += $"!额外获得了:[{itemquality + itemtype}]{itemDrop.Name}"; } } exploreString = $"{exploreString}\r\n{string.Join("\r\n", msgs)}\r\n探索小队战胜了{enemy.Name}!获得了:{award}!"; } else { exploreString = $"{exploreString}\r\n{string.Join("\r\n", msgs)}\r\n探索小队未能战胜{enemy.Name},"; IEnumerable deadEnemys = enemys.Where(c => c.HP <= 0); if (!deadEnemys.Any()) { exploreString += "探索宣告失败!(什么也没有获得)"; } else { Item item = FunGameConstant.ExploreItems[region][Random.Shared.Next(FunGameConstant.ExploreItems[region].Count)]; model.Awards[item.Name] = deadEnemys.Count(); award = $"{deadEnemys.Count()} 个{item.Name}"; exploreString += $"但是获得了补偿:{award}!"; } } model.AfterFightHPs = [.. squad.Select(c => c.HP)]; } break; case ExploreResult.Earned: QualityType quality = QualityType.Blue; types = [.. pE.Keys.OrderByDescending(q => (int)q)]; foreach (QualityType type in types) { if (Random.Shared.NextDouble() <= pE[type]) { quality = type; break; } } Item? itemEarned = region.Items.Where(i => quality == QualityType.Blue ? (int)i.QualityType <= (int)quality : (int)i.QualityType == (int)quality).OrderBy(o => Random.Shared.Next()).FirstOrDefault(); if (itemEarned is null) { model.Result = ExploreResult.Nothing; exploreString = "你在探索中发现了一个神秘的物品,但它似乎无法辨认。(什么也没有获得)"; } else { model.Awards[itemEarned.Name] = 1; string itemquality = ItemSet.GetQualityTypeName(itemEarned.QualityType); string itemtype = ItemSet.GetItemTypeName(itemEarned.ItemType) + (itemEarned.ItemType == ItemType.Weapon && itemEarned.WeaponType != WeaponType.None ? "-" + ItemSet.GetWeaponTypeName(itemEarned.WeaponType) : ""); if (itemtype != "") itemtype = $"|{itemtype}"; award += $"[{itemquality + itemtype}]{itemEarned.Name}"; } break; case ExploreResult.Event: break; case ExploreResult.Nothing: default: break; } model.String = string.Format(exploreString, award, enemy.Name, npc, item1, area1, item2, area2); PluginConfig pc = new("exploring", user.Id.ToString()); pc.LoadConfig(); pc.Add(model.Guid.ToString(), model); pc.SaveConfig(); } public static string GetExploreInfo(ExploreModel model, IEnumerable inventoryCharacters, IEnumerable regions) { StringBuilder sb = new(); if (model.CharacterIds.Any()) { if (regions.FirstOrDefault(r => r.Id == model.RegionId) is Region region) { sb.AppendLine($"☆--- 正在探索 {model.RegionId} 号地区:{region.Name} ---☆"); if (model.StartTime != null) { sb.AppendLine($"探索时间:{model.StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)}"); } sb.AppendLine($"探索角色:{GetCharacterGroupInfoByInventorySequence(inventoryCharacters, model.CharacterIds, ",")}"); } } return sb.ToString().Trim(); } public static bool SettleExplore(string exploreId, PluginConfig pc, User user, out string msg) { bool result = false; msg = ""; ExploreModel? model = pc.Get(exploreId); if (model != null) { result = true; msg = model.String; if (model.CreditsAward > 0) { user.Inventory.Credits += model.CreditsAward; } if (model.MaterialsAward > 0) { user.Inventory.Materials += model.MaterialsAward; } Character[] inventory = [.. user.Inventory.Characters]; foreach (string name in model.Awards.Keys) { if (name == "exp") { double exp = (double)model.Awards[name] / model.CharacterIds.Count(); foreach (long cid in model.CharacterIds) { if (cid > 0 && cid <= inventory.Length) { Character character = inventory[(int)cid - 1]; character.EXP += exp; } } continue; } Item? item = FunGameConstant.AllItems.FirstOrDefault(i => i.Name == name); if (item != null) { for (int i = 0; i < model.Awards[name]; i++) { AddItemToUserInventory(user, item); } } } if (model.AfterFightHPs.Length > 0) { int hpIndex = 0; foreach (long cid in model.CharacterIds) { if (cid > 0 && cid <= inventory.Length && hpIndex < model.AfterFightHPs.Length) { Character character = inventory[(int)cid - 1]; character.HP = model.AfterFightHPs[hpIndex++]; } } } } return result; } public static bool SettleExploreAll(PluginConfig pc, User user, bool skip = false) { bool settle = false; List remove = []; foreach (string guid in pc.Keys) { ExploreModel? model = pc.Get(guid); if (model is null) continue; if (skip || (model.StartTime.HasValue && (DateTime.Now - model.StartTime.Value).TotalMinutes > FunGameConstant.ExploreTime + 2)) { if (SettleExplore(guid, pc, user, out string msg)) { settle = true; AddNotice(user.Id, $"你上次未完成的探索已被自动结算:{msg}"); remove.Add(guid); } } } foreach (string guid in remove) { pc.Remove(guid); } return settle; } public static long MakeOffer(User user, User offeree) { using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper(); if (sql != null) { sql.AddOffer(user.Id, offeree.Id); if (sql.Success) { long offerId = sql.LastInsertId; Offer? offer = SQLService.GetOffer(sql, offerId); if (offer != null) { return offerId; } } } return -1; } public static string AddOfferItems(User user, long offerId, bool isOpposite, int[] itemIds) { using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper(); if (sql != null) { bool result = true; string msg = ""; Offer? offer = SQLService.GetOffer(sql, offerId); if (offer != null && offer.Offeror == user.Id) { try { if (offer.Status != OfferState.Created) { msg = "当前状态不允许修改报价内容。"; return msg; } User user2; PluginConfig pc2 = new("saved", offer.Offeree.ToString()); pc2.LoadConfig(); if (pc2.Count > 0) { user2 = GetUser(pc2); } else { return "无法找到报价的接收方,请稍后再试。"; } User addUser = isOpposite ? user2 : user; offer.OfferorItems = [.. SQLService.GetOfferItemsByOfferIdAndUserId(sql, offerId, user)]; offer.OffereeItems = [.. SQLService.GetOfferItemsByOfferIdAndUserId(sql, offerId, user2)]; sql.NewTransaction(); List failedItems = []; foreach (int itemIndex in itemIds) { if (itemIndex > 0 && itemIndex <= addUser.Inventory.Items.Count) { Item item = addUser.Inventory.Items.ToList()[itemIndex - 1]; if (addUser.Id == offer.Offeror && offer.OfferorItems.Contains(item.Guid) || addUser.Id == offer.Offeree && offer.OffereeItems.Contains(item.Guid)) { result = false; if (msg != "") msg += "\r\n"; msg += $"物品 {itemIndex}. {item.Name}:此物品已在报价中,无需重复添加。"; continue; } if (SQLService.IsItemInOffers(sql, item.Guid)) { result = false; if (msg != "") msg += "\r\n"; msg += $"物品 {itemIndex}. {item.Name}:此物品已经在其它的交易报价中了,无法多次添加。"; break; } if (item.IsLock) { result = false; if (msg != "") msg += "\r\n"; msg += $"物品 {itemIndex}. {item.Name}:此物品已锁定,无法进行交易。"; break; } if (item.Character != null) { result = false; if (msg != "") msg += "\r\n"; msg += $"物品 {itemIndex}. {item.Name}:此物品已被 {item.Character} 装备中,无法进行交易。"; break; } if (!item.IsTradable) { result = false; if (msg != "") msg += "\r\n"; msg += $"物品 {itemIndex}. {item.Name}:此物品无法交易{(item.NextTradableTime != DateTime.MinValue ? $",此物品将在 {item.NextTradableTime.ToString(General.GeneralDateTimeFormatChinese)} 后可交易" : "")}。"; break; } sql.AddOfferItem(offerId, addUser.Id, item.Guid); if (msg != "") msg += "\r\n"; if (sql.Success) { msg += $"物品添加成功:{itemIndex}. {item.Name}"; } else { result = false; msg += $"物品添加失败:{itemIndex}. {item.Name}"; break; } } else { failedItems.Add(itemIndex); } } if (failedItems.Count > 0) { if (msg != "") msg += "\r\n"; msg += "没有找到与这个序号相对应的物品:" + string.Join(",", failedItems); } if (result) { offer = SQLService.GetOffer(sql, offerId); if (offer != null) { sql.Commit(); } } else { sql.Rollback(); } } catch { sql.Rollback(); msg = "修改报价时发生错误,请稍后再试。"; throw; } } else { msg = "报价不存在或你不是该报价的发起方。"; } return msg; } return "服务器繁忙,请稍后再试。"; } public static string SendOffer(User user, long offerId) { using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper(); if (sql != null) { string msg = ""; Offer? offer = SQLService.GetOffer(sql, offerId); if (offer != null && offer.Offeror == user.Id) { try { if (offer.Status != OfferState.Created) { msg = "此报价已被处理。"; return msg; } bool result = true; sql.NewTransaction(); sql.UpdateOfferStatus(offerId, OfferState.Sent); if (result) { offer = SQLService.GetOffer(sql, offerId); if (offer != null) { sql.Commit(); AddNotice(offer.Offeree, $"你收到了一个报价!请通过【查报价{offerId}】查询报价记录。"); return $"报价编号 {offerId} 已发送。"; } } else { sql.Rollback(); } } catch { sql.Rollback(); msg = "修改报价时发生错误,请稍后再试。"; throw; } } else { msg = "报价不存在或你不是该报价的发起方。"; } return msg; } return "服务器繁忙,请稍后再试。"; } public static List GetOffer(User user, out string msg, long offerId = -1) { msg = ""; List offers = []; using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper(); if (sql != null) { if (offerId > 0) { Offer? offer = SQLService.GetOffer(sql, offerId); if (offer != null) { if (offer.Offeror == user.Id || offer.Offeree == user.Id) { offers.Add(offer); } else { msg = $"你无权查看报价编号 {offerId}。"; } } else msg = $"报价编号 {offerId} 不存在。"; } else { offers = sql.GetOffersByOfferor(user.Id); offers = [.. offers, .. sql.GetOffersByOfferee(user.Id)]; offers = [.. offers.DistinctBy(o => o.Id).OrderByDescending(o => o.Id)]; } } return offers; } public static string RemoveOfferItems(User user, long offerId, bool isOpposite, int[] itemIds) { using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper(); if (sql != null) { bool result = true; string msg = ""; Offer? offer = SQLService.GetOffer(sql, offerId); if (offer != null && offer.Offeror == user.Id) { try { if (offer.Status != OfferState.Created) { msg = "当前状态不允许修改报价内容。"; return msg; } User removeUser; List guids = []; if (isOpposite) { PluginConfig pc2 = new("saved", offer.Offeree.ToString()); pc2.LoadConfig(); if (pc2.Count > 0) { removeUser = GetUser(pc2); } else { return "无法找到报价的接收方,请稍后再试。"; } } else { removeUser = user; } guids = [.. SQLService.GetOfferItemsByOfferIdAndUserId(sql, offerId, removeUser)]; sql.NewTransaction(); List failedItems = []; foreach (int itemIndex in itemIds) { if (itemIndex > 0 && itemIndex <= guids.Count) { Guid itemGuid = guids[itemIndex - 1]; SQLService.DeleteOfferItemsByOfferIdAndItemGuid(sql, offerId, itemGuid); } else { failedItems.Add(itemIndex); } } if (failedItems.Count > 0) { if (msg != "") msg += "\r\n"; msg += $"在报价的{(isOpposite ? "接收方" : "发起方")}物品列表中没有找到与这个序号相对应的物品:{string.Join(",", failedItems)}"; } if (result) { offer = SQLService.GetOffer(sql, offerId); if (offer != null) { sql.Commit(); } } else { sql.Rollback(); } } catch { sql.Rollback(); msg = "修改报价时发生错误,请稍后再试。"; throw; } } else { msg = "报价不存在或你不是该报价的发起方。"; } return msg; } return "服务器繁忙,请稍后再试。"; } public static string RespondOffer(PluginConfig pc, User user, long offerId, OfferActionType action) { using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper(); if (sql != null) { string msg = ""; Offer? offer = SQLService.GetOffer(sql, offerId); if (offer != null && offer.Offeree == user.Id) { bool canProceed = false; try { sql.NewTransaction(); // 根据 action 处理状态 switch (action) { case OfferActionType.OffereeAccept: if (offer.Status == OfferState.Sent || offer.Status == OfferState.Negotiating || offer.Status == OfferState.NegotiationAccepted) { sql.UpdateOfferStatus(offerId, OfferState.Completed); sql.UpdateOfferFinishTime(offerId, DateTime.Now); canProceed = true; } else msg = "当前状态不允许接受。"; break; case OfferActionType.OffereeReject: if (offer.Status == OfferState.Sent || offer.Status == OfferState.Negotiating || offer.Status == OfferState.NegotiationAccepted) { sql.UpdateOfferStatus(offerId, OfferState.Rejected); sql.UpdateOfferFinishTime(offerId, DateTime.Now); canProceed = true; } else msg = "当前状态不允许拒绝。"; break; default: msg = "无效的操作类型。"; break; } if (canProceed) { offer = SQLService.GetOffer(sql, offerId); if (offer != null) { if (offer.Status == OfferState.Completed) { PluginConfig pc2 = new("saved", offer.Offeror.ToString()); pc2.LoadConfig(); if (pc2.Count > 0) { User user2 = GetUser(pc2); offer.OffereeItems = [.. SQLService.GetOfferItemsByOfferIdAndUserId(sql, offerId, user)]; offer.OfferorItems = [.. SQLService.GetOfferItemsByOfferIdAndUserId(sql, offerId, user2)]; PluginConfig itemsTradeRecord = new("trades", offerId.ToString()); List offerorItems = []; List offereeItems = []; foreach (Guid itemGuid in offer.OffereeItems) { if (user.Inventory.Items.FirstOrDefault(i => i.Guid == itemGuid) is Item item) { user.Inventory.Items.Remove(item); Item newItem = item.Copy(true, true); newItem.User = user2; newItem.IsSellable = false; newItem.IsTradable = false; newItem.NextSellableTime = DateTimeUtility.GetTradableTime(); newItem.NextTradableTime = DateTimeUtility.GetTradableTime(); user2.Inventory.Items.Add(newItem); offereeItems.Add(newItem); } } foreach (Guid itemGuid in offer.OfferorItems) { if (user2.Inventory.Items.FirstOrDefault(i => i.Guid == itemGuid) is Item item) { user2.Inventory.Items.Remove(item); Item newItem = item.Copy(true, true); newItem.User = user; newItem.IsSellable = false; newItem.IsTradable = false; newItem.NextSellableTime = DateTimeUtility.GetTradableTime(); newItem.NextTradableTime = DateTimeUtility.GetTradableTime(); user.Inventory.Items.Add(newItem); offerorItems.Add(newItem); } } itemsTradeRecord.Add("offeror", offerorItems); itemsTradeRecord.Add("offeree", offereeItems); itemsTradeRecord.SaveConfig(); SetUserConfigAndReleaseSemaphoreSlim(user.Id, pc, user); SetUserConfigAndReleaseSemaphoreSlim(user2.Id, pc2, user2); AddNotice(offer.Offeror, $"报价编号 {offerId} 已交易完成,请通过【查报价{offerId}】查询报价记录。"); msg = ""; } else { msg = "目标玩家不存在,请稍后再试。"; } } else if (offer.Status == OfferState.Rejected) { AddNotice(offer.Offeror, $"报价编号 {offerId} 已被拒绝,请通过【查报价{offerId}】查询报价记录。"); } sql.Commit(); } } if (msg != "") { sql.Rollback(); } else { return $"报价编号 {offerId} 已交易完成,请通过【查报价{offerId}】查询报价记录。"; } } catch { sql.Rollback(); msg = "回应报价时发生错误,请稍后再试。"; throw; } } else { msg = "报价不存在或你不是该报价的接收方。"; } return msg; } return "服务器繁忙,请稍后再试。"; } public static string CancelOffer(User user, long offerId) { using SQLHelper? sql = Factory.OpenFactory.GetSQLHelper(); if (sql != null) { string msg = ""; Offer? offer = SQLService.GetOffer(sql, offerId); if (offer != null && offer.Offeror == user.Id) { try { if (offer.Status != OfferState.Created && offer.Status != OfferState.Sent) { msg = "此报价已被处理。"; return msg; } bool result = true; sql.NewTransaction(); sql.UpdateOfferStatus(offerId, OfferState.Cancelled); if (result) { offer = SQLService.GetOffer(sql, offerId); if (offer != null) { sql.Commit(); return $"报价编号 {offerId} 已取消。"; } } else { sql.Rollback(); } } catch { sql.Rollback(); msg = "修改报价时发生错误,请稍后再试。"; throw; } } else { msg = "报价不存在或你不是该报价的发起方。"; } return msg; } return "服务器繁忙,请稍后再试。"; } public static void AddItemToUserInventory(User user, Item item, bool copyNew = true, bool copyLevel = false, bool hasLock = true, bool hasSellAndTradeTime = true, bool hasPrice = true, bool useOriginalPrice = false, double price = 0, bool toExploreCache = true, bool toActivitiesCache = true) { Item newItem = item; if (copyNew) newItem = item.Copy(copyLevel); newItem.User = user; if (hasLock && (newItem.QualityType >= QualityType.Orange || FunGameConstant.ExploreItems.Values.SelectMany(i => i).Any(c => c.Id == item.Id) || FunGameConstant.CharacterLevelBreakItems.Any(c => c.Id == item.Id) || FunGameConstant.SkillLevelUpItems.Any(c => c.Id == item.Id))) newItem.IsLock = true; if (hasSellAndTradeTime) SetSellAndTradeTime(newItem); if (hasPrice) { if (price == 0) { if (useOriginalPrice) { price = item.Price * 0.35; } else { int min = 0, max = 0; if (FunGameConstant.PriceRanges.TryGetValue(item.QualityType, out (int Min, int Max) range)) { (min, max) = (range.Min, range.Max); } price = Random.Shared.Next(min, max) * 0.35; } } newItem.Price = price; } user.Inventory.Items.Add(newItem); // 连接到任务系统 if (toExploreCache) AddExploreItemCache(user.Id, item.Name); // 连接到活动系统 if (toActivitiesCache) ActivitiesItemCache.Add(item.Name); } public static async Task FightInstance(InstanceType type, int difficulty, User user, Character[] squad) { if (difficulty <= 0) difficulty = 1; else if (difficulty > 5) difficulty = 5; StringBuilder builder = new(); // 生成敌人 int enemyCount = difficulty switch { 1 => 2, 2 => 3, 3 => 4, 4 => 5, _ => 6 }; List enemys = []; for (int i = 0; i < enemyCount; i++) { Character? enemy = FunGameConstant.Regions.SelectMany(r => r.Units).OrderBy(o => Random.Shared.Next()).FirstOrDefault(); if (enemy != null) { enemy = enemy.Copy(); int dcount = enemys.Count(e => e.Name == enemy.Name); if (dcount > 0 && FunGameConstant.GreekAlphabet.Length > dcount) enemy.Name += FunGameConstant.GreekAlphabet[dcount - 1]; enemys.Add(enemy); } } // 定义奖励 Dictionary pCharacterLevelBreak = []; Dictionary pSkillLevelUp = []; Dictionary pRegionItem = []; Dictionary rW = new() { { (int)RarityType.OneStar, 60 }, { (int)RarityType.TwoStar, 30 }, { (int)RarityType.ThreeStar, 10 }, { (int)RarityType.FourStar, 0 }, { (int)RarityType.FiveStar, 0 } }; switch (difficulty) { case 5: rW[4] = 30; rW[3] = 30; rW[2] = 15; rW[1] = 15; rW[0] = 10; break; case 4: rW[4] = 10; rW[3] = 30; rW[2] = 30; rW[1] = 15; rW[0] = 10; break; case 3: rW[4] = 0; rW[3] = 15; rW[2] = 30; rW[1] = 30; rW[0] = 25; break; case 2: rW[4] = 0; rW[3] = 5; rW[2] = 25; rW[1] = 25; rW[0] = 45; break; case 1: default: break; } double totalWeight; totalWeight = FunGameConstant.CharacterLevelBreakItems.Sum(i => rW[(int)i.QualityType]); foreach (Item item in FunGameConstant.CharacterLevelBreakItems) { if (rW.TryGetValue((int)item.QualityType, out double weight)) { pCharacterLevelBreak[item] = weight / totalWeight; } } totalWeight = FunGameConstant.SkillLevelUpItems.Sum(i => rW[(int)i.QualityType]); foreach (Item item in FunGameConstant.SkillLevelUpItems) { if (rW.TryGetValue((int)item.QualityType, out double weight)) { pSkillLevelUp[item] = weight / totalWeight; } } totalWeight = FunGameConstant.Regions.Sum(r => rW[(int)r.Difficulty]); foreach (OshimaRegion region in FunGameConstant.Regions) { if (rW.TryGetValue((int)region.Difficulty, out double weight)) { foreach (Item item in region.Crops) { pRegionItem[item] = weight / totalWeight; } } } Item[] weapons = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("11") && (int)i.QualityType == 5)]; Item[] armors = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("12") && (int)i.QualityType == 5)]; Item[] shoes = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("13") && (int)i.QualityType == 5)]; Item[] accessory = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("14") && (int)i.QualityType == 5)]; Item[] consumables = [.. FunGameConstant.AllItems.Where(i => i.ItemType == ItemType.Consumable && i.IsInGameItem)]; int cLevel = difficulty * 8; int sLevel = difficulty; int mLevel = difficulty + 1; int naLevel = mLevel; foreach (Character enemy_loop in enemys) { EnhanceBoss(enemy_loop, weapons, armors, shoes, accessory, consumables, cLevel, sLevel, mLevel, naLevel, false, false, true); } // 开始战斗 Team team1 = new($"{user.Username}的小队", squad); string team2Name = type switch { InstanceType.Currency => General.GameplayEquilibriumConstant.InGameCurrency, InstanceType.Material => General.GameplayEquilibriumConstant.InGameMaterial, InstanceType.EXP => "经验值/经验书", InstanceType.RegionItem => "地区锻造材料", InstanceType.CharacterLevelBreak => "角色等阶突破材料", InstanceType.SkillLevelUp => "技能等级升级材料", _ => "" } + "秘境"; Team team2 = new(team2Name, enemys); FunGameActionQueue actionQueue = new(); List msgs = await actionQueue.StartTeamGame([team1, team2], showAllRound: true); if (msgs.Count > 2) { msgs = msgs[^2..]; } int award = 0; int characterCount = squad.Length; builder.AppendLine($"☆--- {team2.Name}挑战 ---☆"); builder.AppendLine(string.Join("\r\n", msgs)); if (enemys.All(c => c.HP <= 0)) { builder.Append($"小队战胜了敌人!获得了:"); switch (type) { case InstanceType.Currency: for (int i = 0; i < characterCount; i++) { award += Random.Shared.Next(550, 1050) * difficulty; } user.Inventory.Credits += award; // 这个只是展示,实际上在战斗过程中已经加过了 if (actionQueue.GamingQueue.EarnedMoney.Count > 0) { award += actionQueue.GamingQueue.EarnedMoney.Where(kv => squad.Contains(kv.Key)).Sum(kv => kv.Value); } builder.AppendLine($"{award} {General.GameplayEquilibriumConstant.InGameCurrency}(包含战斗中击杀奖励)!"); break; case InstanceType.Material: for (int i = 0; i < characterCount; i++) { award += Random.Shared.Next(3, 7) * difficulty; } user.Inventory.Materials += award; builder.AppendLine($"{award} {General.GameplayEquilibriumConstant.InGameMaterial}!"); break; case InstanceType.EXP: for (int i = 0; i < characterCount; i++) { award += Random.Shared.Next(570, 1260) * difficulty; } double overflowExp = 0; double avgExp = award / characterCount; int small = 0, medium = 0, large = 0; award = 0; foreach (Character character in squad) { double currentExp = FunGameConstant.PrecomputeTotalExperience[character.Level] + character.EXP; if (currentExp + avgExp > FunGameConstant.PrecomputeTotalExperience[General.GameplayEquilibriumConstant.MaxLevel]) { overflowExp = Math.Min(FunGameConstant.PrecomputeTotalExperience[General.GameplayEquilibriumConstant.MaxLevel], currentExp) + avgExp - FunGameConstant.PrecomputeTotalExperience[General.GameplayEquilibriumConstant.MaxLevel]; while (overflowExp > 0) { if (overflowExp >= 1000) { large++; overflowExp -= 1000; } else if (overflowExp >= 500) { medium++; overflowExp -= 500; } else if (overflowExp >= 200) { small++; overflowExp -= 200; } else { small++; overflowExp = 0; } } } else { character.EXP += avgExp; award += (int)avgExp; } } List expBook = []; if (large > 0) { expBook.Add($"{large} 个大经验书"); for (int i = 0; i < large; i++) { AddItemToUserInventory(user, new 大经验书()); } } if (medium > 0) { expBook.Add($"{medium} 个中经验书"); for (int i = 0; i < medium; i++) { AddItemToUserInventory(user, new 中经验书()); } } if (small > 0) { expBook.Add($"{small} 个小经验书"); for (int i = 0; i < small; i++) { AddItemToUserInventory(user, new 小经验书()); } } builder.AppendLine($"{award} 点经验值(分配给经验未满的角色们){(expBook.Count > 0 ? $",附赠:{string.Join("、", expBook)}" : "")}!"); break; case InstanceType.RegionItem: List regionItems = []; for (int i = 0; i < characterCount; i++) { double roll = Random.Shared.NextDouble(); double cumulativeProbability = 0.0; Item? item = null; OshimaRegion? region = null; foreach (Item loop in pRegionItem.Keys) { cumulativeProbability += pRegionItem[loop]; // 如果随机数落在当前物品的累积概率范围内,则选中该物品 if (roll < cumulativeProbability) { item = loop; region = FunGameConstant.Regions.FirstOrDefault(r => r.Crops.Any(i => i.Id == item.Id)); break; } } region ??= FunGameConstant.Regions[Random.Shared.Next(FunGameConstant.Regions.Count)]; item ??= region.Crops.ToList()[Random.Shared.Next(region.Crops.Count)]; award = Math.Max(1, Random.Shared.Next(1, 4) * difficulty / 2); regionItems.Add($"{award} 个{item.Name}(来自{region.Name})"); for (int j = 0; j < award; j++) { AddItemToUserInventory(user, item); } } builder.AppendLine($"{string.Join("、", regionItems)}!"); break; case InstanceType.CharacterLevelBreak: List characterLevelBreakItems = []; for (int i = 0; i < characterCount; i++) { double roll = Random.Shared.NextDouble(); double cumulativeProbability = 0.0; Item? item = null; foreach (Item loop in pCharacterLevelBreak.Keys) { cumulativeProbability += pCharacterLevelBreak[loop]; // 如果随机数落在当前物品的累积概率范围内,则选中该物品 if (roll < cumulativeProbability) { item = loop; break; } } item ??= FunGameConstant.CharacterLevelBreakItems[Random.Shared.Next(FunGameConstant.CharacterLevelBreakItems.Count)]; award = Math.Max(1, Random.Shared.Next(1, 4) * difficulty / Math.Max(2, (int)item.QualityType + 1)); characterLevelBreakItems.Add($"{award} 个{item.Name}"); for (int j = 0; j < award; j++) { AddItemToUserInventory(user, item); } } builder.AppendLine($"{string.Join("、", characterLevelBreakItems)}!"); break; case InstanceType.SkillLevelUp: List skillLevelUpItems = []; for (int i = 0; i < characterCount; i++) { double roll = Random.Shared.NextDouble(); double cumulativeProbability = 0.0; Item? item = null; foreach (Item loop in pSkillLevelUp.Keys) { cumulativeProbability += pSkillLevelUp[loop]; // 如果随机数落在当前物品的累积概率范围内,则选中该物品 if (roll < cumulativeProbability) { item = loop; break; } } item ??= FunGameConstant.SkillLevelUpItems[Random.Shared.Next(FunGameConstant.SkillLevelUpItems.Count)]; award = Math.Max(1, Random.Shared.Next(1, 4) * difficulty / Math.Max(2, (int)item.QualityType + 1)); skillLevelUpItems.Add($"{award} 个{item.Name}"); for (int j = 0; j < award; j++) { AddItemToUserInventory(user, item); } } builder.AppendLine($"{string.Join("、", skillLevelUpItems)}!"); break; default: break; } } else { builder.Append($"小队未能战胜敌人,"); IEnumerable deadEnemys = enemys.Where(c => c.HP <= 0); if (!deadEnemys.Any()) { builder.AppendLine("无法获取秘境奖励!"); } else { builder.Append("但是获得了战斗失败补偿:"); // 根据死亡敌人的数量生成补偿奖励 int count = deadEnemys.Count(); switch (type) { case InstanceType.Currency: award = 100 * difficulty * count; user.Inventory.Credits += award; // 这个只是展示,实际上在战斗过程中已经加过了 if (actionQueue.GamingQueue.EarnedMoney.Count > 0) { award += actionQueue.GamingQueue.EarnedMoney.Where(kv => squad.Contains(kv.Key)).Sum(kv => kv.Value); } builder.AppendLine($"{award} {General.GameplayEquilibriumConstant.InGameCurrency}(包含战斗中击杀奖励)!"); break; case InstanceType.Material: award = (int)(0.5 * difficulty * count); if (award <= 0) award = 1; user.Inventory.Materials += award; builder.AppendLine($"{award} {General.GameplayEquilibriumConstant.InGameMaterial}!"); break; case InstanceType.EXP: award = 300 * difficulty * count; double overflowExp = 0; double avgExp = (award / characterCount); int small = 0, medium = 0, large = 0; award = 0; foreach (Character character in squad) { double currentExp = FunGameConstant.PrecomputeTotalExperience[character.Level] + character.EXP; if (currentExp + avgExp > FunGameConstant.PrecomputeTotalExperience[General.GameplayEquilibriumConstant.MaxLevel]) { overflowExp = Math.Min(FunGameConstant.PrecomputeTotalExperience[General.GameplayEquilibriumConstant.MaxLevel], currentExp) + avgExp - FunGameConstant.PrecomputeTotalExperience[General.GameplayEquilibriumConstant.MaxLevel]; while (overflowExp > 0) { if (overflowExp >= 1000) { large++; overflowExp -= 1000; } else if (overflowExp >= 500) { medium++; overflowExp -= 500; } else if (overflowExp >= 200) { small++; overflowExp -= 200; } else { small++; overflowExp = 0; } } } else { character.EXP += avgExp; award += (int)avgExp; } } List expBook = []; if (large > 0) { expBook.Add($"{large} 个大经验书"); for (int i = 0; i < large; i++) { AddItemToUserInventory(user, new 大经验书()); } } if (medium > 0) { expBook.Add($"{medium} 个中经验书"); for (int i = 0; i < medium; i++) { AddItemToUserInventory(user, new 中经验书()); } } if (small > 0) { expBook.Add($"{small} 个小经验书"); for (int i = 0; i < small; i++) { AddItemToUserInventory(user, new 小经验书()); } } builder.AppendLine($"{award} 点经验值(分配给经验未满的角色们){(expBook.Count > 0 ? $",附赠:{string.Join("、", expBook)}" : "")}!"); break; case InstanceType.RegionItem: List regionItems = []; for (int i = 0; i < count; i++) { double roll = Random.Shared.NextDouble(); double cumulativeProbability = 0.0; Item? item = null; OshimaRegion? region = null; foreach (Item loop in pRegionItem.Keys) { cumulativeProbability += pRegionItem[loop]; // 如果随机数落在当前物品的累积概率范围内,则选中该物品 if (roll < cumulativeProbability) { item = loop; region = FunGameConstant.Regions.FirstOrDefault(r => r.Crops.Any(i => i.Id == item.Id)); break; } } region ??= FunGameConstant.Regions[Random.Shared.Next(FunGameConstant.Regions.Count)]; item ??= region.Crops.ToList()[Random.Shared.Next(region.Crops.Count)]; award = 1; regionItems.Add($"{award} 个{item.Name}(来自{region.Name})"); for (int j = 0; j < award; j++) { AddItemToUserInventory(user, item); } } builder.AppendLine($"{string.Join("、", regionItems)}!"); break; case InstanceType.CharacterLevelBreak: List characterLevelBreakItems = []; for (int i = 0; i < count; i++) { double roll = Random.Shared.NextDouble(); double cumulativeProbability = 0.0; Item? item = null; foreach (Item loop in pCharacterLevelBreak.Keys) { cumulativeProbability += pCharacterLevelBreak[loop]; // 如果随机数落在当前物品的累积概率范围内,则选中该物品 if (roll < cumulativeProbability) { item = loop; break; } } item ??= FunGameConstant.CharacterLevelBreakItems[Random.Shared.Next(FunGameConstant.CharacterLevelBreakItems.Count)]; award = 1; characterLevelBreakItems.Add($"{award} 个{item.Name}"); for (int j = 0; j < award; j++) { AddItemToUserInventory(user, item); } } builder.AppendLine($"{string.Join("、", characterLevelBreakItems)}!"); break; case InstanceType.SkillLevelUp: List skillLevelUpItems = []; for (int i = 0; i < count; i++) { double roll = Random.Shared.NextDouble(); double cumulativeProbability = 0.0; Item? item = null; foreach (Item loop in pSkillLevelUp.Keys) { cumulativeProbability += pSkillLevelUp[loop]; // 如果随机数落在当前物品的累积概率范围内,则选中该物品 if (roll < cumulativeProbability) { item = loop; break; } } item ??= FunGameConstant.SkillLevelUpItems[Random.Shared.Next(FunGameConstant.SkillLevelUpItems.Count)]; award = 1; skillLevelUpItems.Add($"{award} 个{item.Name}"); for (int j = 0; j < award; j++) { AddItemToUserInventory(user, item); } } builder.AppendLine($"{string.Join("、", skillLevelUpItems)}!"); break; default: break; } } } return builder.ToString().Trim(); } public static Store? GetRegionStore(EntityModuleConfig stores, User user, string storeRegion, string storeName) { Store? store = null; Dictionary regionStores = FunGameConstant.PlayerRegions.ToDictionary(r => r.Name, r => r); if (regionStores.TryGetValue(storeRegion, out OshimaRegion? value) && value != null) { store = value.VisitStore(stores, user, storeName); } return store; } public static void SaveRegionStore(Store store, string storeRegion, string storeName) { if (FunGameConstant.PlayerRegions.FirstOrDefault(r => r.Name == storeRegion) is OshimaRegion value) { value.SaveGlobalStore(store, storeName); } } public static string CheckRegionStore(EntityModuleConfig stores, PluginConfig pc, User user, string storeRegion, string storeName, out bool exist) { string msg = ""; exist = false; Dictionary regionStores = FunGameConstant.PlayerRegions.ToDictionary(r => r.Name, r => r); if (regionStores.TryGetValue(storeRegion, out OshimaRegion? value) && value != null) { Store? store = value.VisitStore(stores, user, storeName); exist = store != null; msg = store?.ToString(user) ?? ""; if (exist && msg != "") { string currencyInfo = $"☆--- {user.Inventory.Name} ---☆\r\n现有{General.GameplayEquilibriumConstant.InGameCurrency}:{user.Inventory.Credits:0.##}\r\n现有{General.GameplayEquilibriumConstant.InGameMaterial}:{user.Inventory.Materials:0.##}"; string regionCurrency = value.GetCurrencyInfo(pc, user, storeName); if (regionCurrency.Trim() != "") { currencyInfo += $"\r\n{regionCurrency}"; } msg += "\r\n" + currencyInfo; } } if (!exist) { msg = "探索者协会专员为你跑遍了全大陆,也没有找到这个商店。"; } else { SetLastStore(user, false, storeRegion, storeName); } return msg; } public static void GenerateForgeResult(User user, ForgeModel model, bool simulate = false) { if (model.ForgeMaterials.Count == 0) { model.ResultString = "没有提交任何锻造材料,请重新提交。"; return; } Dictionary regionMaterialCount = []; Dictionary regionMaterialEquivalent = []; Dictionary regionContributions = []; foreach (string key in model.ForgeMaterials.Keys) { int c = model.ForgeMaterials[key]; OshimaRegion r = FunGameConstant.ExploreItems.FirstOrDefault(kv => kv.Value.Select(i => i.Name).Any(s => s == key)).Key; if (r.Id == 0) continue; if (!regionMaterialCount.TryAdd(r, c)) regionMaterialCount[r] += c; double ce = c * FunGameConstant.ForgeRegionCoefficient[r.Difficulty]; if (!regionMaterialEquivalent.TryAdd(key, ce)) regionMaterialEquivalent[key] += ce; if (!regionContributions.TryAdd(r, ce)) regionContributions[r] += ce; } if (regionMaterialCount.Count == 0) { model.ResultString = "提交的锻造材料均不属于任何地区,请重新提交。"; return; } OshimaRegion resultRegion; int count = 0; bool isSimplyForge = regionMaterialCount.Count == 1; if (isSimplyForge) { OshimaRegion region = regionMaterialCount.Keys.First(); count = regionMaterialCount[region]; if (count < FunGameConstant.ForgeNeedy[QualityType.White]) { model.ResultString = $"提交的锻造材料不足 {FunGameConstant.ForgeNeedy[QualityType.White]} 个,请重新提交。"; return; } model.RegionProbabilities = regionMaterialCount.ToDictionary(kv => kv.Key.Id, kv => (double)kv.Value / count); resultRegion = regionMaterialCount.Keys.First(); } else { count = (int)regionMaterialEquivalent.Values.Sum(); if (count < FunGameConstant.ForgeNeedy[QualityType.White]) { model.ResultString = $"有效材料用量 ({count}) 不足最低要求 ({FunGameConstant.ForgeNeedy[QualityType.White]}),请重新提交!"; return; } model.RegionProbabilities = regionContributions.ToDictionary(kv => kv.Key.Id, kv => kv.Value / count); double randomValue = Random.Shared.NextDouble(); double cumulative = 0; resultRegion = regionContributions.Keys.First(); foreach (OshimaRegion r in regionContributions.Keys) { cumulative += regionContributions[r] / count; if (randomValue <= cumulative) { resultRegion = r; break; } } } model.ResultRegion = resultRegion.Id; if (count >= FunGameConstant.ForgeNeedy[QualityType.Red]) { model.ResultQuality = QualityType.Red; } else if (count >= FunGameConstant.ForgeNeedy[QualityType.Orange]) { model.ResultQuality = QualityType.Orange; } else if (count >= FunGameConstant.ForgeNeedy[QualityType.Purple]) { model.ResultQuality = QualityType.Purple; } else if (count >= FunGameConstant.ForgeNeedy[QualityType.Blue]) { model.ResultQuality = QualityType.Blue; } else { model.ResultQuality = QualityType.White; } model.ResultPointsGeneral = count * 0.3; string resultItemString = ""; Item? resultItem = resultRegion.Items.OrderBy(o => Random.Shared.Next()).FirstOrDefault(i => i.QualityType == model.ResultQuality); if (resultItem != null) { string itemquality = ItemSet.GetQualityTypeName(resultItem.QualityType); string itemtype = ItemSet.GetItemTypeName(resultItem.ItemType) + (resultItem.ItemType == ItemType.Weapon && resultItem.WeaponType != WeaponType.None ? "-" + ItemSet.GetWeaponTypeName(resultItem.WeaponType) : ""); if (itemtype != "") itemtype = $"|{itemtype}"; resultItemString = $"[{itemquality}{itemtype}]{resultItem.Name}"; model.ResultItem = resultItem.Name; } if (isSimplyForge) { if (resultItem is null) { model.ResultPointsFail = count * 0.2; model.ResultString = $"锻造失败!本次锻造物品的品质为:{ItemSet.GetQualityTypeName(model.ResultQuality)},地区为:{resultRegion.Name},该地区不存在该品质的物品!\r\n" + $"本次提交 {count} 个地区 [ {resultRegion.Name} ] 的锻造材料,获得 {model.ResultPoints:0.##} 点锻造积分。"; } else { model.Result = true; model.ResultPointsSuccess = count - FunGameConstant.ForgeNeedy[model.ResultQuality]; model.ResultString = $"锻造成功!本次锻造物品的品质为:{ItemSet.GetQualityTypeName(model.ResultQuality)},地区为:{resultRegion.Name},获得了:{resultItemString}!\r\n" + $"本次提交 {count} 个地区 [ {resultRegion.Name} ] 的锻造材料,获得 {model.ResultPoints:0.##} 点锻造积分。"; if (!simulate) { AddItemToUserInventory(user, resultItem); } } } else { if (resultItem is null) { model.ResultPointsFail = count * 0.2; model.ResultString = $"锻造失败!本次锻造物品的品质为:{ItemSet.GetQualityTypeName(model.ResultQuality)},地区为:{resultRegion.Name},该地区不存在该品质的物品!\r\n" + $"本次提交 {regionContributions.Count} 个地区的锻造材料({string.Join("、", regionMaterialCount.Select(kv => $"{kv.Value} 个来自{kv.Key.Name}"))}),总共 {count} 有效材料用量,获得 {model.ResultPoints:0.##} 点锻造积分。"; } else { model.Result = true; model.ResultPointsSuccess = count - FunGameConstant.ForgeNeedy[model.ResultQuality]; model.ResultString = $"锻造成功!本次锻造物品的品质为:{ItemSet.GetQualityTypeName(model.ResultQuality)},地区为:{resultRegion.Name},获得了:{resultItemString}!\r\n" + $"本次提交 {regionContributions.Count} 个地区的锻造材料({string.Join("、", regionMaterialCount.Select(kv => $"{kv.Value} 个来自{kv.Key.Name}"))}),总共 {count} 有效材料用量,获得 {model.ResultPoints:0.##} 点锻造积分。"; if (!simulate) { AddItemToUserInventory(user, resultItem); } } } if (model.MasterForge) { if (model.Result && model.TargetRegionId == resultRegion.Id && model.TargetQuality == model.ResultQuality) { model.ResultString += "\r\n大师锻造券正在时刻为你护航。"; } else if (user.Inventory.Items.FirstOrDefault(i => i.Name == "大师锻造券") is Item item) { model.MasterForgingSuccess = true; model.ResultString += "\r\n发动了大师锻造券的效果!为你返还了所有的锻造材料!"; user.Inventory.Items.Remove(item); } else { model.ResultString += "\r\n你似乎没有大师锻造券,因此本次锻造一切如常。"; } } if (simulate) { model.ResultString += $"\r\n\r\n☆--- 模拟调试信息 ---☆\r\n本次锻造的出货地区概率:\r\n" + $"{string.Join("\r\n", model.RegionProbabilities.Select(kv => $"{kv.Key}. {FunGameConstant.RegionsName[kv.Key]}:{kv.Value * 100:0.##}%({CharacterSet.GetRarityTypeName(FunGameConstant.RegionsDifficulty[kv.Key])})"))}\r\n" + $"有效材料用量贡献:" + (isSimplyForge ? $"单一锻造模式\r\n{string.Join("\r\n", model.ForgeMaterials.Select(kv => $"{kv.Key}:{kv.Value} 个"))}" : $"混合锻造模式\r\n{string.Join("\r\n", regionMaterialEquivalent.Select(kv => $"{kv.Key}:{kv.Value:0.##} 有效材料用量"))}") + "\r\n" + $"出货品质:{ItemSet.GetQualityTypeName(model.ResultQuality)}\r\n所需有效材料用量:{FunGameConstant.ForgeNeedy[model.ResultQuality]}\r\n总计有效材料用量:{count}\r\n" + $"基础锻造积分:{count * 0.3:0.##} 点\r\n失败积分补偿:{count * 0.2:0.##} 点\r\n超量积分补偿:{count - FunGameConstant.ForgeNeedy[model.ResultQuality]:0.##} 点"; } } public static string GetMarketInfo(Market market, User? user = null, int page = 1, bool simply = false, bool showListed = true) { if (page <= 0) page = 1; int maxPage = market.MarketItems.Values.MaxPage(10); if (page > maxPage) page = maxPage; IEnumerable marketItems = market.MarketItems.Values.GetPage(page, 10); StringBuilder builder = new(); builder.AppendLine($"☆★☆ {market.Name} ☆★☆"); if (market.Description != "") builder.AppendLine($"{market.Description}"); if (market.StartTime.HasValue && market.EndTime.HasValue) { builder.AppendLine($"开放时间:{market.StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)} 至 {market.EndTime.Value.ToString(General.GeneralDateTimeFormatChinese)}"); } else if (market.StartTime.HasValue && !market.EndTime.HasValue) { builder.AppendLine($"开始开放时间:{market.StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)}"); } else if (!market.StartTime.HasValue && market.EndTime.HasValue) { builder.AppendLine($"停止开放时间:{market.EndTime.Value.ToString(General.GeneralDateTimeFormatChinese)}"); } else { builder.AppendLine($"开放时间:全年无休,永久开放"); } if (market.StartTimeOfDay.HasValue && market.EndTimeOfDay.HasValue) { builder.AppendLine($"每日交易时间:{market.StartTimeOfDay.Value.ToString(General.GeneralDateTimeFormatTimeOnly)} 至 {market.EndTimeOfDay.Value.ToString(General.GeneralDateTimeFormatTimeOnly)}"); } else { builder.AppendLine($"[ 24H ] 全天开放交易"); } DateTime now = DateTime.Now; TimeSpan nowTimeOfDay = now.TimeOfDay; bool isStoreOpen = true; if (market.StartTime.HasValue && market.StartTime.Value > now || market.EndTime.HasValue && market.EndTime.Value < now) { isStoreOpen = false; } if (isStoreOpen && market.StartTimeOfDay.HasValue && market.EndTimeOfDay.HasValue) { TimeSpan startTimeSpan = market.StartTimeOfDay.Value.TimeOfDay; TimeSpan endTimeSpan = market.EndTimeOfDay.Value.TimeOfDay; if (startTimeSpan <= endTimeSpan) { isStoreOpen = nowTimeOfDay >= startTimeSpan && nowTimeOfDay <= endTimeSpan; } else { isStoreOpen = nowTimeOfDay >= startTimeSpan || nowTimeOfDay <= endTimeSpan; } } if (!isStoreOpen) { builder.AppendLine($"市场现在不在交易时间内。"); } builder.AppendLine($"☆--- 市场商品列表 ---☆"); MarketItem[] MarketItemsValid = [.. market.MarketItems.Values]; if (showListed) MarketItemsValid = [.. MarketItemsValid.Where(g => g.Status == MarketItemState.Listed)]; if (MarketItemsValid.Length == 0) { builder.AppendLine("当前没有商品可供购买,过一段时间再来吧。"); } else { foreach (MarketItem marketItem in MarketItemsValid) { builder.AppendLine(GetMarketItemInfo(marketItem, true, user?.Id ?? 0)); } builder.AppendLine("提示:使用【市场查看+序号】查看商品详细信息,使用【市场购买+序号】购买商品。"); } if (user != null) { builder.AppendLine($"你的现有{General.GameplayEquilibriumConstant.InGameCurrency}:{user.Inventory.Credits:0.##}"); } builder.AppendLine($"页数:{page} / {maxPage},使用【市场+页码】快速跳转指定页面。"); return builder.ToString().Trim(); } public static string GetMarketItemInfo(MarketItem item, bool simply, long visitUser) { StringBuilder builder = new(); if (simply) { builder.AppendLine($"{item.Id}. [{ItemSet.GetQualityTypeName(item.Item.QualityType)}|{ItemSet.GetItemTypeName(item.Item.ItemType)}] {item.Name}"); string username = item.Username; if (FunGameConstant.UserIdAndUsername.TryGetValue(item.User, out User? user) && user != null) { username = user.Username; } builder.AppendLine($"卖家:{username}"); builder.AppendLine($"商品描述:{item.Item.Description}"); builder.AppendLine($"商品售价:{(item.Price > 0 ? item.Price : "免费")} {General.GameplayEquilibriumConstant.InGameCurrency}"); if (item.Status == MarketItemState.Purchased) { builder.AppendLine($"商品已售罄"); } else if (item.Status == MarketItemState.Delisted) { builder.AppendLine($"商品已下架"); } else builder.AppendLine($"剩余库存:{(item.Stock == -1 ? "不限" : item.Stock)}"); } else { builder.AppendLine($"{item.Id}. {item.Name}"); string username = item.Username; if (FunGameConstant.UserIdAndUsername.TryGetValue(item.User, out User? user) && user != null) { username = user.Username; } builder.AppendLine($"卖家:{username}"); builder.AppendLine($"上架时间:{item.CreateTime.ToString(General.GeneralDateTimeFormatChinese)}"); builder.AppendLine($"商品售价:{(item.Price > 0 ? item.Price : "免费")} {General.GameplayEquilibriumConstant.InGameCurrency}"); if (item.Status == MarketItemState.Purchased) { builder.AppendLine($"商品已售罄"); if (item.FinishTime.HasValue) builder.AppendLine($"售罄时间:{item.FinishTime.Value.ToString(General.GeneralDateTimeFormatChinese)}"); if (visitUser == item.User && item.Buyers.Count > 0) { HashSet buyers = []; foreach (long buyerid in item.Buyers) { username = "Unknown"; if (FunGameConstant.UserIdAndUsername.TryGetValue(buyerid, out User? buyer) && buyer != null) { username = buyer.Username; } buyers.Add(username); } builder.AppendLine($"买家:{string.Join(",", buyers)}"); } } else if (item.Status == MarketItemState.Delisted) { builder.AppendLine($"商品已下架"); if (item.FinishTime.HasValue) builder.AppendLine($"下架时间:{item.FinishTime.Value.ToString(General.GeneralDateTimeFormatChinese)}"); } else builder.AppendLine($"剩余库存:{(item.Stock == -1 ? "不限" : item.Stock)}"); builder.AppendLine($"☆--- 物品信息 ---☆\r\n{item.Item}"); } return builder.ToString().Trim(); } public static void RefreshNotice() { Notices.LoadConfig(); } public static void RefreshSavedCache() { string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/saved"; if (Directory.Exists(directoryPath)) { string[] filePaths = Directory.GetFiles(directoryPath); foreach (string filePath in filePaths) { string fileName = Path.GetFileNameWithoutExtension(filePath); PluginConfig pc = GetUserConfig(fileName, out _); if (pc.Count > 0) { User user = GetUser(pc); // 将用户存入缓存 FunGameConstant.UserIdAndUsername[user.Id] = user; bool updateQuest = false; bool updateExplore = false; // 任务结算 EntityModuleConfig quests = new("quests", user.Id.ToString()); quests.LoadConfig(); if (quests.Count > 0 && SettleQuest(user, quests)) { quests.SaveConfig(); updateQuest = true; } // 探索结算 PluginConfig pc2 = new("exploring", user.Id.ToString()); pc2.LoadConfig(); if (pc2.Count > 0 && SettleExploreAll(pc2, user)) { pc2.SaveConfig(); updateExplore = true; } if (updateQuest || updateExplore) { SetUserConfigButNotRelease(user.Id, pc, user); } if (FunGameConstant.UserLastVisitStore.TryGetValue(user.Id, out LastStoreModel? value) && value != null && (DateTime.Now - value.LastTime).TotalMinutes > 2) { FunGameConstant.UserLastVisitStore.Remove(user.Id); } } ReleaseUserSemaphoreSlim(fileName); } } } public static void RefreshDailyQuest() { string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/quests"; if (Directory.Exists(directoryPath)) { string[] filePaths = Directory.GetFiles(directoryPath); foreach (string filePath in filePaths) { string fileName = Path.GetFileNameWithoutExtension(filePath); EntityModuleConfig quests = new("quests", fileName); quests.Clear(); CheckQuestList(quests); quests.SaveConfig(); } } } public static void RefreshDailySignIn() { // 刷新每天登录 UserNotice.Clear(); // 刷新签到 string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/saved"; if (Directory.Exists(directoryPath)) { string[] filePaths = Directory.GetFiles(directoryPath); foreach (string filePath in filePaths) { string fileName = Path.GetFileNameWithoutExtension(filePath); PluginConfig pc = GetUserConfig(fileName, out _); pc.Add("signed", false); pc.Add("logon", false); pc.Add("lunch", false); pc.Add("dinner", false); pc.Add("exploreTimes", FunGameConstant.MaxExploreTimes); pc.SaveConfig(); ReleaseUserSemaphoreSlim(fileName); } } } public static void RefreshStoreData() { // 刷新商店 string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/stores"; if (Directory.Exists(directoryPath)) { string[] filePaths = Directory.GetFiles(directoryPath); foreach (string filePath in filePaths) { string fileName = Path.GetFileNameWithoutExtension(filePath); EntityModuleConfig stores = new("stores", fileName); stores.LoadConfig(); string[] storeNames = [.. stores.Keys]; if (long.TryParse(fileName, out long userId) && FunGameConstant.UserIdAndUsername.TryGetValue(userId, out User? user) && user != null) { // 更新玩家商店数据,移除所有当天刷新的商店 FunGameConstant.UserLastVisitStore.Remove(userId); stores.Remove("daily"); foreach (string key in storeNames) { Store? store = stores.Get(key); if (store != null && (store.GlobalStock || (store.AutoRefresh && store.NextRefreshDate.Date <= DateTime.Today))) { stores.Remove(key); } } CheckDailyStore(stores, user); } else { // 非玩家商店数据,需要更新模板的商品 foreach (string key in storeNames) { Store? store = stores.Get(key); if (store != null) { if (store.ExpireTime != null && store.ExpireTime.Value.Date <= DateTime.Today) { continue; } if (store.AutoRefresh && store.NextRefreshDate.Date <= DateTime.Today) { store.Goods.Clear(); foreach (long goodsId in store.NextRefreshGoods.Keys) { store.Goods[goodsId] = store.NextRefreshGoods[goodsId]; } store.NextRefreshDate = DateTime.Today.AddHours(4).AddDays(store.RefreshInterval); } stores.Add(key, store); } } } stores.SaveConfig(); } } } public static void RefreshMarketData() { // 刷新市场 GetMarketSemaphoreSlim(); string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/markets"; if (Directory.Exists(directoryPath)) { DateTime now = DateTime.Now; string[] filePaths = Directory.GetFiles(directoryPath); foreach (string filePath in filePaths) { string fileName = Path.GetFileNameWithoutExtension(filePath); EntityModuleConfig markets = new("markets", fileName); markets.LoadConfig(); string[] marketNames = [.. markets.Keys]; foreach (string key in marketNames) { Market? market = markets.Get(key); if (market != null) { long[] items = [.. market.MarketItems.Keys]; foreach (long id in items) { MarketItem item = market.MarketItems[id]; if ((item.Status == MarketItemState.Delisted || item.Status == MarketItemState.Purchased) && item.FinishTime.HasValue && (now - item.FinishTime.Value).TotalDays >= 3) { market.MarketItems.Remove(id); } } markets.Add(key, market); } } markets.SaveConfig(); } } ReleaseMarketSemaphoreSlim(); } public static void PreRefreshStore() { foreach (OshimaRegion region in FunGameConstant.PlayerRegions) { region.UpdateNextRefreshGoods(); } } public static void OnUserConfigSaving(PluginConfig pc, User user) { DateTime now = DateTime.Now; if (!pc.TryGetValue("logon", out object? value) || (value is bool logon && !logon)) { pc.Add("logon", true); AddNotice(user.Id, "欢迎回到筽祀牻大陆!请发送【帮助】获取更多玩法指令哦~"); AddNotice(user.Id, GetEvents()); foreach (NoticeModel notice in Notices.Values) { if (now >= notice.StartTime && now <= notice.EndTime) { AddNotice(user.Id, notice.ToString()); } } } int count1 = 30; int count2 = 30; DateTime d1 = DateTime.Today.AddHours(11); DateTime d2 = DateTime.Today.AddHours(13).AddMinutes(59); DateTime d3 = DateTime.Today.AddHours(17); DateTime d4 = DateTime.Today.AddHours(19).AddMinutes(59); if (now >= d1 && now <= d2 && (!pc.TryGetValue("lunch", out value) || (value is bool lunch && !lunch))) { int exploreTimes = FunGameConstant.MaxExploreTimes + count1; if (pc.TryGetValue("exploreTimes", out object? value2) && int.TryParse(value2.ToString(), out exploreTimes)) { exploreTimes += count1; } pc.Add("exploreTimes", exploreTimes); pc.Add("lunch", true); AddNotice(user.Id, $"在 11-13 点期间登录游戏获得了午餐!(探索许可+{count1}~)"); } if (now >= d3 && now <= d4 && (!pc.TryGetValue("dinner", out value) || (value is bool dinner && !dinner))) { int exploreTimes = FunGameConstant.MaxExploreTimes + count2; if (pc.TryGetValue("exploreTimes", out object? value2) && int.TryParse(value2.ToString(), out exploreTimes)) { exploreTimes += count2; } pc.Add("exploreTimes", exploreTimes); pc.Add("dinner", true); AddNotice(user.Id, $"在 17-19 点期间登录游戏获得了晚餐!(探索许可+{count2}~)"); } } public static void ReleaseUserSemaphoreSlim(string key) { if (FunGameConstant.UserSemaphoreSlims.TryGetValue(key, out SemaphoreSlim? obj) && obj != null && obj.CurrentCount == 0) { obj.Release(); } } public static void ReleaseUserSemaphoreSlim(long uid) => ReleaseUserSemaphoreSlim(uid.ToString()); public static void SetUserConfig(string key, PluginConfig pc, User user, bool updateLastTime = true, bool release = true) { OnUserConfigSaving(pc, user); if (updateLastTime) user.LastTime = DateTime.Now; pc.Add("user", user); pc.SaveConfig(); if (release && FunGameConstant.UserSemaphoreSlims.TryGetValue(key, out SemaphoreSlim? obj) && obj != null && obj.CurrentCount == 0) { obj.Release(); } } public static void SetUserConfigAndReleaseSemaphoreSlim(long uid, PluginConfig pc, User user, bool updateLastTime = true) => SetUserConfig(uid.ToString(), pc, user, updateLastTime); public static void SetUserConfigButNotRelease(long uid, PluginConfig pc, User user, bool updateLastTime = true) => SetUserConfig(uid.ToString(), pc, user, updateLastTime, false); public static PluginConfig GetUserConfig(string key, out bool isTimeout) { isTimeout = false; try { SemaphoreSlim obj = FunGameConstant.UserSemaphoreSlims.GetOrAdd(key, _ => new SemaphoreSlim(1, 1)); obj.Wait(FunGameConstant.SemaphoreSlimTimeout); PluginConfig pc = new("saved", key); pc.LoadConfig(); return pc; } catch { isTimeout = true; return new("saved", "0"); } } public static PluginConfig GetUserConfig(long uid, out bool isTimeout) => GetUserConfig(uid.ToString(), out isTimeout); public static bool CheckSemaphoreSlim(string key) { if (FunGameConstant.UserSemaphoreSlims.TryGetValue(key, out SemaphoreSlim? obj) && obj != null) { return obj.CurrentCount == 0; } return false; } public static bool CheckSemaphoreSlim(long uid) => CheckSemaphoreSlim(uid.ToString()); public static void GetMarketSemaphoreSlim() { FunGameConstant.MarketSemaphoreSlim.Wait(FunGameConstant.SemaphoreSlimTimeout); } public static void ReleaseMarketSemaphoreSlim() { if (FunGameConstant.MarketSemaphoreSlim.CurrentCount == 0) { FunGameConstant.MarketSemaphoreSlim.Release(); } } } }