diff --git a/examples/filters/default.json b/examples/filters/default.json index 515646e9..63968c24 100644 --- a/examples/filters/default.json +++ b/examples/filters/default.json @@ -1,64 +1,68 @@ -{ - "pokemon": - { - "enabled": true, // Filter is enabled - "pokemon": [280,337,374], // List of Pokemon for the filter or empty for all - "min_iv": 0, // Minimum IV of Pokemon to send - "max_iv": 100, // Maximum IV of Pokemon to send - "min_cp": 0, // Minimum CP of Pokemon - "max_cp": 999999, // Maximum CP of Pokemon - "gender": "m", // Only send male (m,f,*) - "size": "Big", // Tiny, Small, Normal, Large, Big - "great_league": true, // Great League - "ultra_league": true, // Ultra League - "min_rank": 1, // Minimum rank of #1 PVP stats - "max_rank": 5, // Maximum rank of #5 PVP stats - "type": "Include", // Include or Exclude the `pokemon` list - "is_event": false, // Only send Pokemon checked with event accounts (GoFest, etc) - "ignoreMissing": true // Ignore Pokemon missing stats - }, - "eggs": - { - "enabled": true, // Filter is enabled - "min_lvl": 1, // Minimum egg level to send - "max_lvl": 6, // Maximum egg level to send - "onlyEx": false, // Only send ex-eligible raids. - "team": "All", // All, Valor, Mystic, Instinct, Neutral - }, - "raids": - { - "enabled": true, // Filter is enabled - "pokemon": [], // Raid bosses to include or none for all. - "min_lvl": 1, // Minimum raid level to send - "max_lvl": 6, // Maximum raid level to send - "type": "Include", // Include or Exclude the `pokemon` list - "onlyEx": false, // Only send ex-eligible raids. - "team": "All", // All, Valor, Mystic, Instinct, Nuetral - "ignoreMissing": true // Ignore raids missing stats - }, - "quests": - { - "enabled": true, // Filter is enabled - "rewards": ["spinda", "nincada"], // Quest reward string (Chansey, stardust, candy, etc.) - "isShiny": false, // Only shiny encounter quests. - "type": "Include" // Include or Exclude the `rewards` list - }, - "pokestops": - { - "enabled": true, // Filter is enabled - "lured": false, // Only send lured pokestops - "lure_types": ["Normal", "Glacial", "Mossy", "Magnetic"], // All lure types - "invasions": false // Only send Team Rocket invasion pokestops - }, - "gyms": - { - "enabled": true, // Filter is enabled - "underAttack": true, // Only gyms that are under attack - "team": "All" // Team change to notify about (i.e. Neutral/Mystic/Valor/Instinct/All) - }, - "weather": - { - "enabled": true, // Filter is enabled - "types": ["Clear", "Rainy", "PartlyCloudy", "Overcast", "Windy", "Snow", "Fog"] // Only send weather types that are in the list - } -} +{ + "pokemon": + { + "enabled": true, // Filter is enabled + "pokemon": [280,337,374], // List of Pokemon for the filter or empty for all + "forms": ["Alola","Galarian"], // List of forms for the filter or empty for all + "costumes": ["Detective","Holiday"], // List of costumes for the filter or empty for all + "min_iv": 0, // Minimum IV of Pokemon to send + "max_iv": 100, // Maximum IV of Pokemon to send + "min_cp": 0, // Minimum CP of Pokemon + "max_cp": 999999, // Maximum CP of Pokemon + "gender": "m", // Only send male (m,f,*) + "size": "Big", // Tiny, Small, Normal, Large, Big + "great_league": true, // Great League + "ultra_league": true, // Ultra League + "min_rank": 1, // Minimum rank of #1 PVP stats + "max_rank": 5, // Maximum rank of #5 PVP stats + "type": "Include", // Include or Exclude the `pokemon` list + "is_event": false, // Only send Pokemon checked with event accounts (GoFest, etc) + "ignoreMissing": true // Ignore Pokemon missing stats + }, + "eggs": + { + "enabled": true, // Filter is enabled + "min_lvl": 1, // Minimum egg level to send + "max_lvl": 6, // Maximum egg level to send + "onlyEx": false, // Only send ex-eligible raids. + "team": "All", // All, Valor, Mystic, Instinct, Neutral + }, + "raids": + { + "enabled": true, // Filter is enabled + "pokemon": [], // Raid bosses to include or none for all. + "costumes": ["Detective","Holiday"], //List of costumes for the filter or empty for all + "forms": ["Alola","Galarian"], //List of forms for the filter or empty for all + "min_lvl": 1, // Minimum raid level to send + "max_lvl": 6, // Maximum raid level to send + "type": "Include", // Include or Exclude the `pokemon` list + "onlyEx": false, // Only send ex-eligible raids. + "team": "All", // All, Valor, Mystic, Instinct, Nuetral + "ignoreMissing": true // Ignore raids missing stats + }, + "quests": + { + "enabled": true, // Filter is enabled + "rewards": ["spinda", "nincada"], // Quest reward string (Chansey, stardust, candy, etc.) + "isShiny": false, // Only shiny encounter quests. + "type": "Include" // Include or Exclude the `rewards` list + }, + "pokestops": + { + "enabled": true, // Filter is enabled + "lured": false, // Only send lured pokestops + "lure_types": ["Normal", "Glacial", "Mossy", "Magnetic"], // All lure types + "invasions": false // Only send Team Rocket invasion pokestops + }, + "gyms": + { + "enabled": true, // Filter is enabled + "underAttack": true, // Only gyms that are under attack + "team": "All" // Team change to notify about (i.e. Neutral/Mystic/Valor/Instinct/All) + }, + "weather": + { + "enabled": true, // Filter is enabled + "types": ["Clear", "Rainy", "PartlyCloudy", "Overcast", "Windy", "Snow", "Fog"] // Only send weather types that are in the list + } +} diff --git a/src/Alarms/Filters/Models/FilterPokemonObject.cs b/src/Alarms/Filters/Models/FilterPokemonObject.cs index 98357ead..9045983a 100644 --- a/src/Alarms/Filters/Models/FilterPokemonObject.cs +++ b/src/Alarms/Filters/Models/FilterPokemonObject.cs @@ -13,86 +13,98 @@ public class FilterPokemonObject { /// - /// Enable pokemon filter + /// Gets or sets a value determining whether to enable the pokemon filter /// [JsonProperty("enabled")] public bool Enabled { get; set; } /// - /// List of pokemon pokedex IDs to filter against + /// Gets or sets the list of pokemon pokedex IDs to filter against /// //TODO: Allow pokemon names and ids for pokemon filter. [JsonProperty("pokemon")] public List Pokemon { get; set; } /// - /// Minimum IV value to report + /// Gets or sets the list of pokemon Form strings to filter against + /// + [JsonProperty("forms")] + public List Forms { get; set; } + + /// + /// Gets or sets the list of Pokemon costume strings to filter against + /// + [JsonProperty("costumes")] + public List Costumes { get; set; } + + /// + /// Gets or sets the minimum IV value to report /// [JsonProperty("min_iv")] public uint MinimumIV { get; set; } /// - /// Maximum IV value to report + /// Gets or sets the maximum IV value to report /// [JsonProperty("max_iv")] public uint MaximumIV { get; set; } /// - /// Minimum CP value to report + /// Gets or sets the minimum CP value to report /// [JsonProperty("min_cp")] public uint MinimumCP { get; set; } /// - /// Maximum CP value to report + /// Gets or sets the maximum CP value to report /// [JsonProperty("max_cp")] public uint MaximumCP { get; set; } /// - /// Minimum level value to report + /// Gets or sets the minimum level value to report /// [JsonProperty("min_lvl")] public uint MinimumLevel { get; set; } /// - /// Maximum level value to report + /// Gets or sets the maximum level value to report /// [JsonProperty("max_lvl")] public uint MaximumLevel { get; set; } /// - /// Pokemon gender to filter by + /// Gets or sets the Pokemon gender to filter by /// [JsonProperty("gender")] public char Gender { get; set; } /// - /// Pokemon size to filter by + /// Gets or sets the Pokemon size to filter by /// [JsonProperty("size")] public PokemonSize? Size { get; set; } /// - /// Only great league PvP eligible Pokemon + /// Gets or sets a value determining to filter only great league PvP eligible Pokemon /// [JsonProperty("great_league")] public bool IsPvpGreatLeague { get; set; } /// - /// Only ultra league PvP eligible Pokemon + /// Gets or sets a value determining to filter only ultra league PvP eligible Pokemon /// [JsonProperty("ultra_league")] public bool IsPvpUltraLeague { get; set; } /// - /// Minimum PvP rank to report + /// Gets or sets the minimum PvP rank to report /// [JsonProperty("min_rank")] public uint MinimumRank { get; set; } /// - /// Maximum PvP rank to report + /// Gets or sets the maximum PvP rank to report /// [JsonProperty("max_rank")] public uint MaximumRank { get; set; } @@ -100,19 +112,19 @@ public class FilterPokemonObject //TODO: Filter by move? /// - /// Pokemon filter type + /// Gets or sets the Pokemon filter type /// [JsonProperty("type")] public FilterType FilterType { get; set; } /// - /// Event Pokemon flag indicating it was checked with an event account + /// Gets or sets a value determining whether a Pokemon was checked with an event account /// [JsonProperty("is_event")] public bool IsEvent { get; set; } /// - /// Ignore Pokemon missing stats + /// Gets or sets a value determining whether to ignore Pokemon missing stats /// [JsonProperty("ignoreMissing")] public bool IgnoreMissing { get; set; } @@ -122,6 +134,9 @@ public class FilterPokemonObject /// public FilterPokemonObject() { + Pokemon = new List(); + Forms = new List(); + Costumes = new List(); MinimumIV = 0; MaximumIV = 100; MinimumCP = 0; diff --git a/src/Alarms/Filters/Models/FilterRaidObject.cs b/src/Alarms/Filters/Models/FilterRaidObject.cs index 5188f0e1..3cd5f4df 100644 --- a/src/Alarms/Filters/Models/FilterRaidObject.cs +++ b/src/Alarms/Filters/Models/FilterRaidObject.cs @@ -13,50 +13,62 @@ public class FilterRaidObject { /// - /// Enable raid boss filter + /// Gets or sets a value determining whether to enable the raid boss filter /// [JsonProperty("enabled")] public bool Enabled { get; set; } /// - /// Minimum raid level + /// Gets or sets the minimum raid level /// [JsonProperty("min_lvl")] public uint MinimumLevel { get; set; } /// - /// Maximum raid level + /// Gets or sets the maximum raid level /// [JsonProperty("max_lvl")] public uint MaximumLevel { get; set; } /// - /// Raid boss pokedex ID list to filter against + /// Gets or sets the Raid boss pokedex ID list to filter against /// //TODO: Allow pokemon names and ids for raid filter. [JsonProperty("pokemon")] public List Pokemon { get; set; } /// - /// Raid boss filter type + /// Gets or sets the list of Raid Boss Pokemon Form strings to filter against + /// + [JsonProperty("forms")] + public List Forms { get; set; } + + /// + /// Gets or sets the list of Raid Boss Pokemon costume strings to filter against + /// + [JsonProperty("costumes")] + public List Costumes { get; set; } + + /// + /// Gets or sets the Raid boss filter type /// [JsonProperty("type")] public FilterType FilterType { get; set; } /// - /// Only report ex-eligible raids + /// Gets or sets a value determining whether to only report ex-eligible raids /// [JsonProperty("onlyEx")] public bool OnlyEx { get; set; } /// - /// Gym team control filter + /// Gets or sets the Gym team control filter /// [JsonProperty("team")] public PokemonTeam Team { get; set; } /// - /// Ignore raids missing stats + /// Gets or sets a value determining whether to ignore raids missing stats /// [JsonProperty("ignoreMissing")] public bool IgnoreMissing { get; set; } @@ -66,6 +78,9 @@ public class FilterRaidObject /// public FilterRaidObject() { + Pokemon = new List(); + Forms = new List(); + Costumes = new List(); MinimumLevel = 1; MaximumLevel = 5; Team = PokemonTeam.All; diff --git a/src/Bot.cs b/src/Bot.cs index bb97a901..1f7536f6 100644 --- a/src/Bot.cs +++ b/src/Bot.cs @@ -26,7 +26,6 @@ using DSharpPlus.CommandsNext; using DSharpPlus.Interactivity; - // TODO: Subscriptions, Pokemon, Raid, Quest, Invasion, Gym, Weather alarm statistics by day. date/pokemonId/count // TODO: List all subscriptions with info command // TODO: Multiple discord bot tokens per server // TODO: Check nests again diff --git a/src/Localization/Translator.cs b/src/Localization/Translator.cs index a1949c8c..6d349db6 100644 --- a/src/Localization/Translator.cs +++ b/src/Localization/Translator.cs @@ -70,14 +70,14 @@ public string GetPokemonName(int pokeId) return Translate($"poke_{pokeId}"); } - public string GetFormName(int formId) + public string GetFormName(int formId, bool includeNormal = false) { if (formId == 0) return null; var form = Translate("form_" + formId); // TODO: Localize - if (string.Compare(form, "Normal", true) == 0) + if (!includeNormal && string.Compare(form, "Normal", true) == 0) return string.Empty; return form; } diff --git a/src/Net/Webhooks/WebhookController.cs b/src/Net/Webhooks/WebhookController.cs index 0b872741..454c4f40 100644 --- a/src/Net/Webhooks/WebhookController.cs +++ b/src/Net/Webhooks/WebhookController.cs @@ -16,6 +16,7 @@ using WhMgr.Diagnostics; using WhMgr.Extensions; using WhMgr.Geofence; + using WhMgr.Localization; using WhMgr.Net; using WhMgr.Net.Configuration; using WhMgr.Net.Models; @@ -580,6 +581,32 @@ private void ProcessPokemon(PokemonData pkmn) continue; } + var formName = Translator.Instance.GetFormName(pkmn.FormId).ToLower(); + if (alarm.Filters.Pokemon.FilterType == FilterType.Exclude && alarm.Filters.Pokemon.Forms.Select(x => x.ToLower()).Contains(formName)) + { + //_logger.Info($"[{alarm.Name}] [{geofence.Name}] Skipping pokemon {pkmn.Id} with form {pkmn.FormId} ({formName}): filter {alarm.Filters.Pokemon.FilterType}."); + continue; + } + + if (alarm.Filters.Pokemon.FilterType == FilterType.Include && alarm.Filters.Pokemon.Forms?.Count > 0 && !alarm.Filters.Pokemon.Forms.Select(x => x.ToLower()).Contains(formName)) + { + //_logger.Info($"[{alarm.Name}] [{geofence.Name}] Skipping pokemon {pkmn.Id} with form {pkmn.FormId} ({formName}): filter {alarm.Filters.Pokemon.FilterType}."); + continue; + } + + var costumeName = Translator.Instance.GetCostumeName(pkmn.Costume).ToLower(); + if (alarm.Filters.Pokemon.FilterType == FilterType.Exclude && alarm.Filters.Pokemon.Costumes.Select(x => x.ToLower()).Contains(costumeName)) + { + //_logger.Info($"[{alarm.Name}] [{geofence.Name}] Skipping pokemon {pkmn.Id} with costume {pkmn.Costume} ({costumeName}): filter {alarm.Filters.Pokemon.FilterType}."); + continue; + } + + if (alarm.Filters.Pokemon.FilterType == FilterType.Include && alarm.Filters.Pokemon.Costumes?.Count > 0 && !alarm.Filters.Pokemon.Costumes.Select(x => x.ToLower()).Contains(costumeName)) + { + //_logger.Info($"[{alarm.Name}] [{geofence.Name}] Skipping pokemon {pkmn.Id} with costume {pkmn.Costume} ({costumeName}): filter {alarm.Filters.Pokemon.FilterType}."); + continue; + } + if (alarm.Filters.Pokemon.IgnoreMissing && pkmn.IsMissingStats) { //_logger.Info($"[{alarm.Name}] [{geofence.Name}] Skipping pokemon {pkmn.Id}: IgnoreMissing=true."); @@ -738,6 +765,32 @@ private void ProcessRaid(RaidData raid) continue; } + var formName = Translator.Instance.GetFormName(raid.Form).ToLower(); + if (alarm.Filters.Raids.FilterType == FilterType.Exclude && alarm.Filters.Raids.Forms.Select(x => x.ToLower()).Contains(formName)) + { + //_logger.Info($"[{alarm.Name}] [{geofence.Name}] Skipping raid boss {raid.Id} with form {raid.Form} ({formName}): filter {alarm.Filters.Raids.FilterType}."); + continue; + } + + if (alarm.Filters.Raids.FilterType == FilterType.Include && alarm.Filters.Raids.Forms?.Count > 0 && !alarm.Filters.Raids.Forms.Select(x => x.ToLower()).Contains(formName)) + { + //_logger.Info($"[{alarm.Name}] [{geofence.Name}] Skipping raid boss {raid.Id} with form {raid.Form} ({formName}): filter {alarm.Filters.Raids.FilterType}."); + continue; + } + + var costumeName = Translator.Instance.GetCostumeName(raid.Costume).ToLower(); + if (alarm.Filters.Raids.FilterType == FilterType.Exclude && alarm.Filters.Raids.Costumes.Select(x => x.ToLower()).Contains(costumeName)) + { + //_logger.Info($"[{alarm.Name}] [{geofence.Name}] Skipping raid boss {raid.Id} with costume {raid.Costume} ({costumeName}): filter {alarm.Filters.Raids.FilterType}."); + continue; + } + + if (alarm.Filters.Raids.FilterType == FilterType.Include && alarm.Filters.Raids.Costumes?.Count > 0 && !alarm.Filters.Raids.Costumes.Select(x => x.ToLower()).Contains(costumeName)) + { + //_logger.Info($"[{alarm.Name}] [{geofence.Name}] Skipping raid boss {raid.Id} with costume {raid.Costume} ({costumeName}): filter {alarm.Filters.Raids.FilterType}."); + continue; + } + if (alarm.Filters.Raids.OnlyEx && !raid.IsExEligible) { //_logger.Info($"[{alarm.Name}] [{geofence.Name}] Skipping raid boss {raid.PokemonId}: only ex {alarm.Filters.Raids.OnlyEx}.");