using AnotherReplayReader.ReplayFile; using System; using System.Collections.Generic; using System.Linq; namespace AnotherReplayReader.Apm { internal class DataRow { public const string AverageApmRow = "APM(整局游戏)"; public const string PartialApmRow = "APM(当前时间段)"; public string Name { get; } public bool IsDisabled { get; } public DataValue Player1Value => _values[0]; public DataValue Player2Value => _values[1]; public DataValue Player3Value => _values[2]; public DataValue Player4Value => _values[3]; public DataValue Player5Value => _values[4]; public DataValue Player6Value => _values[5]; private readonly IReadOnlyList _values; public DataRow(string name, IEnumerable values, bool isDisabled = false) { Name = name; IsDisabled = isDisabled; if (values.Count() < 6) { values = values.Concat(new string[6 - values.Count()]); } _values = values.Select(x => new DataValue(x)).ToArray(); } public static List GetList(ApmPlotter plotter, ApmPlotterFilterOptions options, TimeSpan begin, TimeSpan end, out int apmRowIndex) { // these commands should appear in this order by default var orderedCommands = new List(); orderedCommands.AddRange( [ 0x1F5, // 选择 0x1F6, 0x1F8, 0x1F9, 0x22A, 0x1FA, // 编队 0x1FB, 0x1FC, 0x207, // 生产/建造 0x208, 0x205, 0x206, 0x209, // 摆放 0x20A, // 出售 0x203, // 升级 0x204, 0x20D, // 右键攻击 0x20E, // 强A 0x20F, // 强A 0x215, // 移动攻击 0x214, // 移动 0x236, // 倒车 0x216, // 碾压 0x22C, // 队形 0x21A, // 停止 0x21B, // 散开 0x24E, // 选择协议 0x1FE, // 释放特殊能力 0x1FF, 0x200, 0x201, 0x232, 0x22E, // 姿态 0x22F, // 计划模式 0x228, // 维修 0x229, 0x202, // 集结点 0x210, // 进驻建筑 0x20C, // 从建筑中撤出 0x248, // 采矿交矿 0x212, 0x24B, // 信标 0x24C, 0x24D, 0x1, // 退出地图 ]); orderedCommands.AddRange(RA3Commands.AutoCommands); orderedCommands.AddRange(RA3Commands.UnknownCommands); var dataList = new List { new("ID", plotter.PlayersArray.Select(x => x.PlayerName)) }; var isPartial = begin > TimeSpan.Zero || end <= plotter.ReplayLength; if (isPartial) { string GetStatus(Player player, int i) { if (player.IsComputer) { return "这是 AI"; } if (begin < plotter.StricterPlayerLifes[i]) { return "存活"; } return begin < plotter.PlayerLifes[i] ? "变身天眼帝国,或双手离开键盘" : "可能已离开房间"; } dataList.Add(new("存活状态(推测)", plotter.PlayersArray.Select(GetStatus))); } apmRowIndex = dataList.Count; // kill-death ratio if (plotter.Replay.Footer?.TryGetKillDeathRatios() is { } kdRatios) { var texts = kdRatios .Take(plotter.PlayersArray.Length) .Select(x => $"{x:0.##}"); dataList.Add(new("击杀阵亡比(存疑)", texts)); } // get commands var commandCounts = plotter.GetCommandCounts(begin, end); // add commands in the order specified by the list foreach (var command in orderedCommands) { var counts = commandCounts.TryGetValue(command, out var stored) ? stored : new int[plotter.PlayersArray.Length]; if (!isPartial || counts.Any(x => x > 0)) { dataList.Add(new(RA3Commands.GetCommandName(command), counts.Select(x => $"{x}"), options.ShouldSkip(command))); } commandCounts.Remove(command); } // add other commands foreach (var commandCount in commandCounts) { dataList.Add(new(RA3Commands.GetCommandName(commandCount.Key), commandCount.Value.Select(x => $"{x}"), options.ShouldSkip(commandCount.Key))); } return dataList; } } }