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}.");