diff --git a/OshimaModules/Items/GiftBox/礼包.cs b/OshimaModules/Items/GiftBox/礼包.cs index 0e3d5f9..9e10757 100644 --- a/OshimaModules/Items/GiftBox/礼包.cs +++ b/OshimaModules/Items/GiftBox/礼包.cs @@ -162,19 +162,20 @@ namespace Oshima.FunGame.OshimaModules.Items public override long Id => (long)GiftBoxID.魔法卡礼包; public override string Name => "魔法卡礼包"; public override string Description => Skills.Active?.Description ?? ""; - public int Count => _count; + public int Count { get; set; } = 1; public Dictionary Gifts { get; set; } = []; - private readonly int _count = 1; + private const string GiftName = "与礼包同品质、随机属性、随机魔法技能的魔法卡"; public 魔法卡礼包(QualityType type = QualityType.White, int count = 1, User? user = null, int remainUseTimes = 1) : base(ItemType.GiftBox) { QualityType = type; Others.Add("QualityType", (int)type); - _count = count; + Count = count; + Others.Add("Count", count); User = user; 礼包.Init(this, new() { - { "与礼包同品质、随机属性、随机魔法技能的魔法卡", count } + { GiftName, count } }, remainUseTimes); } @@ -184,6 +185,11 @@ namespace Oshima.FunGame.OshimaModules.Items { QualityType = (QualityType)qualityType; } + if (Others.TryGetValue("Count", out value) && int.TryParse(value.ToString(), out int count)) + { + Count = count; + Gifts[GiftName] = count; + } } } diff --git a/OshimaModules/Regions/Anomaly.cs b/OshimaModules/Regions/Anomaly.cs index bbf7649..5748400 100644 --- a/OshimaModules/Regions/Anomaly.cs +++ b/OshimaModules/Regions/Anomaly.cs @@ -21,6 +21,10 @@ namespace Oshima.FunGame.OshimaModules.Regions Crops.Add(new(180101, "星银合金", "锻造物品的材料。", "银辉城特有的金属材料,拥有银色的光泽和坚固的质地。能够吸收和储存能量,是建造城市和制造武器的理想材料。")); Crops.Add(new(180102, "液态月光", "锻造物品的材料。", "散发着柔和光芒的液体,如同月光般清澈。蕴含悖论引擎的能量,能够影响现实的结构。")); Crops.Add(new(180103, "星辉凝露", "锻造物品的材料。", "星辉水母散发的凝露,蕴含重构重力的能量,能够暂时扭曲局部空间法则。")); + NPCs.Add("莉娅"); + NPCs.Add("沉默守卫G-7"); + Areas.Add("悖论深井"); + Areas.Add("星屑回廊"); } } @@ -39,6 +43,10 @@ namespace Oshima.FunGame.OshimaModules.Regions Units.Add(new(20401, "冰霜傀儡")); Crops.Add(new(180401, "时霜药剂", "锻造物品的材料。", "能够减缓时间流逝的药剂,维持神智清醒但可能导致记忆混乱和时间感知错乱。")); Crops.Add(new(180402, "冰封记忆", "锻造物品的材料。", "冰封的古代战争幻象碎片,触碰时引发强烈记忆回溯与认知扭曲。")); + NPCs.Add("艾萨克"); + NPCs.Add("冻伤的信使"); + Areas.Add("时钟哨塔"); + Areas.Add("记忆回廊"); } } @@ -57,6 +65,10 @@ namespace Oshima.FunGame.OshimaModules.Regions Characters.Add(new(10601, "镜像之主")); Units.Add(new(20601, "镜像守卫")); Crops.Add(new(180601, "量子纠缠碎片", "锻造物品的材料。", "瞳孔状传送门的微观残片,能够引发量子纠缠现象,连接平行时空。")); + NPCs.Add("奥尔加"); + NPCs.Add("溺亡观测者"); + Areas.Add("倒影城"); + Areas.Add("千瞳之巢"); } } @@ -78,6 +90,10 @@ namespace Oshima.FunGame.OshimaModules.Regions Units.Add(new(20702, "时之蝎")); Crops.Add(new(180701, "时间碎片", "锻造物品的材料。", "时间残骸形成的晶体,拥有不规则形状和模糊纹路,会随机重组周围时空。")); Crops.Add(new(180702, "时凝液", "锻造物品的材料。", "时漏仙人掌分泌的粘稠液体,能够加速或减缓局部时间流逝,但难以控制。")); + NPCs.Add("卖沙人"); + NPCs.Add("循环勘探队"); + Areas.Add("昨日之城"); + Areas.Add("时漏绿洲"); } } @@ -95,6 +111,10 @@ namespace Oshima.FunGame.OshimaModules.Regions Characters.Add(new(10801, "梦魇之主")); Units.Add(new(20801, "思维寄生虫")); Crops.Add(new(180801, "梦境碎片", "锻造物品的材料。", "能够改变认知的梦境残留物,摄入后会混淆现实与虚幻的边界。")); + NPCs.Add("认知矫正师"); + NPCs.Add("洛伦佐"); + Areas.Add("梦境交易所"); + Areas.Add("​​幻疡医院"); } } } diff --git a/OshimaModules/Regions/Ecology.cs b/OshimaModules/Regions/Ecology.cs index 038ce5c..2578a6a 100644 --- a/OshimaModules/Regions/Ecology.cs +++ b/OshimaModules/Regions/Ecology.cs @@ -20,6 +20,10 @@ namespace Oshima.FunGame.OshimaModules.Regions Units.Add(new(20202, "蜜蜡蜂")); Crops.Add(new(180201, "荧蓝汁液", "锻造物品的材料。", "林海特有树木的汁液,拥有荧蓝色的光泽。能够吸收和储存能量,是珍贵的炼金材料。")); Crops.Add(new(180202, "可编程蜜蜡", "锻造物品的材料。", "脉轮圣树分泌的树脂,拥有记忆塑性能力,能够编程实现特定功能。")); + NPCs.Add("老祭司苔藓须"); + NPCs.Add("封喉歌者"); + Areas.Add("古龙沉眠地穴"); + Areas.Add("立体蜂巢市集"); } } @@ -37,6 +41,10 @@ namespace Oshima.FunGame.OshimaModules.Regions Characters.Add(new(10901, "共生母体")); Units.Add(new(20901, "沼泽毒虫")); Crops.Add(new(180901, "菌类样本", "锻造物品的材料。", "共生母体上生长的奇异菌类,能释放麻痹毒素,具有高度研究价值。")); + NPCs.Add("伊芙琳"); + NPCs.Add("溃烂猎人"); + Areas.Add("母体神经丛​​"); + Areas.Add("诱捕菌林"); } } @@ -58,6 +66,12 @@ namespace Oshima.FunGame.OshimaModules.Regions Units.Add(new(21002, "浮空岛灵", [(r => r.Weather == "永夜")])); Crops.Add(new(181001, "影玫瑰", "锻造物品的材料。", "永夜侧绽放的奇异植物,散发幽光,只在绝对黑暗中盛开。", QualityType.White, [(r => r.Weather == "永夜")])); Crops.Add(new(181002, "星锚晶石", "锻造物品的材料。", "引雷柱上脱落的晶体碎片,蕴含空间束缚能量,能暂时固定空间结构。", QualityType.White, [(r => r.Weather == "永昼")])); + NPCs.Add("守夜人卡尔"); + NPCs.Add("星锚祭司​​"); + Areas.Add("永昼庭园​​"); + Areas.Add("永夜墓园"); + Areas.Add("星锚之地"); + Areas.Add("中央之岛"); } } @@ -80,6 +94,10 @@ namespace Oshima.FunGame.OshimaModules.Regions Crops.Add(new(181101, "晶化记忆孢子", "锻造物品的材料。", "红杉散发的记忆载体,吸入后可能体验亡者临终经历。")); Crops.Add(new(181102, "虚空骨髓", "锻造物品的材料。", "骨骼深处的虚空物质,散发扭曲精神的空间能量。")); Crops.Add(new(181103, "神经蕨类", "锻造物品的材料。", "寄生在骸骨上的蕨类植物,根系连接骸骨神经,触碰引发剧烈幻觉。")); + NPCs.Add("骸骨诗人"); + NPCs.Add("\"船长\""); + Areas.Add("骸鲸观星台"); + Areas.Add("幽灵船坞"); } } } diff --git a/OshimaModules/Regions/Machine.cs b/OshimaModules/Regions/Machine.cs index 3438a8d..63d5fe9 100644 --- a/OshimaModules/Regions/Machine.cs +++ b/OshimaModules/Regions/Machine.cs @@ -20,6 +20,10 @@ namespace Oshima.FunGame.OshimaModules.Regions Units.Add(new(20502, "改造士兵")); Crops.Add(new(180501, "机械核心碎片", "锻造物品的材料。", "上古机械文明的能量核心,蕴含强大动力但可能触发自毁程序。")); Crops.Add(new(180502, "活体魔力血", "锻造物品的材料。", "具有自我修复能力的液态魔力,接触会导致身体不可预知的异变。")); + NPCs.Add("\"噬罪者\""); + NPCs.Add("7号改造体"); + Areas.Add("​​忏悔教堂​​"); + Areas.Add("造物车间"); } } } diff --git a/OshimaModules/Regions/Mineral.cs b/OshimaModules/Regions/Mineral.cs index 70e5892..aa2b4da 100644 --- a/OshimaModules/Regions/Mineral.cs +++ b/OshimaModules/Regions/Mineral.cs @@ -20,6 +20,10 @@ namespace Oshima.FunGame.OshimaModules.Regions Units.Add(new(20302, "火焰元素")); Crops.Add(new(180301, "活体金属苔藓", "锻造物品的材料。", "具有金属质感的生命体,能够自我修复和繁殖,是研究金属生命的珍贵样本。")); Crops.Add(new(180302, "深渊火钻", "锻造物品的材料。", "火山深处开采的珍稀矿石,只有被矿工灵魂烙印认可者才能安全触碰。")); + NPCs.Add("\"铁颚\"巴拉克"); + NPCs.Add("苔丝夫人"); + Areas.Add("鱿熔血池​​"); + Areas.Add("活体锻炉"); } } } diff --git a/OshimaModules/Regions/Outworld.cs b/OshimaModules/Regions/Outworld.cs index 820611b..24f68a8 100644 --- a/OshimaModules/Regions/Outworld.cs +++ b/OshimaModules/Regions/Outworld.cs @@ -21,6 +21,11 @@ namespace Oshima.FunGame.OshimaModules.Regions Crops.Add(new(181201, "泰坦符文石", "锻造物品的材料。", "裁决尖碑脱落的法则碎片,蕴含世界调试规则,解读需强大精神力。")); Crops.Add(new(181202, "神经宝石", "锻造物品的材料。", "与矿脉神经相连的晶体,开采时引发山体剧痛和精神污染。")); Crops.Add(new(181203, "矿脉神经纤维", "锻造物品的材料。", "连接神经宝石的活体纤维,触碰导致剧烈痛苦和神经感染。")); + NPCs.Add("泰坦刻录员"); + NPCs.Add("矿痛共生体"); + Areas.Add("神经矿脉​​"); + Areas.Add("雷霆王座"); + Areas.Add("裁决矩阵"); } } } diff --git a/OshimaServers/AnonymousServer.cs b/OshimaServers/AnonymousServer.cs index 43d02ae..10b96c8 100644 --- a/OshimaServers/AnonymousServer.cs +++ b/OshimaServers/AnonymousServer.cs @@ -7,6 +7,7 @@ using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Core.Library.Constant; using Oshima.Core.Configs; using Oshima.Core.Constant; +using Oshima.FunGame.OshimaServers.Model; using Oshima.FunGame.OshimaServers.Service; using TaskScheduler = Milimoe.FunGame.Core.Api.Utility.TaskScheduler; @@ -141,12 +142,28 @@ namespace Oshima.FunGame.OshimaServers User user = FunGameService.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 && FunGameService.SettleQuest(user, quests)) { quests.SaveConfig(); + updateQuest = true; + } + // 探索结算 + List list = pc.Get>("exploring") ?? []; + if (list.Count > 0) + { + updateExplore = FunGameService.SettleExploreAll(list, user); + if (updateExplore) + { + pc.Add("exploring", list); + } + } + if (updateQuest || updateExplore) + { user.LastTime = DateTime.Now; pc.Add("user", user); pc.SaveConfig(); @@ -178,6 +195,8 @@ namespace Oshima.FunGame.OshimaServers }); Task.Run(() => { + // 刷新每天登录 + FunGameService.UserNotice.Clear(); // 刷新签到 string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/saved"; if (Directory.Exists(directoryPath)) @@ -189,6 +208,8 @@ namespace Oshima.FunGame.OshimaServers PluginConfig pc = new("saved", fileName); pc.LoadConfig(); pc.Add("signed", false); + pc.Add("logon", false); + pc.Add("exploreTimes", FunGameConstant.MaxExploreTimes); pc.SaveConfig(); } Controller.WriteLine("刷新签到"); @@ -212,25 +233,6 @@ namespace Oshima.FunGame.OshimaServers Controller.WriteLine("刷新商店"); } }); - Task.Run(() => - { - // 刷新每天登录 - FunGameService.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 = new("saved", fileName); - pc.LoadConfig(); - pc.Add("logon", false); - pc.SaveConfig(); - } - Controller.WriteLine("刷新每天登录"); - } - }); // 刷新活动缓存 FunGameService.GetEventCenter(); }); diff --git a/OshimaServers/Model/ExploreModel.cs b/OshimaServers/Model/ExploreModel.cs new file mode 100644 index 0000000..2e0aa42 --- /dev/null +++ b/OshimaServers/Model/ExploreModel.cs @@ -0,0 +1,42 @@ +using System.Text; +using Milimoe.FunGame.Core.Entity; +using Milimoe.FunGame.Core.Library.Constant; +using Oshima.FunGame.OshimaServers.Service; + +namespace Oshima.FunGame.OshimaServers.Model +{ + public class ExploreModel() + { + public Guid Guid { get; set; } = Guid.NewGuid(); + public long RegionId { get; set; } = 0; + public IEnumerable CharacterIds { get; set; } = []; + public DateTime? StartTime { get; set; } = null; + public ExploreResult Result { get; set; } = ExploreResult.Nothing; + public string String { get; set; } = ""; + public double CreditsAward { get; set; } = 0; + public double MaterialsAward { get; set; } = 0; + public Dictionary Awards { get; set; } = []; + public bool FightWin { get; set; } = false; + public double[] AfterFightHPs { get; set; } = []; + + public string GetExploreInfo(IEnumerable inventoryCharacters, IEnumerable regions) + { + StringBuilder sb = new(); + + if (CharacterIds.Any()) + { + if (regions.FirstOrDefault(r => r.Id == RegionId) is Region region) + { + sb.AppendLine($"☆--- 正在探索 {RegionId} 号地区:{region.Name} ---☆"); + if (StartTime != null) + { + sb.AppendLine($"探索时间:{StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)}"); + } + sb.AppendLine($"探索角色:{FunGameService.GetCharacterGroupInfoByInventorySequence(inventoryCharacters, CharacterIds, ",")}"); + } + } + + return sb.ToString().Trim(); + } + } +} diff --git a/OshimaServers/Service/FunGameConstant.cs b/OshimaServers/Service/FunGameConstant.cs index 5a05ccd..b9c03ee 100644 --- a/OshimaServers/Service/FunGameConstant.cs +++ b/OshimaServers/Service/FunGameConstant.cs @@ -12,6 +12,7 @@ namespace Oshima.FunGame.OshimaServers.Service public const int ItemsPerPage1 = 6; public const int ItemsPerPage2 = 10; public const int ExploreTime = 2; + public const int MaxExploreTimes = 12; public static List Characters { get; } = []; public static List Skills { get; } = []; public static List PassiveSkills { get; } = []; @@ -551,33 +552,37 @@ namespace Oshima.FunGame.OshimaServers.Service ]; /// - /// 参数说明:{0} 奖励内容字符串,{1} 出现的敌人名称,{2} 出现的NPC名称,{3} 出现的物品名称 + /// 参数说明:{0} 奖励内容字符串,{1} 敌人名称,{2} NPC名称,{3} 物品名称1,{4} 地点名称1,{5} 物品名称1,{6} 地点名称2 /// public static Dictionary ExploreString { get; } = new() { - { "哎呀,这波啊,这波是探了个寂寞!不过…好像也不是完全没有收获?奖励:{0}!", ExploreResult.General }, - { "你以为会一无所获?哼,天真!虽然也没啥大用,但至少…获得了:{0}!", ExploreResult.General }, - { "恭喜你!成功在荒野中迷路!奖励…等等,好像是:{0}?算了,凑合着用吧!", ExploreResult.General }, - { "你凝视着远方…远方也凝视着你…然后,你获得了:{ 0}!这大概就是命运吧。", ExploreResult.General }, - { "探索结果:空气,阳光,还有…奖励:{ 0}!看来今天运气还不错?", ExploreResult.General }, + // General - 带奖励的普通结果 + { "当{3}的光芒洒满{4}时,{6}显露出了被封印的{0},你快马加鞭冲了上去夺走!", ExploreResult.General }, + { "{2}的低语在风中消散,但留在你手中的是闪耀的{0}!", ExploreResult.General }, + { "恭喜你!成功在荒野中迷路!奖励…等等,好像是:{0}?至少不是空手而归…", ExploreResult.General }, + { "你凝视着远方,远方也凝视着你…然后,你获得了:{0}!这大概就是命运吧。", ExploreResult.General }, + { "探索结果:空气,阳光,还有…奖励:{0}!看来今天运气还不错?", ExploreResult.General }, - { "啥也没找到,白跑一趟!下次记得带上指南针!", ExploreResult.Nothing }, - { "空空如也,一无所获。看来这地方已经被搜刮干净了!", ExploreResult.Nothing }, - { "你对着空地发呆了半天,然后决定回家。今天就当无事发生。", ExploreResult.Nothing }, - { "探索失败!你被自己的影子吓了一跳,然后落荒而逃。", ExploreResult.Nothing }, - { "你努力寻找着什么,但最终只找到了自己的寂寞。", ExploreResult.Nothing }, + // Nothing - 无收获 + { "风沙抹去了所有痕迹,只有{3}见证过你的到来。(什么也没有获得)", ExploreResult.Nothing }, + { "{4}地牢里的封印纹丝未动,仿佛在嘲笑着你的徒劳……(什么也没有获得)", ExploreResult.Nothing }, + { "在你的注视下,{4}的宝藏已被{2}掠夺一空。(什么也没有获得)", ExploreResult.Nothing }, + { "你对着空地发呆了半天,只剩冰冷的{4}和你的失望。(什么也没有获得)", ExploreResult.Nothing }, + { "在空荡的回响中传来讥笑,原来{4}的秘宝不过是个传说。(什么也没有获得)", ExploreResult.Nothing }, - { "前方高能!遭遇了{ 1}!准备好迎接一场史诗般的…菜鸡互啄!", ExploreResult.Fight }, - { "警告!{ 1} 正在接近!是时候展现真正的技术了…逃跑技术!", ExploreResult.Fight }, - { "战斗警报!{ 1} 想要和你一较高下!拿出你的勇气…或者直接认输吧!", ExploreResult.Fight }, - { "不好了!{ 1} 出现了!快使用你的绝招…装死!", ExploreResult.Fight }, - { "危险!{ 1} 来袭!但是…你好像忘了带武器?", ExploreResult.Fight }, + // Fight - 遭遇敌人 + { "{4}的地面突然裂开,{1}扑向了你!迎接战斗吧!", ExploreResult.Fight }, + { "当你触碰{3}时,{1}的咆哮震撼着{4}!", ExploreResult.Fight }, + { "原来这里真的有危险……是{1}守卫着{4},不得不战了!", ExploreResult.Fight }, + { "在探索{4}的某处时,身旁的墙突然破裂,{1}从阴影中降临!", ExploreResult.Fight }, + { "你惊动了{1}!{4}瞬间化作战场!", ExploreResult.Fight }, - { "发财了!竟然捡到了{ 0}!看来今天出门踩到狗屎了!", ExploreResult.Earned }, - { "哇!{ 0}!这一定是上天赐予我的!感谢老天爷!", ExploreResult.Earned }, - { "你简直不敢相信自己的眼睛!{ 0}!这运气也太好了吧!", ExploreResult.Earned }, - { "天降横财!{ 0}!看来以后要多出门走走了!", ExploreResult.Earned }, - { "惊喜!{ 0}!这一定是隐藏的宝藏!", ExploreResult.Earned } + // Earned - 珍贵收获 + { "当{3}发出诡异的光芒照亮{4}时,藏在其中的{0}突然落入你手中!", ExploreResult.Earned }, + { "祝福应验!{4}深处的{0}为你所有!", ExploreResult.Earned }, + { "解开{4}地牢中的谜题后,{0}终于显现!", ExploreResult.Earned }, + { "屏障消散,至宝{0}光芒万丈,自觉地飞进了你的口袋!", ExploreResult.Earned }, + { "在偶遇{1}和{2}的遭遇战时,你渔翁得利抢到了:{0}!", ExploreResult.Earned } }; public static Dictionary DrawCardProbabilities { get; } = new() diff --git a/OshimaServers/Service/FunGameOrderList.cs b/OshimaServers/Service/FunGameOrderList.cs index b650d9c..c2b5ca0 100644 --- a/OshimaServers/Service/FunGameOrderList.cs +++ b/OshimaServers/Service/FunGameOrderList.cs @@ -43,7 +43,7 @@ {"抽卡/十连抽卡", "金币抽卡(1000/次)"}, {"材料抽卡/材料十连抽卡", "材料抽卡(5/次)"}, {"兑换金币 <材料数>", "1材料=200金币"}, - {"使用 <名称> <数量> [角色] [角色序号]", "使用物品(可指定角色)"}, + {"使用 <名称> <数量> [角色] [角色序号]", "使用物品(可指定角色)举例:使用大经验书 100 角色1"}, {"使用 <序号> [角色] [角色序号]", "使用物品(可指定角色)"}, {"使用魔法卡 <物品序号> <卡包序号>", "使用指定魔法卡"}, {"合成魔法卡 <{序号...}>", "3张魔法卡合成(空格隔开)"}, @@ -69,8 +69,7 @@ {"世界地图", "查看当前地图"}, {"主城", "查看主城信息"}, {"查地区 <序号>", "查看指定地区信息"}, - {"探索 <序号>", "主战角色探索指定地区"}, - {"小队探索 <序号>", "小队探索指定地区(4*单人消耗和奖励)"}, + {"探索 <地区序号> <{角色序号...}>", "探索指定地区(可多角色)"} }; public static Dictionary ClubHelp { get; } = new() { diff --git a/OshimaServers/Service/FunGameService.cs b/OshimaServers/Service/FunGameService.cs index 1aeb844..e70b561 100644 --- a/OshimaServers/Service/FunGameService.cs +++ b/OshimaServers/Service/FunGameService.cs @@ -9,13 +9,15 @@ using Oshima.FunGame.OshimaModules.Effects.OpenEffects; using Oshima.FunGame.OshimaModules.Items; using Oshima.FunGame.OshimaModules.Regions; using Oshima.FunGame.OshimaModules.Skills; +using Oshima.FunGame.OshimaModules.Units; +using Oshima.FunGame.OshimaServers.Model; namespace Oshima.FunGame.OshimaServers.Service { public class FunGameService { public static HashSet Activities { get; } = []; - public static Dictionary> UserNotice { 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; @@ -602,9 +604,12 @@ namespace Oshima.FunGame.OshimaServers.Service public static void AddNotice(long userId, params string[] notices) { - if (UserNotice.TryGetValue(userId, out List? list) && list != null) + if (UserNotice.TryGetValue(userId, out HashSet? list) && list != null) { - list.AddRange(notices); + foreach (string notice in notices) + { + list.Add(notice); + } } else UserNotice[userId] = [.. notices]; } @@ -1281,7 +1286,7 @@ namespace Oshima.FunGame.OshimaServers.Service } } - public static string GetTrainingInfo(TimeSpan diff, bool isPre, out int totalExperience, out int smallBookCount, out int mediumBookCount, out int largeBookCount) + 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; @@ -1317,7 +1322,11 @@ namespace Oshima.FunGame.OshimaServers.Service largeBookCount = Math.Min(1, (trainingHours - 24) / 1); } + double TotalHR = Math.Min(character.MaxHP, character.HR * diff.TotalSeconds); + double TotalMR = Math.Min(character.MaxMP, character.MR * diff.TotalSeconds); + return $"练级时长:{totalMinutes} 分钟,{(isPre ? "预计可" : "")}获得:{totalExperience} 点经验值,{smallBookCount} 本小经验书,{mediumBookCount} 本中经验书,{largeBookCount} 本大经验书。" + + $"回复角色 {TotalHR:0.##} 点生命值和 {TotalMR:0.##} 点魔法值。" + $"{(isPre ? "练级时间上限 1440 分钟(24小时),超时将不会再产生收益,请按时领取奖励!" : "")}"; } @@ -1391,117 +1400,137 @@ namespace Oshima.FunGame.OshimaServers.Service int sLevel = General.GameplayEquilibriumConstant.MaxSkillLevel / cutRate; int mLevel = General.GameplayEquilibriumConstant.MaxMagicLevel / cutRate; int naLevel = General.GameplayEquilibriumConstant.MaxNormalAttackLevel / cutRate; - boss.Level = cLevel; - boss.NormalAttack.Level = naLevel; boss.NormalAttack.ExHardnessTime = -4; - 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; - Effect effect = Factory.OpenFactory.GetInstance((long)EffectID.DynamicsEffect, "", new() - { - { "skill", bossSkill }, - { - "values", - new Dictionary() - { - { "exatk", 200 / cutRate }, - { "exdef", 200 / cutRate }, - { "exhp2", 1.5 }, - { "exmp2", 0.8 }, - { "exhr", 8 / cutRate }, - { "exmr", 4 / cutRate }, - { "excr", 0.35 }, - { "excrd", 0.9 }, - { "excdr", 0.25 }, - { "exacc", 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); + 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) + { + 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) + { + exHP2 = 0; + exMP2 = 0; + } + 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", 3.4 * cLevel }, + { "exdef", 3.4 * cLevel }, + { "exhp2", exHP2 }, + { "exmp2", exMP2 }, + { "exhr", 0.15 * cLevel }, + { "exmr", 0.1 * cLevel }, + { "excr", exCR }, + { "excrd", exCRD }, + { "excdr", 0.25 }, + { "exacc", 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 = []; @@ -1969,13 +1998,348 @@ namespace Oshima.FunGame.OshimaServers.Service return "该活动已删除!"; } - public static string GetSquadInfo(IEnumerable inventory, HashSet squadIds) + 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("\r\n", squad.Select(c => $"#{characters[c]}. {c}")) : "空")}"; + return $"{(squad.Length > 0 ? string.Join(separator, squad.Select(c => $"#{characters[c]}. {c}")) : "空")}"; + } + + 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}")) : "空")}"; + } + + public static async Task GenerateExploreModel(OshimaRegion region, long[] characterIds, User user) + { + int characterCount = characterIds.Length; + ExploreModel model = new() + { + RegionId = region.Id, + CharacterIds = characterIds, + StartTime = DateTime.Now + }; + + // 直接保存探索奖励,但是要等到探索结束后发放 + int random = Random.Shared.Next(FunGameConstant.ExploreString.Count); + string exploreString = FunGameConstant.ExploreString.Keys.ToArray()[random]; + + // 出现的NPC + 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; + + // 筛选敌人 + int diff = region.Difficulty switch + { + RarityType.OneStar => 1, + RarityType.TwoStar => 2, + RarityType.ThreeStar => 3, + RarityType.FourStar => 4, + _ => 5 + }; + List enemys = []; + Character enemy; + if (region.Characters.Count > 0 && region.Units.Count > 0) + { + random = Random.Shared.Next(2); + if (random == 0) + { + 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(); + enemys.Add(enemy.Copy()); + break; + case 3: + case 4: + enemy = region.Units.OrderBy(o => Random.Shared.Next()).First(); + enemys.Add(enemy.Copy()); + enemy = region.Units.OrderBy(o => Random.Shared.Next()).First(); + enemys.Add(enemy.Copy()); + break; + case 5: + default: + enemy = region.Units.OrderBy(o => Random.Shared.Next()).First(); + enemys.Add(enemy.Copy()); + enemy = region.Units.OrderBy(o => Random.Shared.Next()).First(); + enemys.Add(enemy.Copy()); + enemy = region.Units.OrderBy(o => Random.Shared.Next()).First(); + enemys.Add(enemy.Copy()); + break; + } + } + } + else + { + enemy = new RegionCharacter(long.Parse(Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 8)), GenerateRandomChineseUserName()); + enemys.Add(enemy); + } + + // 生成奖励 + string award = ""; + model.Result = FunGameConstant.ExploreString[exploreString]; + 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(500, 1000) * 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, 700) * diff; + } + model.Awards["exp"] = exp; + award += $",并额外获得了 {exp} 点经验值(探索队员们平分)"; + break; + case ExploreResult.Fight: + // 小队信息 + Character[] squad = [.. user.Inventory.Characters.Where((c, index) => characterIds.Contains(index + 1)).Select(c => CharacterBuilder.Build(c, false, true, user.Inventory, 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); + } + // 开始战斗 + Team team1 = new($"{user.Username}的探索小队", squad); + Team team2 = new($"{region.Name}", enemys); + List msgs = await FunGameActionQueue.NewAndStartTeamGame([team1, team2], showAllRound: true); + if (msgs.Count > 2) + { + msgs = msgs[^2..]; + } + if (enemy.HP <= 0) + { + model.FightWin = true; + int credits = 0; + for (int i = 0; i < characterCount; i++) + { + credits += Random.Shared.Next(1000, 1500) * diff; + } + model.CreditsAward = credits; + exp = 0; + for (int i = 0; i < characterCount; i++) + { + exp += Random.Shared.Next(600, 1000) * diff; + } + model.Awards["exp"] = exp; + int materials = 0; + for (int i = 0; i < characterCount; i++) + { + materials += Random.Shared.Next(4, 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}"; + exploreString = $"{exploreString}\r\n{string.Join("\r\n", msgs)}\r\n探索小队战胜了{enemy.Name}!获得了:{award}!"; + } + else + { + Item item = FunGameConstant.ExploreItems[region][Random.Shared.Next(FunGameConstant.ExploreItems[region].Count)]; + model.Awards[item.Name] = characterCount; + award = $"{characterCount} 个{item.Name}"; + exploreString = $"{exploreString}\r\n{string.Join("\r\n", msgs)}\r\n探索小队未能战胜{enemy.Name},但是获得了补偿:{award}!"; + } + model.AfterFightHPs = [.. squad.Select(c => c.HP)]; + } + break; + case ExploreResult.Earned: + Item? itemEarned = region.Items.OrderBy(o => Random.Shared.Next()).FirstOrDefault(); + if (itemEarned is null) + { + model.Result = ExploreResult.Nothing; + exploreString = "你在探索中发现了一个神秘的物品,但它似乎无法辨认。(什么也没有获得)"; + } + else + { + model.Awards[itemEarned.Name] = 1; + award = 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); + return model; + } + + public static bool SettleExplore(Guid exploreId, List list, User user, out string msg) + { + bool result = false; + msg = ""; + ExploreModel? model = list.FirstOrDefault(m => m.Guid == 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++) + { + Item newItem = item.Copy(); + newItem.User = user; + SetSellAndTradeTime(newItem); + user.Inventory.Items.Add(newItem); + } + } + } + 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(List list, User user) + { + bool settle = false; + List remove = []; + foreach (ExploreModel model in list) + { + if (model.StartTime.HasValue && (DateTime.Now - model.StartTime.Value).TotalMinutes > FunGameConstant.ExploreTime + 5) + { + if (SettleExplore(model.Guid, list, user, out string msg)) + { + settle = true; + AddNotice(user.Id, $"你上次未完成的探索已被自动结算:{msg}"); + remove.Add(model.Guid); + } + } + } + foreach (Guid guid in remove) + { + list.RemoveAll(m => m.Guid == guid); + } + return settle; } } } diff --git a/OshimaWebAPI/Controllers/FunGameController.cs b/OshimaWebAPI/Controllers/FunGameController.cs index 3c53229..6ace146 100644 --- a/OshimaWebAPI/Controllers/FunGameController.cs +++ b/OshimaWebAPI/Controllers/FunGameController.cs @@ -13,6 +13,7 @@ using Oshima.Core.Configs; using Oshima.FunGame.OshimaModules.Characters; using Oshima.FunGame.OshimaModules.Items; using Oshima.FunGame.OshimaModules.Regions; +using Oshima.FunGame.OshimaServers.Model; using Oshima.FunGame.OshimaServers.Service; namespace Oshima.FunGame.WebAPI.Controllers @@ -3022,11 +3023,13 @@ namespace Oshima.FunGame.WebAPI.Controllers user.Inventory.Training.Remove(cid); TimeSpan diff = now - time; - string msg = FunGameService.GetTrainingInfo(diff, false, out int totalExperience, out int smallBookCount, out int mediumBookCount, out int largeBookCount); + string msg = FunGameService.GetTrainingInfo(diff, character, false, out int totalExperience, out int smallBookCount, out int mediumBookCount, out int largeBookCount); if (totalExperience > 0) { character.EXP += totalExperience; + character.HP += character.HR * diff.TotalSeconds; + character.MP += character.MR * diff.TotalSeconds; } for (int i = 0; i < smallBookCount; i++) @@ -3095,7 +3098,7 @@ namespace Oshima.FunGame.WebAPI.Controllers if (character != null) { TimeSpan diff = now - time; - string msg = FunGameService.GetTrainingInfo(diff, true, out int totalExperience, out int smallBookCount, out int mediumBookCount, out int largeBookCount); + string msg = FunGameService.GetTrainingInfo(diff, character, true, out int totalExperience, out int smallBookCount, out int mediumBookCount, out int largeBookCount); return $"角色 [ {character} ] 正在练级中,{msg}\r\n确认无误后请输入【练级结算】领取奖励!"; } @@ -5230,10 +5233,13 @@ namespace Oshima.FunGame.WebAPI.Controllers } [HttpPost("exploreregion")] - public string ExploreRegion([FromQuery] long? uid = null, [FromQuery] long? id = null) + public async Task<(string, Guid)> ExploreRegion([FromQuery] long? uid = null, [FromQuery] long? id = null, [FromBody] long[]? cids = null) { + Guid exploreId = Guid.Empty; long userid = uid ?? Convert.ToInt64("10" + Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 11)); long regionid = id ?? 0; + long[] characterIds = cids ?? []; + int characterCount = characterIds.Length; PluginConfig pc = new("saved", userid.ToString()); pc.LoadConfig(); @@ -5243,13 +5249,249 @@ namespace Oshima.FunGame.WebAPI.Controllers { User user = FunGameService.GetUser(pc); - if (regionid > 0 && regionid <= FunGameConstant.Regions.Count && FunGameConstant.Regions.FirstOrDefault(r => r.Id == regionid) is OshimaRegion region) + // 检查角色存在 + List invalid = []; + foreach (long cid in characterIds) { - msg = $"开始探索【{region.Name}】,探索时间:{FunGameConstant.ExploreTime} 分钟。(骗你的,其实还没做)"; + if (cid > 0 && cid <= user.Inventory.Characters.Count) + { + // do nothing + } + else + { + invalid.Add(cid); + } + } + if (invalid.Count > 0) + { + msg = $"没有找到与输入序号相对应的角色:{string.Join(",", invalid)}。"; + } + + // 检查探索次数 + if (pc.TryGetValue("exploreTimes", out object? value) && int.TryParse(value.ToString(), out int exploreTimes)) + { + if (exploreTimes <= 0) + { + exploreTimes = 0; + msg = $"今日的探索次数已用完,无法再继续探索。"; + } + else if (characterCount > exploreTimes) + { + msg = $"你选择的角色数量超过了剩余的探索次数({exploreTimes} 次),请减少选择的角色数量。需要注意:探索角色越多,奖励越多,但是会扣除相应的探索次数。"; + } } else { - return $"没有找到与这个序号相对应的地区!"; + exploreTimes = FunGameConstant.MaxExploreTimes; + } + + // 检查角色是否正在探索 + List list = pc.Get>("exploring") ?? []; + if (list.Count > 0) + { + string msg2 = ""; + List remove = []; + foreach (ExploreModel model in list) + { + // 可能要结算先前的超时探索 + if (model.StartTime.HasValue && (DateTime.Now - model.StartTime.Value).TotalMinutes > FunGameConstant.ExploreTime + 5) + { + if (FunGameService.SettleExplore(model.Guid, list, user, out string notice)) + { + if (notice != "") + { + if (msg2 != "") msg2 += "\r\n"; + msg2 += $"你上次未完成的探索已被自动结算{notice}"; + } + remove.Add(model.Guid); + } + } + + IEnumerable exploring = model.CharacterIds.Intersect(characterIds); + if (exploring.Any()) + { + if (msg2 != "") msg2 += "\r\n"; + msg2 += $"你暂时无法使用以下角色进行探索:[ {FunGameService.GetCharacterGroupInfoByInventorySequence(user.Inventory.Characters, exploring, " ] / [ ")} ]," + + $"因为这些角色已经参与了另一场探索:\r\n{model.GetExploreInfo(user.Inventory.Characters, FunGameConstant.Regions)}"; + } + } + foreach (Guid guid in remove) + { + list.RemoveAll(m => m.Guid == guid); + } + if (msg2 != "") + { + if (msg != "") msg += "\r\n"; + msg += msg2; + } + } + + if (msg == "") + { + exploreTimes -= characterCount; + if (regionid > 0 && regionid <= FunGameConstant.Regions.Count && FunGameConstant.Regions.FirstOrDefault(r => r.Id == regionid) is OshimaRegion region) + { + msg = $"开始探索【{region.Name}】,探索时间预计 {FunGameConstant.ExploreTime} 分钟(系统会自动结算,届时会有提示)。" + + $"探索成员:[ {FunGameService.GetCharacterGroupInfoByInventorySequence(user.Inventory.Characters, characterIds, " ] / [ ")} ]"; + ExploreModel model = await FunGameService.GenerateExploreModel(region, characterIds, user); + exploreId = model.Guid; + list.Add(model); + } + else + { + return ($"没有找到与这个序号相对应的地区!", exploreId); + } + } + + if (exploreTimes > 0) + { + if (msg != "") msg += "\r\n"; + msg += $"本次扣除探索次数 {characterCount} 次,你的剩余探索次数:{exploreTimes} 次。需要注意:探索角色越多,奖励越多,但是会扣除相应的探索次数。"; + } + + user.LastTime = DateTime.Now; + pc.Add("user", user); + pc.Add("exploreTimes", exploreTimes); + pc.Add("exploring", list); + pc.SaveConfig(); + + return (msg, exploreId); + } + else + { + return (noSaved, exploreId); + } + } + + [HttpGet("exploreinfo")] + public string GetExploreInfo([FromQuery] long? uid = null) + { + long userid = uid ?? Convert.ToInt64("10" + Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 11)); + + PluginConfig pc = new("saved", userid.ToString()); + pc.LoadConfig(); + + string msg = ""; + if (pc.Count > 0) + { + User user = FunGameService.GetUser(pc); + + // 检查探索次数 + if (pc.TryGetValue("exploreTimes", out object? value) && int.TryParse(value.ToString(), out int exploreTimes)) + { + if (exploreTimes <= 0) + { + exploreTimes = 0; + msg = $"今日的探索次数已用完,无法再继续探索。"; + } + } + else + { + exploreTimes = FunGameConstant.MaxExploreTimes; + } + + List list = pc.Get>("exploring") ?? []; + if (list.Count > 0) + { + string msg2 = ""; + foreach (ExploreModel model in list) + { + if (msg2 != "") msg2 += "\r\n"; + msg2 += model.GetExploreInfo(user.Inventory.Characters, FunGameConstant.Regions); + } + if (msg2 != "") + { + if (msg != "") msg += "\r\n"; + msg += $"你目前有以下角色正在探索中:\r\n{msg2}"; + } + } + else + { + msg = $"你目前没有角色正在探索。"; + } + + if (exploreTimes > 0) + { + if (msg != "") msg += "\r\n"; + msg += $"你的剩余探索次数:{exploreTimes} 次。"; + } + + user.LastTime = DateTime.Now; + pc.Add("user", user); + pc.SaveConfig(); + + return msg; + } + else + { + return noSaved; + } + } + + [HttpPost("exploresettleall")] + public string SettleExploreAll([FromQuery] long? uid = null) + { + long userid = uid ?? Convert.ToInt64("10" + Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 11)); + + PluginConfig pc = new("saved", userid.ToString()); + pc.LoadConfig(); + + string msg; + if (pc.Count > 0) + { + User user = FunGameService.GetUser(pc); + + List list = pc.Get>("exploring") ?? []; + if (list.Count > 0) + { + if (FunGameService.SettleExploreAll(list, user)) + { + pc.Add("exploring", list); + msg = $"已完成探索结算。"; + } + else + { + msg = $"没有需要结算的探索。"; + } + } + else + { + msg = $"你目前没有角色正在探索。"; + } + + user.LastTime = DateTime.Now; + pc.Add("user", user); + pc.SaveConfig(); + + return msg; + } + else + { + return noSaved; + } + } + + [HttpPost("exploresettle")] + public string SettleExplore(Guid exploreId, [FromQuery] long? uid = null) + { + long userid = uid ?? Convert.ToInt64("10" + Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 11)); + + PluginConfig pc = new("saved", userid.ToString()); + pc.LoadConfig(); + + string msg = ""; + if (pc.Count > 0) + { + User user = FunGameService.GetUser(pc); + + List list = pc.Get>("exploring") ?? []; + if (list.Count > 0) + { + if (FunGameService.SettleExplore(exploreId, list, user, out msg)) + { + list.RemoveAll(m => m.Guid == exploreId); + } + pc.Add("exploring", list); } user.LastTime = DateTime.Now; diff --git a/OshimaWebAPI/Services/RainBOTService.cs b/OshimaWebAPI/Services/RainBOTService.cs index 749f7a2..786d936 100644 --- a/OshimaWebAPI/Services/RainBOTService.cs +++ b/OshimaWebAPI/Services/RainBOTService.cs @@ -44,7 +44,7 @@ namespace Oshima.FunGame.WebAPI.Services content = content.Trim(); await Service.SendC2CMessageAsync(msg.OpenId, content, msgType, media, msg.Id, msgSeq); } - if (msg.FunGameUID > 0 && FunGameService.UserNotice.TryGetValue(msg.FunGameUID, out List? msgs) && msgs != null) + if (msg.FunGameUID > 0 && FunGameService.UserNotice.TryGetValue(msg.FunGameUID, out HashSet? msgs) && msgs != null) { FunGameService.UserNotice.Remove(msg.FunGameUID); await SendAsync(msg, "每日登录提醒", string.Join("\r\n", msgs), msgType, media, 5); @@ -2052,17 +2052,64 @@ namespace Oshima.FunGame.WebAPI.Services return result; } + if (e.Detail == "探索信息") + { + string msg = Controller.GetExploreInfo(uid); + if (msg != "") + { + await SendAsync(e, "探索信息", string.Join("\r\n", msg)); + } + return result; + } + + if (e.Detail == "探索结算") + { + string msg = Controller.SettleExploreAll(uid); + if (msg != "") + { + await SendAsync(e, "探索结算", string.Join("\r\n", msg)); + } + return result; + } + if (e.Detail.StartsWith("探索") || e.Detail.StartsWith("前往")) { string detail = e.Detail.Replace("探索", "").Replace("前往", "").Trim(); string msg = ""; - if (int.TryParse(detail, out int cid)) + Guid eid = Guid.Empty; + string[] strings = detail.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); + List cindexs = []; + foreach (string s in strings) { - msg = Controller.ExploreRegion(uid, cid); + if (int.TryParse(s, out int c)) + { + cindexs.Add(c); + } + } + if (cindexs.Count > 1 && cindexs.Count <= 5) + { + (msg, eid) = await Controller.ExploreRegion(uid, cindexs[0], [.. cindexs.Skip(1).Select(id => (long)id)]); if (msg.Trim() != "") { await SendAsync(e, "探索", msg); } + _ = Task.Run(async () => + { + await Task.Delay(FunGameConstant.ExploreTime * 60 * 1000); + msg = Controller.SettleExplore(eid, uid); + if (msg.Trim() != "") + { + await SendAsync(e, "探索", msg, msgSeq: 2); + } + }); + } + else if (cindexs.Count > 5) + { + await SendAsync(e, "探索", "一次探索只能指定至多 4 个角色,需要注意:探索角色越多,奖励越多,但是会扣除相应的探索次数。"); + } + else + { + await SendAsync(e, "探索", "探索指令格式错误,正确格式为:探索 <地区序号> <{角色序号...}>"); } return result; } @@ -2079,10 +2126,17 @@ namespace Oshima.FunGame.WebAPI.Services if (e.Detail == "毕业礼包") { - string msg = Controller.CreateGiftBox(uid, "毕业礼包", true, 2); - if (msg != "") + if (FunGameService.Activities.FirstOrDefault(a => a.Name == "毕业季") is Activity activity && activity.Status == ActivityState.InProgress) { - await SendAsync(e, "毕业礼包", string.Join("\r\n", msg)); + string msg = Controller.CreateGiftBox(uid, "毕业礼包", true, 2); + if (msg != "") + { + await SendAsync(e, "毕业礼包", string.Join("\r\n", msg)); + } + } + else + { + await SendAsync(e, "毕业礼包", "活动不存在或已过期。"); } return result; }