169 lines
5.7 KiB
C#
169 lines
5.7 KiB
C#
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<DataValue> _values;
|
||
|
||
public DataRow(string name,
|
||
IEnumerable<string> 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<DataRow> 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<int>();
|
||
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<DataRow>
|
||
{
|
||
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;
|
||
}
|
||
}
|
||
}
|