修复赛马BUG,添加共斗

This commit is contained in:
milimoe 2025-08-01 01:35:27 +08:00
parent ef349b5d45
commit 5c55f6e48c
Signed by: milimoe
GPG Key ID: 9554D37E4B8991D0
8 changed files with 627 additions and 37 deletions

View File

@ -18,6 +18,7 @@ namespace Oshima.FunGame.OshimaModules.Models
public const int DrawCardReduce = 1000; public const int DrawCardReduce = 1000;
public const int DrawCardReduce_Material = 5; public const int DrawCardReduce_Material = 5;
public const int SemaphoreSlimTimeout = 5000; public const int SemaphoreSlimTimeout = 5000;
public const int RoomExpireTime = 10;
public static List<Character> Characters { get; } = []; public static List<Character> Characters { get; } = [];
public static List<Skill> Skills { get; } = []; public static List<Skill> Skills { get; } = [];
public static List<Skill> PassiveSkills { get; } = []; public static List<Skill> PassiveSkills { get; } = [];
@ -40,6 +41,12 @@ namespace Oshima.FunGame.OshimaModules.Models
public static Dictionary<long, Room> UsersInRoom { get; set; } = []; public static Dictionary<long, Room> UsersInRoom { get; set; } = [];
public static ItemType[] ItemCanUsed => [ItemType.Consumable, ItemType.MagicCard, ItemType.SpecialItem, ItemType.GiftBox, ItemType.Others]; public static ItemType[] ItemCanUsed => [ItemType.Consumable, ItemType.MagicCard, ItemType.SpecialItem, ItemType.GiftBox, ItemType.Others];
public static ItemType[] ItemCanNotDrawCard => [ItemType.Collectible, ItemType.QuestItem, ItemType.GiftBox, ItemType.Others]; public static ItemType[] ItemCanNotDrawCard => [ItemType.Collectible, ItemType.QuestItem, ItemType.GiftBox, ItemType.Others];
public static Dictionary<long, int> UserHorseRacingRanking { get; } = [];
public static Dictionary<long, double> UserCreditsRanking { get; } = [];
public static Dictionary<long, double> UserMaterialsRanking { get; } = [];
public static Dictionary<long, double> UserEXPRanking { get; } = [];
public static Dictionary<long, double> UserSkillRanking { get; } = [];
public static DateTime RankingUpdateTime { get; set; } = DateTime.Now;
public static char[] SplitChars => [',', ' ', '', '', ';']; public static char[] SplitChars => [',', ' ', '', '', ';'];
public static Dictionary<int, Dictionary<string, int>> LevelBreakNeedyList { get; } = new() public static Dictionary<int, Dictionary<string, int>> LevelBreakNeedyList { get; } = new()

View File

@ -0,0 +1,189 @@
using System.Text;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
using Oshima.FunGame.OshimaModules.Models;
using Oshima.FunGame.OshimaModules.Regions;
using Oshima.FunGame.OshimaServers.Service;
namespace Oshima.FunGame.OshimaServers.Model
{
public class Cooperative
{
private const int MaxRounds = 9999;
private static readonly Random _random = new();
public static async Task RunCooperativeGame(List<string> msgs, Room room)
{
long[] userIds = [.. room.UserAndIsReady.Keys.Select(user => user.Id)];
try
{
Dictionary<User, Character> characters = [];
Dictionary<User, PluginConfig> pcs = [];
try
{
foreach (User user in room.UserAndIsReady.Keys)
{
PluginConfig pc = FunGameService.GetUserConfig(user.Id, out bool isTimeout);
if (isTimeout)
{
throw new Exception($"获取 {user.Username} 的库存信息超时。");
}
if (pc.Count > 0)
{
User userTemp = FunGameService.GetUser(pc);
pcs[userTemp] = pc;
characters[user] = user.Inventory.MainCharacter;
}
else
{
throw new Exception($"获取 {user.Username} 的库存信息失败。");
}
}
}
catch (Exception e)
{
msgs.Add($"发生错误:{e.Message}");
return;
}
StringBuilder builder = new();
builder.AppendLine("☆--- 共斗模式玩家列表 ---☆");
builder.AppendLine($"房间号:{room.Roomid}");
foreach (User user in characters.Keys)
{
builder.AppendLine($"[ {user} ] 出战角色:{characters[user].ToStringWithLevelWithOutUser()}");
}
msgs.Add(builder.ToString().Trim());
// 生成敌人
OshimaRegion region = FunGameConstant.Regions.OrderBy(o => _random.Next()).First();
List<Character> enemys = [];
Character? enemy = null;
bool isUnit = Random.Shared.Next(2) != 0;
if (!isUnit)
{
enemy = region.Characters.OrderBy(o => Random.Shared.Next()).FirstOrDefault();
if (enemy != null)
{
enemy = enemy.Copy();
enemy.ExHPPercentage += 0.2;
enemys.Add(enemy);
}
}
else
{
for (int i = 0; i < Math.Max(1, characters.Count); i++)
{
enemy = region.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);
}
}
}
if (enemys.Count == 0)
{
msgs.Add("没有可用的敌人,返回游戏房间。");
}
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 = (int)characters.Values.Average(c => c.Level) + 5;
int sLevel = cLevel / 7;
int mLevel = cLevel / 9;
int naLevel = mLevel;
foreach (Character enemy_loop in enemys)
{
FunGameService.EnhanceBoss(enemy_loop, weapons, armors, shoes, accessory, consumables, cLevel, sLevel, mLevel, naLevel, false, false, isUnit);
}
// 开始战斗
Team team1 = new($"房间{room.Roomid}", characters.Values);
Team team2 = new($"{region.Name}", enemys);
FunGameActionQueue actionQueue = new();
List<string> gameMsgs = await actionQueue.StartTeamGame([team1, team2], showAllRound: true);
if (gameMsgs.Count > 15)
{
gameMsgs = gameMsgs[^15..];
}
msgs.AddRange(gameMsgs);
// 结算奖励
Character? mvp = actionQueue.GamingQueue.CharacterStatistics.OrderByDescending(d => d.Value.Rating).Select(d => d.Key).FirstOrDefault();
int multiplication = 1;
int award = multiplication * enemys.Count;
if (enemys.All(e => e.HP == 0))
{
multiplication = 15;
award = multiplication * enemys.Count;
builder.Clear();
builder.AppendLine($"☆--- 战斗胜利奖励 ---☆");
builder.AppendLine($"击杀了全部敌人,所有玩家获得奖励:{award} {General.GameplayEquilibriumConstant.InGameMaterial}");
}
else
{
builder.AppendLine($"☆--- 战斗失败奖励 ---☆");
int count = enemys.Count(e => e.HP == 0);
award = multiplication * count;
builder.AppendLine($"击杀了 {count} 个敌人,所有玩家获得奖励:{award} {General.GameplayEquilibriumConstant.InGameMaterial}");
}
foreach (User user in characters.Keys)
{
user.Inventory.Materials += award;
}
if (mvp != null)
{
builder.AppendLine($"MVP 玩家额外获得奖励:{award} {General.GameplayEquilibriumConstant.InGameMaterial}");
if (characters.Keys.FirstOrDefault(u => u.Id == mvp.User.Id) is User mvpUser)
{
mvpUser.Inventory.Materials += award;
}
}
builder.AppendLine($"☆--- 战斗数据 ---☆");
int index = 1;
foreach (Character character in actionQueue.GamingQueue.CharacterStatistics.Where(kv => characters.ContainsValue(kv.Key)).Select(kv => kv.Key))
{
CharacterStatistics stats = actionQueue.GamingQueue.CharacterStatistics[character];
builder.AppendLine($"{index + ". "}[ {character.ToStringWithLevel()} ]");
builder.AppendLine($"技术得分:{stats.Rating:0.0#} / 击杀数:{stats.Kills} / 助攻数:{stats.Assists} / 死亡数:{stats.Deaths}");
builder.AppendLine($"存活时长:{stats.LiveTime:0.##} / 存活回合数:{stats.LiveRound} / 行动回合数:{stats.ActionTurn}");
builder.AppendLine($"控制时长:{stats.ControlTime:0.##} / 总计治疗:{stats.TotalHeal:0.##} / 护盾抵消:{stats.TotalShield:0.##}");
builder.AppendLine($"总计伤害:{stats.TotalDamage:0.##} / 总计物理伤害:{stats.TotalPhysicalDamage:0.##} / 总计魔法伤害:{stats.TotalMagicDamage:0.##}");
builder.AppendLine($"总承受伤害:{stats.TotalTakenDamage:0.##} / 总承受物理伤害:{stats.TotalTakenPhysicalDamage:0.##} / 总承受魔法伤害:{stats.TotalTakenMagicDamage:0.##}");
if (stats.TotalTrueDamage > 0 || stats.TotalTakenTrueDamage > 0) builder.AppendLine($"总计真实伤害:{stats.TotalTrueDamage:0.##} / 总承受真实伤害:{stats.TotalTakenTrueDamage:0.##}");
builder.AppendLine($"每秒伤害:{stats.DamagePerSecond:0.##} / 每回合伤害:{stats.DamagePerTurn:0.##}");
index++;
}
msgs.Add(builder.ToString().Trim());
}
// 存档
foreach (User user in pcs.Keys)
{
FunGameService.SetUserConfigButNotRelease(user.Id, pcs[user], user);
}
}
catch (Exception e)
{
msgs.Add($"发生错误:{e.Message}");
}
finally
{
foreach (long id in userIds)
{
FunGameService.ReleaseUserSemaphoreSlim(id);
}
}
}
}
}

View File

@ -4,7 +4,7 @@ using Oshima.FunGame.OshimaModules.Models;
namespace Oshima.FunGame.OshimaServers.Model namespace Oshima.FunGame.OshimaServers.Model
{ {
public static class HorseRacing public class HorseRacing
{ {
private const int MaxTurns = 100; private const int MaxTurns = 100;
private static readonly Random _random = new(); private static readonly Random _random = new();
@ -26,10 +26,10 @@ namespace Oshima.FunGame.OshimaServers.Model
Horse horse = new(user); Horse horse = new(user);
AssignRandomSkills(horse); AssignRandomSkills(horse);
horses.Add(horse); horses.Add(horse);
builder.AppendLine($"[ {horse}({horse.HP}) ] 已准备就绪!初始步数: {horse.Step}, 生命值: {horse.HP}, 每回合恢复生命值: {horse.HPRecovery}"); builder.AppendLine($"[ {horse} ] 已准备就绪!初始步数: {horse.Step}, 生命值: {horse.HP}, 每回合恢复生命值: {horse.HPRecovery}");
if (horse.Skills.Count != 0) if (horse.Skills.Count != 0)
{ {
builder.AppendLine($"[ {horse}({horse.HP}) ] 拥有技能: {string.Join("", horse.Skills.Select(s => $"{s.Name} {s.Duration} "))}"); builder.AppendLine($"[ {horse} ] 拥有技能: {string.Join("", horse.Skills.Select(s => $"{s.Name} {s.Duration} "))}");
} }
} }
@ -49,6 +49,7 @@ namespace Oshima.FunGame.OshimaServers.Model
foreach (Horse horse in horses) foreach (Horse horse in horses)
{ {
turnSkills.TryAdd(horse, []); turnSkills.TryAdd(horse, []);
if (horse.HP == 0) continue;
// 触发永久技能 // 触发永久技能
foreach (HorseSkill skill in horse.Skills) foreach (HorseSkill skill in horse.Skills)
{ {
@ -101,7 +102,8 @@ namespace Oshima.FunGame.OshimaServers.Model
turnSteps[horse] += skill.ChangePosition; turnSteps[horse] += skill.ChangePosition;
Horse? source = skill.Horse; Horse? source = skill.Horse;
if (source != null && source != horse) turnEvents.Add($"💥 受到了 [ {skill.Name}(来自:{source}] 的影响,{skill}"); if (source != null && source != horse) turnEvents.Add($"💥 受到了 [ {skill.Name}(来自:{source}] 的影响,{skill}(剩余 {activeEffect.RemainDuration} 回合)");
else turnEvents.Add($"💥 受到了 [ {skill.Name} ] 的影响,{skill}(剩余 {activeEffect.RemainDuration} 回合)");
activeEffect.RemainDuration--; activeEffect.RemainDuration--;
if (activeEffect.RemainDuration <= 0) if (activeEffect.RemainDuration <= 0)
@ -116,7 +118,7 @@ namespace Oshima.FunGame.OshimaServers.Model
} }
// 随机事件 // 随机事件
if (_random.NextDouble() < 0.5) if (_random.NextDouble() < 0.3)
{ {
HorseSkill eventSkill = GenerateRandomEventSkill(); HorseSkill eventSkill = GenerateRandomEventSkill();
// 随机事件技能也可能持续多回合 // 随机事件技能也可能持续多回合
@ -140,11 +142,16 @@ namespace Oshima.FunGame.OshimaServers.Model
horse.HP += effectiveHPRecovery; horse.HP += effectiveHPRecovery;
if (hp != horse.HP) if (hp != horse.HP)
{ {
builder.AppendLine($"[ {horse}({horse.HP}) ] ❤️ 生命值恢复至 {horse.HP} 点(+{effectiveHPRecovery})。"); turnEvents.Add($"❤️ 生命值恢复至 {horse.HP} 点(+{effectiveHPRecovery})。");
} }
if (horse.HP <= 0) if (horse.HP <= 0)
{ {
turnSteps[horse] = 0;
if (turnEvents.Count != 0)
{
builder.AppendLine($"[ {horse} ] {string.Join("", turnEvents)}");
}
continue; continue;
} }
@ -153,15 +160,15 @@ namespace Oshima.FunGame.OshimaServers.Model
horse.CurrentPosition += effectiveStep; // 移动 horse.CurrentPosition += effectiveStep; // 移动
turnSteps[horse] += effectiveStep; turnSteps[horse] += effectiveStep;
//if (effectiveStep > 1) builder.AppendLine($"[ {horse}({horse.HP}) ] 移动了 {effectiveStep} 步!"); //if (effectiveStep > 1) builder.AppendLine($"[ {horse} ] 移动了 {effectiveStep} 步!");
if (turnEvents.Count != 0) if (turnEvents.Count != 0)
{ {
builder.AppendLine($"[ {horse}({horse.HP}) ] {string.Join("", turnEvents)}"); builder.AppendLine($"[ {horse} ] {string.Join("", turnEvents)}");
} }
if (horse.CurrentPosition >= maxLength) if (horse.CurrentPosition >= maxLength)
{ {
builder.AppendLine($"\r\n🎯 恭喜 [ {horse}({horse.HP}) ] 冲过终点线!它赢得了比赛!\r\n"); builder.AppendLine($"\r\n🎯 恭喜 [ {horse} ] 冲过终点线!它赢得了比赛!\r\n");
raceFinished = true; raceFinished = true;
break; break;
} }
@ -185,13 +192,36 @@ namespace Oshima.FunGame.OshimaServers.Model
builder.Clear(); builder.Clear();
builder.AppendLine("☆--- 比赛结果 ---☆"); builder.AppendLine("☆--- 比赛结果 ---☆");
List<Horse> finalRanking = [.. horses.OrderByDescending(h => h.CurrentPosition)]; List<Horse> finalRanking = [.. horses.OrderByDescending(h => h.CurrentPosition)];
int points = 10; int rank = 1;
int horsesAtCurrentRankCount = 0; // 当前名次有多少匹马
int lastPosition = -1; // 上一匹马的位置
for (int i = 0; i < finalRanking.Count; i++) for (int i = 0; i < finalRanking.Count; i++)
{ {
userPoints[finalRanking[i].Id] = points; Horse currentHorse = finalRanking[i];
builder.AppendLine($"第 {i + 1} 名:{finalRanking[i].Name}(获得 {points} 点赛马积分)");
points = (int)(points * 0.8); if (i == 0)
if (points == 0) points = 1; {
rank = 1;
lastPosition = currentHorse.CurrentPosition;
horsesAtCurrentRankCount = 1;
}
else if (currentHorse.CurrentPosition == lastPosition) // 与前一匹马平局
{
horsesAtCurrentRankCount++;
}
else
{
// 新的名次是当前名次加上之前平局的马匹数量
rank += horsesAtCurrentRankCount;
lastPosition = currentHorse.CurrentPosition;
horsesAtCurrentRankCount = 1;
}
// 根据实际名次计算积分
int points = CalculatePointsForRank(rank);
userPoints[currentHorse.Id] = points;
builder.AppendLine($"{(horsesAtCurrentRankCount > 1 ? "" : "")}第 {rank} 名:{currentHorse.Name}(获得 {points} 点赛马积分)");
} }
builder.AppendLine("\r\n比赛结束奖励将在稍后发放"); builder.AppendLine("\r\n比赛结束奖励将在稍后发放");
@ -200,6 +230,20 @@ namespace Oshima.FunGame.OshimaServers.Model
return userPoints; return userPoints;
} }
private static int CalculatePointsForRank(int rank)
{
if (rank <= 0) return 0;
if (rank == 1) return 10;
int points = 10;
for (int r = 2; r <= rank; r++)
{
points = (int)(points * 0.8);
if (points == 0) points = 1;
}
return points;
}
private static void AssignRandomSkills(Horse horse) private static void AssignRandomSkills(Horse horse)
{ {
// 技能池 // 技能池
@ -277,7 +321,7 @@ namespace Oshima.FunGame.OshimaServers.Model
int dashesAfterHorse = Math.Max(0, maxLength - horse.CurrentPosition); int dashesAfterHorse = Math.Max(0, maxLength - horse.CurrentPosition);
builder.Append(new string('=', dashesAfterHorse)); builder.Append(new string('=', dashesAfterHorse));
string horseMarker = $"<{horse}>"; string horseMarker = $"<{horse}({horse.HP})>";
if (horse.ActiveEffects.Count > 0 || horse.HP == 0) if (horse.ActiveEffects.Count > 0 || horse.HP == 0)
{ {
if (horse.HP == 0) if (horse.HP == 0)
@ -293,7 +337,7 @@ namespace Oshima.FunGame.OshimaServers.Model
builder.Append(horseMarker); builder.Append(horseMarker);
builder.Append(new string('=', dashesBeforeHorse)); builder.Append(new string('=', dashesBeforeHorse));
int turnStep = 1; int turnStep = 0;
if (turnSteps.TryGetValue(horse, out int step)) if (turnSteps.TryGetValue(horse, out int step))
{ {
turnStep = step; turnStep = step;

View File

@ -75,6 +75,10 @@
{"练级信息", "查看练级进度"}, {"练级信息", "查看练级进度"},
{"生命之泉", "使用金币回复角色状态"}, {"生命之泉", "使用金币回复角色状态"},
{"酒馆", "使用钻石使角色获得满能量"}, {"酒馆", "使用钻石使角色获得满能量"},
{"排行榜/养成排行榜", "查看全服角色养成排行榜"},
{"金币排行榜", "查看全服金币数量排行榜"},
{"钻石排行榜", "查看全服钻石数量排行榜"},
{"赛马排行榜", "查看全服赛马积分排行榜"},
}; };
public static Dictionary<string, string> PlayHelp { get; } = new() { public static Dictionary<string, string> PlayHelp { get; } = new() {
@ -101,12 +105,12 @@
{"创建房间 <类型>", "类型mix/team/cooperative/horseracing对应混战/团队/共斗/赛马" }, {"创建房间 <类型>", "类型mix/team/cooperative/horseracing对应混战/团队/共斗/赛马" },
{"加入房间 <房间号>", "加入多人游戏房间" }, {"加入房间 <房间号>", "加入多人游戏房间" },
{"退出房间", "退出多人游戏房间" }, {"退出房间", "退出多人游戏房间" },
{"创建赛马", "快速创建赛马房间" },
{"开始游戏", "开始多人游戏" }, {"开始游戏", "开始多人游戏" },
{"加入赛马", "快速加入赛马房间" },
{"创建共斗", "快速创建共斗房间" },
{"创建混战", "快速创建混战房间" }, {"创建混战", "快速创建混战房间" },
{"创建团战", "快速创建团队死斗房间" }, {"创建团战", "快速创建团队死斗房间" },
{"创建共斗", "快速创建共斗房间" },
{"创建赛马", "快速创建赛马房间" },
{"加入赛马", "快速加入赛马房间" },
}; };
public static Dictionary<string, string> ClubHelp { get; } = new() { public static Dictionary<string, string> ClubHelp { get; } = new() {

View File

@ -1288,7 +1288,7 @@ namespace Oshima.FunGame.OshimaServers.Service
for (int i = 0; i < cardBox.Count; i++) for (int i = 0; i < cardBox.Count; i++)
{ {
Item newItem = GenerateMagicCard(item.QualityType); Item newItem = GenerateMagicCard(item.QualityType);
AddItemToUserInventory(user, newItem, false); AddItemToUserInventory(user, newItem, false, true);
cards.Add($"[{ItemSet.GetQualityTypeName(item.QualityType)}|魔法卡] {newItem.Name}\r\n{newItem.ToStringInventory(false)}"); cards.Add($"[{ItemSet.GetQualityTypeName(item.QualityType)}|魔法卡] {newItem.Name}\r\n{newItem.ToStringInventory(false)}");
} }
msg = "打开礼包成功!获得了以下物品:\r\n" + string.Join("\r\n", cards); msg = "打开礼包成功!获得了以下物品:\r\n" + string.Join("\r\n", cards);
@ -1564,7 +1564,7 @@ namespace Oshima.FunGame.OshimaServers.Service
} }
} }
private static void EnhanceBoss(Character boss, Item[] weapons, Item[] armors, Item[] shoes, Item[] accessory, Item[] consumables, public 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) int cLevel, int sLevel, int mLevel, int naLevel, bool enhanceHPMP = true, bool enhanceCRCRD = true, bool isUnit = false)
{ {
boss.Level = cLevel; boss.Level = cLevel;
@ -4570,9 +4570,19 @@ namespace Oshima.FunGame.OshimaServers.Service
{ {
FunGameConstant.UserLastVisitStore.Remove(user.Id); FunGameConstant.UserLastVisitStore.Remove(user.Id);
} }
// 排行榜更新
FunGameConstant.UserCreditsRanking[user.Id] = user.Inventory.Credits;
FunGameConstant.UserMaterialsRanking[user.Id] = user.Inventory.Materials;
FunGameConstant.UserEXPRanking[user.Id] = user.Inventory.Characters.Select(c => FunGameConstant.PrecomputeTotalExperience[c.Level] + c.EXP).Sum();
FunGameConstant.UserSkillRanking[user.Id] = user.Inventory.Characters.Select(c => (c.NormalAttack.Level - 1) * 50000 + c.Skills.Select(s => s.Level * 40000).Sum()).Sum();
if (pc.TryGetValue("horseRacingPoints", out object? value3) && int.TryParse(value3.ToString(), out int horseRacingPoints))
{
FunGameConstant.UserHorseRacingRanking[user.Id] = horseRacingPoints;
}
} }
ReleaseUserSemaphoreSlim(fileName); ReleaseUserSemaphoreSlim(fileName);
} }
FunGameConstant.RankingUpdateTime = DateTime.Now;
} }
} }

View File

@ -10,6 +10,7 @@ namespace Oshima.FunGame.OshimaServers.Service
{ {
public static SemaphoreSlim RoomSemaphoreSlim { get; } = new(1, 1); public static SemaphoreSlim RoomSemaphoreSlim { get; } = new(1, 1);
public static SemaphoreSlim HorseRacingSettleSemaphoreSlim { get; } = new(1, 1); public static SemaphoreSlim HorseRacingSettleSemaphoreSlim { get; } = new(1, 1);
public static SemaphoreSlim CooperativeSettleSemaphoreSlim { get; } = new(1, 1);
public static Dictionary<string, bool> GroupsHasHorseRacing { get; } = []; public static Dictionary<string, bool> GroupsHasHorseRacing { get; } = [];
public static void GetRoomSemaphoreSlim() public static void GetRoomSemaphoreSlim()
@ -38,6 +39,19 @@ namespace Oshima.FunGame.OshimaServers.Service
} }
} }
public static void GetCooperativeSettleSemaphoreSlim()
{
CooperativeSettleSemaphoreSlim.Wait(FunGameConstant.SemaphoreSlimTimeout);
}
public static void ReleaseCooperativeSettleSemaphoreSlim()
{
if (CooperativeSettleSemaphoreSlim.CurrentCount == 0)
{
CooperativeSettleSemaphoreSlim.Release();
}
}
public static Room CreateRoom(User user, string roomType, string password, string groupId, out string msg) public static Room CreateRoom(User user, string roomType, string password, string groupId, out string msg)
{ {
try try
@ -57,12 +71,13 @@ namespace Oshima.FunGame.OshimaServers.Service
case "horseracing": case "horseracing":
if (GroupsHasHorseRacing.TryGetValue(groupId, out bool has) && has) if (GroupsHasHorseRacing.TryGetValue(groupId, out bool has) && has)
{ {
msg = "本群已经存在一个赛马房间!空闲房间会在 6 分钟后自动解散,请先等待该房间完成比赛或自动解散。"; msg = $"本群已经存在一个赛马房间!空闲房间会在 {FunGameConstant.RoomExpireTime} 分钟后自动解散,请先等待该房间完成比赛或自动解散。";
} }
else else
{ {
room.RoomType = RoomType.Custom; room.RoomType = RoomType.Custom;
room.Name = "赛马房间"; room.Name = "赛马房间";
room.GameModule = "horseracing";
room.GameMap = groupId; room.GameMap = groupId;
room.MaxUsers = 8; room.MaxUsers = 8;
} }
@ -70,16 +85,22 @@ namespace Oshima.FunGame.OshimaServers.Service
case "mix": case "mix":
room.RoomType = RoomType.Mix; room.RoomType = RoomType.Mix;
room.Name = "混战房间"; room.Name = "混战房间";
room.GameModule = "mix";
room.GameMap = groupId;
room.MaxUsers = 10; room.MaxUsers = 10;
break; break;
case "team": case "team":
room.RoomType = RoomType.Team; room.RoomType = RoomType.Team;
room.Name = "团队死斗房间"; room.Name = "团队死斗房间";
room.GameModule = "team";
room.GameMap = groupId;
room.MaxUsers = 8; room.MaxUsers = 8;
break; break;
case "cooperative": case "cooperative":
room.RoomType = RoomType.Custom; room.RoomType = RoomType.Custom;
room.Name = "共斗房间"; room.Name = "共斗房间";
room.GameModule = "cooperative";
room.GameMap = groupId;
room.MaxUsers = 4; room.MaxUsers = 4;
break; break;
default: default:
@ -98,14 +119,14 @@ namespace Oshima.FunGame.OshimaServers.Service
} }
room.Roomid = Verification.CreateVerifyCode(VerifyCodeType.MixVerifyCode, 7); room.Roomid = Verification.CreateVerifyCode(VerifyCodeType.MixVerifyCode, 7);
} }
msg = $"房间创建成功,房间号为:{room.Roomid}\r\n注意房间若在 6 分钟后仍处于空闲状态,将自动解散。"; msg = $"房间创建成功,房间号为:{room.Roomid}\r\n注意房间若在 {FunGameConstant.RoomExpireTime} 分钟后仍处于空闲状态,将自动解散。";
room.RoomMaster = user; room.RoomMaster = user;
room.CreateTime = DateTime.Now; room.CreateTime = DateTime.Now;
} }
if (room.Roomid != "-1") if (room.Roomid != "-1")
{ {
FunGameConstant.Rooms[room.Roomid] = room; FunGameConstant.Rooms[room.Roomid] = room;
if (room.Name == "赛马房间") if (room.GameModule == "horseracing")
{ {
GroupsHasHorseRacing[room.GameMap] = true; GroupsHasHorseRacing[room.GameMap] = true;
} }
@ -203,7 +224,7 @@ namespace Oshima.FunGame.OshimaServers.Service
{ {
FunGameConstant.Rooms.Remove(room.Roomid); FunGameConstant.Rooms.Remove(room.Roomid);
msg += ",该房间人数为零,已解散该房间。"; msg += ",该房间人数为零,已解散该房间。";
if (room.Name == "赛马房间") if (room.GameModule == "horseracing")
{ {
GroupsHasHorseRacing[room.GameMap] = false; GroupsHasHorseRacing[room.GameMap] = false;
} }
@ -239,6 +260,34 @@ namespace Oshima.FunGame.OshimaServers.Service
} }
} }
public static string RoomInfo(User user)
{
string msg = "";
if (FunGameConstant.UsersInRoom.TryGetValue(user.Id, out Room? room) && room != null)
{
string username = "";
if (FunGameConstant.UserIdAndUsername.TryGetValue(room.RoomMaster.Id, out User? value) && value != null)
{
username = value.Username;
}
List<string> users = [];
foreach (long uid in room.UserAndIsReady.Keys.Select(u => u.Id))
{
if (FunGameConstant.UserIdAndUsername.TryGetValue(uid, out value) && value != null)
{
users.Add(value.Username);
}
}
msg += $"☆--- [ {room.Roomid} ] ---☆\r\n房间类型{room.Name}\r\n创建时间{room.CreateTime.ToString(General.GeneralDateTimeFormatChinese)}\r\n房主{username}\r\n" +
$"人数:{room.UserAndIsReady.Count} / {room.MaxUsers}\r\n在线玩家{string.Join("", users)}\r\n该房间将于 {room.CreateTime.AddMinutes(FunGameConstant.RoomExpireTime).ToString(General.GeneralDateTimeFormatChinese)} 后自动解散,请尽快开局";
}
else
{
msg = "你当前不在任何房间中。";
}
return msg;
}
public static void RoomsAutoDisband() public static void RoomsAutoDisband()
{ {
try try
@ -247,14 +296,14 @@ namespace Oshima.FunGame.OshimaServers.Service
Room[] rooms = [.. FunGameConstant.Rooms.Values]; Room[] rooms = [.. FunGameConstant.Rooms.Values];
foreach (Room room in rooms) foreach (Room room in rooms)
{ {
if (room.RoomState == RoomState.Created && room.CreateTime.AddMinutes(6) < DateTime.Now) if (room.RoomState == RoomState.Created && room.CreateTime.AddMinutes(FunGameConstant.RoomExpireTime) < DateTime.Now)
{ {
foreach (User user in room.UserAndIsReady.Keys) foreach (User user in room.UserAndIsReady.Keys)
{ {
FunGameConstant.UsersInRoom.Remove(user.Id); FunGameConstant.UsersInRoom.Remove(user.Id);
} }
FunGameConstant.Rooms.Remove(room.Roomid); FunGameConstant.Rooms.Remove(room.Roomid);
if (room.Name == "赛马房间") if (room.GameModule == "horseracing")
{ {
GroupsHasHorseRacing[room.GameMap] = false; GroupsHasHorseRacing[room.GameMap] = false;
} }
@ -308,7 +357,7 @@ namespace Oshima.FunGame.OshimaServers.Service
FunGameConstant.UsersInRoom.Remove(userTemp.Id); FunGameConstant.UsersInRoom.Remove(userTemp.Id);
} }
FunGameConstant.Rooms.Remove(room.Roomid); FunGameConstant.Rooms.Remove(room.Roomid);
if (room.Name == "赛马房间") if (room.GameModule == "horseracing")
{ {
GroupsHasHorseRacing[room.GameMap] = false; GroupsHasHorseRacing[room.GameMap] = false;
} }
@ -320,9 +369,9 @@ namespace Oshima.FunGame.OshimaServers.Service
else else
{ {
room.RoomState = RoomState.Gaming; room.RoomState = RoomState.Gaming;
switch (room.Name) switch (room.GameModule)
{ {
case "赛马房间": case "horseracing":
try try
{ {
GetHorseRacingSettleSemaphoreSlim(); GetHorseRacingSettleSemaphoreSlim();
@ -354,6 +403,22 @@ namespace Oshima.FunGame.OshimaServers.Service
ReleaseHorseRacingSettleSemaphoreSlim(); ReleaseHorseRacingSettleSemaphoreSlim();
} }
break; break;
case "cooperative":
try
{
GetCooperativeSettleSemaphoreSlim();
await Cooperative.RunCooperativeGame(msgs, room);
}
catch (Exception e2)
{
msgs.Add("Error: " + e2.Message);
}
finally
{
ReleaseCooperativeSettleSemaphoreSlim();
}
room.CreateTime = DateTime.Now;
break;
default: default:
msgs.Add("游戏已开始!"); msgs.Add("游戏已开始!");
await Task.Delay(5000); await Task.Delay(5000);

View File

@ -4471,7 +4471,7 @@ namespace Oshima.FunGame.WebAPI.Controllers
pc.Add("days", days + 1); pc.Add("days", days + 1);
pc.Add("lastTime", newLastTime); pc.Add("lastTime", newLastTime);
FunGameService.SetUserConfigAndReleaseSemaphoreSlim(userid, pc, user); FunGameService.SetUserConfigAndReleaseSemaphoreSlim(userid, pc, user);
return msg + "\r\n>>> 请发送【帮助】来获取更多玩法指令!<<<"; return msg + "\r\n提示:发送【帮助】来获取更多玩法指令!";
} }
else else
{ {
@ -8108,6 +8108,43 @@ namespace Oshima.FunGame.WebAPI.Controllers
} }
} }
[HttpPost("roominfo")]
public string RoomInfo([FromQuery] long uid = -1)
{
try
{
PluginConfig pc = FunGameService.GetUserConfig(uid, out bool isTimeout);
if (isTimeout)
{
return busy;
}
string msg = "";
if (pc.Count > 0)
{
User user = FunGameService.GetUser(pc);
msg = OnlineService.RoomInfo(user);
FunGameService.SetUserConfigButNotRelease(uid, pc, user);
return msg;
}
else
{
return noSaved;
}
}
catch (Exception e)
{
Logger.LogError(e, "Error: {e}", e);
return busy;
}
finally
{
FunGameService.ReleaseUserSemaphoreSlim(uid);
}
}
[HttpPost("rungame")] [HttpPost("rungame")]
public async Task<(Room, List<string>)> RunGame([FromQuery] long uid = -1) public async Task<(Room, List<string>)> RunGame([FromQuery] long uid = -1)
{ {
@ -8124,10 +8161,10 @@ namespace Oshima.FunGame.WebAPI.Controllers
if (pc.Count > 0) if (pc.Count > 0)
{ {
User user = FunGameService.GetUser(pc); User user = FunGameService.GetUser(pc);
FunGameService.SetUserConfigButNotRelease(uid, pc, user);
(room, msgs) = await OnlineService.RunGameAsync(user); (room, msgs) = await OnlineService.RunGameAsync(user);
FunGameService.SetUserConfigButNotRelease(uid, pc, user);
return (room, msgs); return (room, msgs);
} }
else else
@ -8146,6 +8183,116 @@ namespace Oshima.FunGame.WebAPI.Controllers
} }
} }
[HttpGet("getranking")]
public string GetRanking([FromQuery] long uid = -1, [FromQuery] int type = -1)
{
try
{
PluginConfig pc = FunGameService.GetUserConfig(uid, out bool isTimeout);
if (isTimeout)
{
return busy;
}
string msg = "";
int currentTop = -1;
int showTop = 20;
if (pc.Count > 0)
{
User user = FunGameService.GetUser(pc);
msg = type switch
{
0 => $"【{General.GameplayEquilibriumConstant.InGameCurrency}排行榜】\r\n" +
$"数据每分钟更新一次,上次更新:{FunGameConstant.RankingUpdateTime.ToString(General.GeneralDateTimeFormatChinese)}\r\n" +
$"\r\n{(FunGameConstant.UserCreditsRanking.Count > 0 ? string.Join("\r\n", FunGameConstant.UserCreditsRanking.
OrderByDescending(kv => kv.Value).Take(showTop).Select((kv, index) =>
{
string username = "Unknown";
if (FunGameConstant.UserIdAndUsername.TryGetValue(kv.Key, out User? value) && value != null)
{
username = value.Username;
}
if (kv.Key == user.Id)
{
currentTop = index + 1;
}
return $"{index + 1}. UID{kv.Key},昵称:{username}{General.GameplayEquilibriumConstant.InGameCurrency}{kv.Value:0.##}";
})) : "暂无任何数据。")}\r\n\r\n仅显示前 {showTop} {(currentTop > 0 ? $",你目前排在第 {currentTop} 位。" : "")}",
1 => $"【{General.GameplayEquilibriumConstant.InGameMaterial}排行榜】\r\n" +
$"数据每分钟更新一次,上次更新:{FunGameConstant.RankingUpdateTime.ToString(General.GeneralDateTimeFormatChinese)}\r\n" +
$"\r\n{(FunGameConstant.UserMaterialsRanking.Count > 0 ? string.Join("\r\n", FunGameConstant.UserMaterialsRanking.
OrderByDescending(kv => kv.Value).Take(showTop).Select((kv, index) =>
{
string username = "Unknown";
if (FunGameConstant.UserIdAndUsername.TryGetValue(kv.Key, out User? value) && value != null)
{
username = value.Username;
}
if (kv.Key == user.Id)
{
currentTop = index + 1;
}
return $"{index + 1}. UID{kv.Key},昵称:{username}{General.GameplayEquilibriumConstant.InGameMaterial}{kv.Value:0.##}";
})) : "暂无任何数据。")}\r\n\r\n仅显示前 {showTop} {(currentTop > 0 ? $",你目前排在第 {currentTop} 位。" : "")}",
2 => $"【角色养成排行榜】\r\n" +
$"数据每分钟更新一次,上次更新:{FunGameConstant.RankingUpdateTime.ToString(General.GeneralDateTimeFormatChinese)}\r\n" +
$"\r\n{(FunGameConstant.UserEXPRanking.Count > 0 ? string.Join("\r\n", FunGameConstant.UserEXPRanking.
OrderByDescending(kv => kv.Value).Take(showTop).Select((kv, index) =>
{
string username = "Unknown";
if (FunGameConstant.UserIdAndUsername.TryGetValue(kv.Key, out User? value) && value != null)
{
username = value.Username;
}
if (kv.Key == user.Id)
{
currentTop = index + 1;
}
double score = kv.Value;
if (FunGameConstant.UserSkillRanking.TryGetValue(kv.Key, out double value2))
{
score += value2;
}
return $"{index + 1}. UID{kv.Key},昵称:{username},总得分:{score:0.##}";
})) : "暂无任何数据。")}\r\n\r\n本榜单统计角色的经验值总额\r\n仅显示前 {showTop} {(currentTop > 0 ? $",你目前排在第 {currentTop} 位。" : "")}",
3 => $"【赛马积分排行榜】\r\n" +
$"数据每分钟更新一次,上次更新:{FunGameConstant.RankingUpdateTime.ToString(General.GeneralDateTimeFormatChinese)}\r\n" +
$"\r\n{(FunGameConstant.UserHorseRacingRanking.Count > 0 ? string.Join("\r\n", FunGameConstant.UserHorseRacingRanking.
OrderByDescending(kv => kv.Value).Take(showTop).Select((kv, index) =>
{
string username = "Unknown";
if (FunGameConstant.UserIdAndUsername.TryGetValue(kv.Key, out User? value) && value != null)
{
username = value.Username;
}
if (kv.Key == user.Id)
{
currentTop = index + 1;
}
return $"{index + 1}. UID{kv.Key},昵称:{username},赛马积分:{kv.Value}";
})) : "暂无任何数据。")}\r\n\r\n仅显示前 {showTop} {(currentTop > 0 ? $",你目前排在第 {currentTop} 位。" : "")}",
_ => "不支持的查询。",
};
FunGameService.SetUserConfigButNotRelease(uid, pc, user);
return msg;
}
else
{
return noSaved;
}
}
catch (Exception e)
{
Logger.LogError(e, "Error: {e}", e);
return busy;
}
finally
{
FunGameService.ReleaseUserSemaphoreSlim(uid);
}
}
[HttpPost("template")] [HttpPost("template")]
public string Template([FromQuery] long uid = -1) public string Template([FromQuery] long uid = -1)
{ {

View File

@ -3314,6 +3314,84 @@ namespace Oshima.FunGame.WebAPI.Services
return result; return result;
} }
if (e.Detail == "创建共斗")
{
string groupId = "";
if (e.IsGroup && e is GroupAtMessage groupAtMessage && groupAtMessage.GroupOpenId != "")
{
groupId = groupAtMessage.GroupOpenId;
}
else if (e.IsGroup && e is ThirdPartyMessage thirdPartyMessage && thirdPartyMessage.GroupOpenId != "")
{
groupId = thirdPartyMessage.GroupOpenId;
}
if (groupId != "")
{
string msg = Controller.CreateRoom(uid, "cooperative", "", groupId);
if (msg.Trim() != "")
{
await SendAsync(e, "房间", msg);
}
}
else
{
await SendAsync(e, "房间", "请在群聊中进行多人游戏。");
}
return result;
}
if (e.Detail == "创建混战")
{
string groupId = "";
if (e.IsGroup && e is GroupAtMessage groupAtMessage && groupAtMessage.GroupOpenId != "")
{
groupId = groupAtMessage.GroupOpenId;
}
else if (e.IsGroup && e is ThirdPartyMessage thirdPartyMessage && thirdPartyMessage.GroupOpenId != "")
{
groupId = thirdPartyMessage.GroupOpenId;
}
if (groupId != "")
{
string msg = Controller.CreateRoom(uid, "mix", "", groupId);
if (msg.Trim() != "")
{
await SendAsync(e, "房间", msg);
}
}
else
{
await SendAsync(e, "房间", "请在群聊中进行多人游戏。");
}
return result;
}
if (e.Detail == "创建团战")
{
string groupId = "";
if (e.IsGroup && e is GroupAtMessage groupAtMessage && groupAtMessage.GroupOpenId != "")
{
groupId = groupAtMessage.GroupOpenId;
}
else if (e.IsGroup && e is ThirdPartyMessage thirdPartyMessage && thirdPartyMessage.GroupOpenId != "")
{
groupId = thirdPartyMessage.GroupOpenId;
}
if (groupId != "")
{
string msg = Controller.CreateRoom(uid, "team", "", groupId);
if (msg.Trim() != "")
{
await SendAsync(e, "房间", msg);
}
}
else
{
await SendAsync(e, "房间", "请在群聊中进行多人游戏。");
}
return result;
}
if (e.Detail == "加入赛马") if (e.Detail == "加入赛马")
{ {
string groupId = ""; string groupId = "";
@ -3436,11 +3514,7 @@ namespace Oshima.FunGame.WebAPI.Services
} }
if (groupId != "") if (groupId != "")
{ {
if (e.Detail == "开始赛马" && FunGameConstant.UsersInRoom.TryGetValue(uid, out Room? value) && value != null && value.Name == "赛马房间") if (e.Detail == "开始赛马" && (!FunGameConstant.UsersInRoom.TryGetValue(uid, out Room? value) || value is null || value.Name != "赛马房间"))
{
// do nothing
}
else
{ {
await SendAsync(e, "房间", "你不在房间中或者所在的房间不是赛马房间,请使用【开始游戏】指令。注意:只有房主才可以开始游戏。"); await SendAsync(e, "房间", "你不在房间中或者所在的房间不是赛马房间,请使用【开始游戏】指令。注意:只有房主才可以开始游戏。");
return result; return result;
@ -3521,6 +3595,56 @@ namespace Oshima.FunGame.WebAPI.Services
return result; return result;
} }
if (e.Detail == "房间信息")
{
string msg = Controller.RoomInfo(uid);
if (msg.Trim() != "")
{
await SendAsync(e, "房间", msg);
}
return result;
}
if (e.Detail == "排行榜" || e.Detail == "养成排行榜")
{
string msg = Controller.GetRanking(uid, 2);
if (msg.Trim() != "")
{
await SendAsync(e, "排行榜", msg);
}
return result;
}
if (e.Detail == $"{General.GameplayEquilibriumConstant.InGameCurrency}排行榜")
{
string msg = Controller.GetRanking(uid, 0);
if (msg.Trim() != "")
{
await SendAsync(e, "排行榜", msg);
}
return result;
}
if (e.Detail == $"{General.GameplayEquilibriumConstant.InGameMaterial}排行榜")
{
string msg = Controller.GetRanking(uid, 1);
if (msg.Trim() != "")
{
await SendAsync(e, "排行榜", msg);
}
return result;
}
if (e.Detail == $"赛马排行榜")
{
string msg = Controller.GetRanking(uid, 3);
if (msg.Trim() != "")
{
await SendAsync(e, "排行榜", msg);
}
return result;
}
if (uid == GeneralSettings.Master && e.Detail.StartsWith("重载FunGame", StringComparison.CurrentCultureIgnoreCase)) if (uid == GeneralSettings.Master && e.Detail.StartsWith("重载FunGame", StringComparison.CurrentCultureIgnoreCase))
{ {
string msg = Controller.Relaod(uid); string msg = Controller.Relaod(uid);