mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 09:18:27 -04:00
Global usings and file scoped namespaces
This commit is contained in:
@@ -1,327 +1,321 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Modules.Searches.Common;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
|
||||
namespace NadekoBot.Modules.Searches
|
||||
namespace NadekoBot.Modules.Searches;
|
||||
|
||||
public partial class Searches
|
||||
{
|
||||
public partial class Searches
|
||||
[Group]
|
||||
public class OsuCommands : NadekoSubmodule
|
||||
{
|
||||
[Group]
|
||||
public class OsuCommands : NadekoSubmodule
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
|
||||
public OsuCommands(IBotCredentials creds, IHttpClientFactory factory)
|
||||
{
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
_creds = creds;
|
||||
_httpFactory = factory;
|
||||
}
|
||||
|
||||
public OsuCommands(IBotCredentials creds, IHttpClientFactory factory)
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task Osu(string user, [Leftover] string mode = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(user))
|
||||
return;
|
||||
|
||||
using (var http = _httpFactory.CreateClient())
|
||||
{
|
||||
_creds = creds;
|
||||
_httpFactory = factory;
|
||||
}
|
||||
var modeNumber = string.IsNullOrWhiteSpace(mode)
|
||||
? 0
|
||||
: ResolveGameMode(mode);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task Osu(string user, [Leftover] string mode = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(user))
|
||||
return;
|
||||
|
||||
using (var http = _httpFactory.CreateClient())
|
||||
try
|
||||
{
|
||||
var modeNumber = string.IsNullOrWhiteSpace(mode)
|
||||
? 0
|
||||
: ResolveGameMode(mode);
|
||||
|
||||
try
|
||||
if (string.IsNullOrWhiteSpace(_creds.OsuApiKey))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_creds.OsuApiKey))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.osu_api_key).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var smode = ResolveGameMode(modeNumber);
|
||||
var userReq = $"https://osu.ppy.sh/api/get_user?k={_creds.OsuApiKey}&u={user}&m={modeNumber}";
|
||||
var userResString = await http.GetStringAsync(userReq)
|
||||
.ConfigureAwait(false);
|
||||
var objs = JsonConvert.DeserializeObject<List<OsuUserData>>(userResString);
|
||||
|
||||
if (objs.Count == 0)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.osu_user_not_found).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = objs[0];
|
||||
var userId = obj.UserId;
|
||||
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle($"osu! {smode} profile for {user}")
|
||||
.WithThumbnailUrl($"https://a.ppy.sh/{userId}")
|
||||
.WithDescription($"https://osu.ppy.sh/u/{userId}")
|
||||
.AddField("Official Rank", $"#{obj.PpRank}", true)
|
||||
.AddField("Country Rank", $"#{obj.PpCountryRank} :flag_{obj.Country.ToLower()}:", true)
|
||||
.AddField("Total PP", Math.Round(obj.PpRaw, 2), true)
|
||||
.AddField("Accuracy", Math.Round(obj.Accuracy, 2) + "%", true)
|
||||
.AddField("Playcount", obj.Playcount, true)
|
||||
.AddField("Level", Math.Round(obj.Level), true)
|
||||
);
|
||||
await ReplyErrorLocalizedAsync(strs.osu_api_key).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.osu_user_not_found).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.osu_failed).ConfigureAwait(false);
|
||||
Log.Warning(ex, "Osu command failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task Gatari(string user, [Leftover] string mode = null)
|
||||
{
|
||||
using (var http = _httpFactory.CreateClient())
|
||||
{
|
||||
var modeNumber = string.IsNullOrWhiteSpace(mode)
|
||||
? 0
|
||||
: ResolveGameMode(mode);
|
||||
|
||||
var modeStr = ResolveGameMode(modeNumber);
|
||||
var resString = await http
|
||||
.GetStringAsync($"https://api.gatari.pw/user/stats?u={user}&mode={modeNumber}")
|
||||
var smode = ResolveGameMode(modeNumber);
|
||||
var userReq = $"https://osu.ppy.sh/api/get_user?k={_creds.OsuApiKey}&u={user}&m={modeNumber}";
|
||||
var userResString = await http.GetStringAsync(userReq)
|
||||
.ConfigureAwait(false);
|
||||
var objs = JsonConvert.DeserializeObject<List<OsuUserData>>(userResString);
|
||||
|
||||
var statsResponse = JsonConvert.DeserializeObject<GatariUserStatsResponse>(resString);
|
||||
if (statsResponse.Code != 200 || statsResponse.Stats.Id == 0)
|
||||
if (objs.Count == 0)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.osu_user_not_found).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var usrResString = await http.GetStringAsync($"https://api.gatari.pw/users/get?u={user}")
|
||||
.ConfigureAwait(false);
|
||||
var obj = objs[0];
|
||||
var userId = obj.UserId;
|
||||
|
||||
var userData = JsonConvert.DeserializeObject<GatariUserResponse>(usrResString).Users[0];
|
||||
var userStats = statsResponse.Stats;
|
||||
|
||||
var embed = _eb.Create()
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle($"osu!Gatari {modeStr} profile for {user}")
|
||||
.WithThumbnailUrl($"https://a.gatari.pw/{userStats.Id}")
|
||||
.WithDescription($"https://osu.gatari.pw/u/{userStats.Id}")
|
||||
.AddField("Official Rank", $"#{userStats.Rank}", true)
|
||||
.AddField("Country Rank", $"#{userStats.CountryRank} :flag_{userData.Country.ToLower()}:", true)
|
||||
.AddField("Total PP", userStats.Pp, true)
|
||||
.AddField("Accuracy", $"{Math.Round(userStats.AvgAccuracy, 2)}%", true)
|
||||
.AddField("Playcount", userStats.Playcount, true)
|
||||
.AddField("Level", userStats.Level, true);
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
.WithTitle($"osu! {smode} profile for {user}")
|
||||
.WithThumbnailUrl($"https://a.ppy.sh/{userId}")
|
||||
.WithDescription($"https://osu.ppy.sh/u/{userId}")
|
||||
.AddField("Official Rank", $"#{obj.PpRank}", true)
|
||||
.AddField("Country Rank", $"#{obj.PpCountryRank} :flag_{obj.Country.ToLower()}:", true)
|
||||
.AddField("Total PP", Math.Round(obj.PpRaw, 2), true)
|
||||
.AddField("Accuracy", Math.Round(obj.Accuracy, 2) + "%", true)
|
||||
.AddField("Playcount", obj.Playcount, true)
|
||||
.AddField("Level", Math.Round(obj.Level), true)
|
||||
);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.osu_user_not_found).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.osu_failed).ConfigureAwait(false);
|
||||
Log.Warning(ex, "Osu command failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task Osu5(string user, [Leftover] string mode = null)
|
||||
{;
|
||||
if (string.IsNullOrWhiteSpace(_creds.OsuApiKey))
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task Gatari(string user, [Leftover] string mode = null)
|
||||
{
|
||||
using (var http = _httpFactory.CreateClient())
|
||||
{
|
||||
var modeNumber = string.IsNullOrWhiteSpace(mode)
|
||||
? 0
|
||||
: ResolveGameMode(mode);
|
||||
|
||||
var modeStr = ResolveGameMode(modeNumber);
|
||||
var resString = await http
|
||||
.GetStringAsync($"https://api.gatari.pw/user/stats?u={user}&mode={modeNumber}")
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var statsResponse = JsonConvert.DeserializeObject<GatariUserStatsResponse>(resString);
|
||||
if (statsResponse.Code != 200 || statsResponse.Stats.Id == 0)
|
||||
{
|
||||
await SendErrorAsync("An osu! API key is required.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalizedAsync(strs.osu_user_not_found).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(user))
|
||||
var usrResString = await http.GetStringAsync($"https://api.gatari.pw/users/get?u={user}")
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var userData = JsonConvert.DeserializeObject<GatariUserResponse>(usrResString).Users[0];
|
||||
var userStats = statsResponse.Stats;
|
||||
|
||||
var embed = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle($"osu!Gatari {modeStr} profile for {user}")
|
||||
.WithThumbnailUrl($"https://a.gatari.pw/{userStats.Id}")
|
||||
.WithDescription($"https://osu.gatari.pw/u/{userStats.Id}")
|
||||
.AddField("Official Rank", $"#{userStats.Rank}", true)
|
||||
.AddField("Country Rank", $"#{userStats.CountryRank} :flag_{userData.Country.ToLower()}:", true)
|
||||
.AddField("Total PP", userStats.Pp, true)
|
||||
.AddField("Accuracy", $"{Math.Round(userStats.AvgAccuracy, 2)}%", true)
|
||||
.AddField("Playcount", userStats.Playcount, true)
|
||||
.AddField("Level", userStats.Level, true);
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task Osu5(string user, [Leftover] string mode = null)
|
||||
{;
|
||||
if (string.IsNullOrWhiteSpace(_creds.OsuApiKey))
|
||||
{
|
||||
await SendErrorAsync("An osu! API key is required.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(user))
|
||||
{
|
||||
await SendErrorAsync("Please provide a username.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
using (var http = _httpFactory.CreateClient())
|
||||
{
|
||||
var m = 0;
|
||||
if (!string.IsNullOrWhiteSpace(mode))
|
||||
{
|
||||
await SendErrorAsync("Please provide a username.").ConfigureAwait(false);
|
||||
return;
|
||||
m = ResolveGameMode(mode);
|
||||
}
|
||||
|
||||
using (var http = _httpFactory.CreateClient())
|
||||
var reqString = $"https://osu.ppy.sh/api/get_user_best" +
|
||||
$"?k={_creds.OsuApiKey}" +
|
||||
$"&u={Uri.EscapeDataString(user)}" +
|
||||
$"&type=string" +
|
||||
$"&limit=5" +
|
||||
$"&m={m}";
|
||||
|
||||
var resString = await http.GetStringAsync(reqString).ConfigureAwait(false);
|
||||
var obj = JsonConvert.DeserializeObject<List<OsuUserBests>>(resString);
|
||||
|
||||
var mapTasks = obj.Select(async item =>
|
||||
{
|
||||
var m = 0;
|
||||
if (!string.IsNullOrWhiteSpace(mode))
|
||||
{
|
||||
m = ResolveGameMode(mode);
|
||||
}
|
||||
var mapReqString = $"https://osu.ppy.sh/api/get_beatmaps" +
|
||||
$"?k={_creds.OsuApiKey}" +
|
||||
$"&b={item.BeatmapId}";
|
||||
|
||||
var reqString = $"https://osu.ppy.sh/api/get_user_best" +
|
||||
$"?k={_creds.OsuApiKey}" +
|
||||
$"&u={Uri.EscapeDataString(user)}" +
|
||||
$"&type=string" +
|
||||
$"&limit=5" +
|
||||
$"&m={m}";
|
||||
var mapResString = await http.GetStringAsync(mapReqString).ConfigureAwait(false);
|
||||
var map = JsonConvert.DeserializeObject<List<OsuMapData>>(mapResString).FirstOrDefault();
|
||||
if (map is null)
|
||||
return default;
|
||||
var pp = Math.Round(item.Pp, 2);
|
||||
var acc = CalculateAcc(item, m);
|
||||
var mods = ResolveMods(item.EnabledMods);
|
||||
|
||||
var resString = await http.GetStringAsync(reqString).ConfigureAwait(false);
|
||||
var obj = JsonConvert.DeserializeObject<List<OsuUserBests>>(resString);
|
||||
|
||||
var mapTasks = obj.Select(async item =>
|
||||
{
|
||||
var mapReqString = $"https://osu.ppy.sh/api/get_beatmaps" +
|
||||
$"?k={_creds.OsuApiKey}" +
|
||||
$"&b={item.BeatmapId}";
|
||||
|
||||
var mapResString = await http.GetStringAsync(mapReqString).ConfigureAwait(false);
|
||||
var map = JsonConvert.DeserializeObject<List<OsuMapData>>(mapResString).FirstOrDefault();
|
||||
if (map is null)
|
||||
return default;
|
||||
var pp = Math.Round(item.Pp, 2);
|
||||
var acc = CalculateAcc(item, m);
|
||||
var mods = ResolveMods(item.EnabledMods);
|
||||
|
||||
var title = $"{map.Artist}-{map.Title} ({map.Version})";
|
||||
var desc = $@"[/b/{item.BeatmapId}](https://osu.ppy.sh/b/{item.BeatmapId})
|
||||
var title = $"{map.Artist}-{map.Title} ({map.Version})";
|
||||
var desc = $@"[/b/{item.BeatmapId}](https://osu.ppy.sh/b/{item.BeatmapId})
|
||||
{pp + "pp",-7} | {acc + "%",-7}
|
||||
";
|
||||
if (mods != "+")
|
||||
{
|
||||
desc += Format.Bold(mods);
|
||||
}
|
||||
|
||||
return (title, desc);
|
||||
});
|
||||
|
||||
var eb = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle($"Top 5 plays for {user}");
|
||||
|
||||
var mapData = await Task.WhenAll(mapTasks);
|
||||
foreach (var (title, desc) in mapData.Where(x => x != default))
|
||||
if (mods != "+")
|
||||
{
|
||||
eb.AddField(title, desc, false);
|
||||
desc += Format.Bold(mods);
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(eb).ConfigureAwait(false);
|
||||
return (title, desc);
|
||||
});
|
||||
|
||||
var eb = _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle($"Top 5 plays for {user}");
|
||||
|
||||
var mapData = await Task.WhenAll(mapTasks);
|
||||
foreach (var (title, desc) in mapData.Where(x => x != default))
|
||||
{
|
||||
eb.AddField(title, desc, false);
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(eb).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
//https://osu.ppy.sh/wiki/Accuracy
|
||||
private static double CalculateAcc(OsuUserBests play, int mode)
|
||||
{
|
||||
double hitPoints;
|
||||
double totalHits;
|
||||
if (mode == 0)
|
||||
{
|
||||
hitPoints = play.Count50 * 50 +
|
||||
play.Count100 * 100 +
|
||||
play.Count300 * 300;
|
||||
totalHits = play.Count50 + play.Count100 +
|
||||
play.Count300 + play.Countmiss;
|
||||
totalHits *= 300;
|
||||
}
|
||||
else if (mode == 1)
|
||||
{
|
||||
hitPoints = play.Countmiss * 0 + play.Count100 * 0.5 + play.Count300;
|
||||
totalHits = (play.Countmiss + play.Count100 + play.Count300) * 300;
|
||||
hitPoints *= 300;
|
||||
}
|
||||
else if (mode == 2)
|
||||
{
|
||||
hitPoints = play.Count50 + play.Count100 + play.Count300;
|
||||
totalHits = play.Countmiss + play.Count50 + play.Count100 + play.Count300 +
|
||||
play.Countkatu;
|
||||
}
|
||||
else
|
||||
{
|
||||
hitPoints = play.Count50 * 50 +
|
||||
play.Count100 * 100 +
|
||||
play.Countkatu * 200 +
|
||||
(play.Count300 + play.Countgeki) * 300;
|
||||
|
||||
totalHits = (play.Countmiss + play.Count50 + play.Count100 +
|
||||
play.Countkatu + play.Count300 + play.Countgeki) * 300;
|
||||
}
|
||||
|
||||
|
||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||
}
|
||||
|
||||
private static int ResolveGameMode(string mode)
|
||||
{
|
||||
switch (mode.ToUpperInvariant())
|
||||
{
|
||||
case "STD":
|
||||
case "STANDARD":
|
||||
return 0;
|
||||
case "TAIKO":
|
||||
return 1;
|
||||
case "CTB":
|
||||
case "CATCHTHEBEAT":
|
||||
return 2;
|
||||
case "MANIA":
|
||||
case "OSU!MANIA":
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResolveGameMode(int mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case 0:
|
||||
return "Standard";
|
||||
case 1:
|
||||
return "Taiko";
|
||||
case 2:
|
||||
return "Catch";
|
||||
case 3:
|
||||
return "Mania";
|
||||
default:
|
||||
return "Standard";
|
||||
}
|
||||
}
|
||||
|
||||
//https://github.com/ppy/osu-api/wiki#mods
|
||||
private static string ResolveMods(int mods)
|
||||
{
|
||||
var modString = $"+";
|
||||
|
||||
if (IsBitSet(mods, 0))
|
||||
modString += "NF";
|
||||
if (IsBitSet(mods, 1))
|
||||
modString += "EZ";
|
||||
if (IsBitSet(mods, 8))
|
||||
modString += "HT";
|
||||
|
||||
if (IsBitSet(mods, 3))
|
||||
modString += "HD";
|
||||
if (IsBitSet(mods, 4))
|
||||
modString += "HR";
|
||||
if (IsBitSet(mods, 6) && !IsBitSet(mods, 9))
|
||||
modString += "DT";
|
||||
if (IsBitSet(mods, 9))
|
||||
modString += "NC";
|
||||
if (IsBitSet(mods, 10))
|
||||
modString += "FL";
|
||||
|
||||
if (IsBitSet(mods, 5))
|
||||
modString += "SD";
|
||||
if (IsBitSet(mods, 14))
|
||||
modString += "PF";
|
||||
|
||||
if (IsBitSet(mods, 7))
|
||||
modString += "RX";
|
||||
if (IsBitSet(mods, 11))
|
||||
modString += "AT";
|
||||
if (IsBitSet(mods, 12))
|
||||
modString += "SO";
|
||||
return modString;
|
||||
}
|
||||
|
||||
private static bool IsBitSet(int mods, int pos) =>
|
||||
(mods & (1 << pos)) != 0;
|
||||
}
|
||||
|
||||
//https://osu.ppy.sh/wiki/Accuracy
|
||||
private static double CalculateAcc(OsuUserBests play, int mode)
|
||||
{
|
||||
double hitPoints;
|
||||
double totalHits;
|
||||
if (mode == 0)
|
||||
{
|
||||
hitPoints = play.Count50 * 50 +
|
||||
play.Count100 * 100 +
|
||||
play.Count300 * 300;
|
||||
totalHits = play.Count50 + play.Count100 +
|
||||
play.Count300 + play.Countmiss;
|
||||
totalHits *= 300;
|
||||
}
|
||||
else if (mode == 1)
|
||||
{
|
||||
hitPoints = play.Countmiss * 0 + play.Count100 * 0.5 + play.Count300;
|
||||
totalHits = (play.Countmiss + play.Count100 + play.Count300) * 300;
|
||||
hitPoints *= 300;
|
||||
}
|
||||
else if (mode == 2)
|
||||
{
|
||||
hitPoints = play.Count50 + play.Count100 + play.Count300;
|
||||
totalHits = play.Countmiss + play.Count50 + play.Count100 + play.Count300 +
|
||||
play.Countkatu;
|
||||
}
|
||||
else
|
||||
{
|
||||
hitPoints = play.Count50 * 50 +
|
||||
play.Count100 * 100 +
|
||||
play.Countkatu * 200 +
|
||||
(play.Count300 + play.Countgeki) * 300;
|
||||
|
||||
totalHits = (play.Countmiss + play.Count50 + play.Count100 +
|
||||
play.Countkatu + play.Count300 + play.Countgeki) * 300;
|
||||
}
|
||||
|
||||
|
||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||
}
|
||||
|
||||
private static int ResolveGameMode(string mode)
|
||||
{
|
||||
switch (mode.ToUpperInvariant())
|
||||
{
|
||||
case "STD":
|
||||
case "STANDARD":
|
||||
return 0;
|
||||
case "TAIKO":
|
||||
return 1;
|
||||
case "CTB":
|
||||
case "CATCHTHEBEAT":
|
||||
return 2;
|
||||
case "MANIA":
|
||||
case "OSU!MANIA":
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResolveGameMode(int mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case 0:
|
||||
return "Standard";
|
||||
case 1:
|
||||
return "Taiko";
|
||||
case 2:
|
||||
return "Catch";
|
||||
case 3:
|
||||
return "Mania";
|
||||
default:
|
||||
return "Standard";
|
||||
}
|
||||
}
|
||||
|
||||
//https://github.com/ppy/osu-api/wiki#mods
|
||||
private static string ResolveMods(int mods)
|
||||
{
|
||||
var modString = $"+";
|
||||
|
||||
if (IsBitSet(mods, 0))
|
||||
modString += "NF";
|
||||
if (IsBitSet(mods, 1))
|
||||
modString += "EZ";
|
||||
if (IsBitSet(mods, 8))
|
||||
modString += "HT";
|
||||
|
||||
if (IsBitSet(mods, 3))
|
||||
modString += "HD";
|
||||
if (IsBitSet(mods, 4))
|
||||
modString += "HR";
|
||||
if (IsBitSet(mods, 6) && !IsBitSet(mods, 9))
|
||||
modString += "DT";
|
||||
if (IsBitSet(mods, 9))
|
||||
modString += "NC";
|
||||
if (IsBitSet(mods, 10))
|
||||
modString += "FL";
|
||||
|
||||
if (IsBitSet(mods, 5))
|
||||
modString += "SD";
|
||||
if (IsBitSet(mods, 14))
|
||||
modString += "PF";
|
||||
|
||||
if (IsBitSet(mods, 7))
|
||||
modString += "RX";
|
||||
if (IsBitSet(mods, 11))
|
||||
modString += "AT";
|
||||
if (IsBitSet(mods, 12))
|
||||
modString += "SO";
|
||||
return modString;
|
||||
}
|
||||
|
||||
private static bool IsBitSet(int mods, int pos) =>
|
||||
(mods & (1 << pos)) != 0;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user