using System; using System.Collections.Generic; using System.Linq; using CommonDomain; using CommonDomain.BaseModel; using CommonDomain.Enum; using UserDomain.Entity; namespace RedisService.Param { public static class RoomBotFactory { public static readonly int[] FixedBotSeats = Array.Empty(); public static bool FixedBotSeatsEnabled => FixedBotSeats.Length > 0; /// 基础默认炮台(与 UserService.UnloadCannon 中一致) public const string DefaultCannonNumber = "11001"; /// 机器人初始等级范围 public const int MinBotLevel = 1; public const int MaxBotLevel = 15; /// 机器人初始 VIP 等级范围 public const int MinBotVipLevel = 0; public const int MaxBotVipLevel = 5; public static RedisGamePlayer CreateBot(int position, RoomConfig roomConfig, GameConfig gameConfig, IReadOnlyList botProfiles) { if (roomConfig?.CannonMultipleList == null || roomConfig.CannonMultipleList.Count == 0 || botProfiles == null || botProfiles.Count == 0) return null; var profile = botProfiles[System.Random.Shared.Next(botProfiles.Count)]; var maxMultiple = roomConfig.CannonMultipleList.Max(); var gold = maxMultiple * System.Random.Shared.Next(100, 501); var botId = Guid.NewGuid().ToString("N"); var botNumber = Common.Utils.RandomHelper.RandomNumbers(8); var bot = new RedisGamePlayer { UserId = botId, UserNumber = botNumber, UserName = profile.Name, Avatar = profile.Avatar, IsBot = true, Gold = gold, Diamond = System.Random.Shared.Next(100, 5001), Position = position, CannonMultiple = roomConfig.CannonMultipleList[System.Random.Shared.Next(roomConfig.CannonMultipleList.Count)], BeginCoin = gold, BeginTime = new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds(), CId = string.Empty, State = 0, PlayerFactor = new PlayerFactor() }; ApplyBotBaseValues(bot, gameConfig); return bot; } /// /// 设置机器人基础值:等级 1~15、VIP 0~5、经验与等级对应、炮台 30% 非默认 / 70% 默认、 /// 翅膀 15%、战神 5%。三处创建机器人的入口共用,避免取值不一致。 /// public static void ApplyBotBaseValues(RedisGamePlayer bot, GameConfig gameConfig) { if (bot == null) return; var levelConfigs = gameConfig?.UserLevelConfigs ?? new List(); var inRangeLevels = levelConfigs .Where(c => c != null && c.Level >= MinBotLevel && c.Level <= MaxBotLevel) .ToList(); var levelCfg = inRangeLevels.Count > 0 ? inRangeLevels[System.Random.Shared.Next(inRangeLevels.Count)] : null; bot.Level = levelCfg?.Level ?? MinBotLevel; bot.MaxExp = levelCfg?.ExpMax ?? 0; bot.Exp = levelCfg == null || levelCfg.ExpMax <= levelCfg.ExpMin ? (levelCfg?.ExpMin ?? 0) : System.Random.Shared.NextInt64(levelCfg.ExpMin, levelCfg.ExpMax); bot.VipLevel = System.Random.Shared.Next(MinBotVipLevel, MaxBotVipLevel + 1); var props = gameConfig?.PropConfig ?? new List(); var cannons = props.Where(p => p.Type == ProductTypeEnum.炮台 && p.IsEnable && !p.Number.StartsWith("401")).ToList(); var wings = props.Where(p => p.Type == ProductTypeEnum.翅膀 && p.IsEnable && p.IsSale).ToList(); var warGods = props.Where(p => p.Type == ProductTypeEnum.战神 && p.IsEnable && p.IsSale).ToList(); var nonDefaultCannons = cannons.Where(c => c.Number != DefaultCannonNumber).ToList(); bot.CannonId = System.Random.Shared.Next(100) < 30 && nonDefaultCannons.Count > 0 ? nonDefaultCannons[System.Random.Shared.Next(nonDefaultCannons.Count)].Number : DefaultCannonNumber; bot.WingsId = wings.Count > 0 && System.Random.Shared.Next(100) < 15 ? wings[System.Random.Shared.Next(wings.Count)].Number : string.Empty; bot.WarGodId = warGods.Count > 0 && System.Random.Shared.Next(100) < 5 ? warGods[System.Random.Shared.Next(warGods.Count)].Number : string.Empty; } public static List CreateFixedSeatBots(RedisGameRoom room, RoomConfig roomConfig, GameConfig gameConfig, IReadOnlyList botProfiles, IReadOnlyList fixedSeats = null) { var result = new List(); if (room == null) return result; fixedSeats ??= FixedBotSeats; if (fixedSeats.Count == 0) return result; room.Players ??= new List(); foreach (var seat in fixedSeats.Distinct()) { if (seat < 0 || seat >= room.MaxPlayerCount) continue; if (room.Players.Any(p => p.Position == seat)) continue; var bot = CreateBot(seat, roomConfig, gameConfig, botProfiles); if (bot != null) result.Add(bot); } return result; } } }