1
Fork 0
mirror of https://github.com/Steffo99/patched-porobot.git synced 2024-12-23 01:54:22 +00:00

Add proper support for the new formats

This commit is contained in:
Steffo 2023-04-11 19:12:09 +02:00
parent 267e205af4
commit 1766b6adcc
Signed by: steffo
GPG key ID: 2A24051445686895
8 changed files with 328 additions and 36 deletions

View file

@ -0,0 +1,68 @@
//! Module defining structs representing localized card formats.
use crate::data::setbundle::format::CardFormat;
use std::collections::HashMap;
/// A Legends of Runeterra [CardFormat], and its associated localization.
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct LocalizedCardFormat {
/// The [CardFormat] these strings refer to.
#[serde(rename = "nameRef")]
pub format: CardFormat,
/// The localized name of the keyword.
pub name: String,
/// URL to the icon of the set in `.png` format.
#[serde(rename = "iconAbsolutePath")]
pub icon_png: Option<String>,
}
/// How [LocalizedCardSet]s appear in `global.json` files.
pub type LocalizedCardFormatVec = Vec<LocalizedCardFormat>;
/// An index of [LocalizedCardSet]s, with [LocalizedCardSet::set]s as keys.
pub type LocalizedCardFormatIndex = HashMap<CardFormat, LocalizedCardFormat>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[rustfmt::skip]
fn deserialize_standard() {
assert_eq!(
serde_json::de::from_str::<'static, LocalizedCardFormat>(r#"
{
"iconAbsolutePath": "http://dd.b.pvp.net/4_3_0/core/en_us/img/formats/queue_select_standard_toggle_active.png",
"name": "Standard",
"nameRef": "client_Formats_Standard_name"
}
"#).unwrap(),
LocalizedCardFormat {
format: CardFormat::Standard,
name: "Standard".to_string(),
icon_png: Some("http://dd.b.pvp.net/4_3_0/core/en_us/img/formats/queue_select_standard_toggle_active.png".to_string()),
}
);
}
#[test]
#[rustfmt::skip]
fn deserialize_singleton() {
assert_eq!(
serde_json::de::from_str::<'static, LocalizedCardFormat>(r#"
{
"iconAbsolutePath": null,
"name": "Singleton",
"nameRef": "client_Deckbuilder_RulesFilters_Singleton"
}
"#).unwrap(),
LocalizedCardFormat {
format: CardFormat::Singleton,
name: "Singleton".to_string(),
icon_png: None,
}
);
}
}

View file

@ -6,6 +6,7 @@ use super::region::{LocalizedCardRegionIndex, LocalizedCardRegionVec};
use super::set::{LocalizedCardSetIndex, LocalizedCardSetVec};
use super::speed::{LocalizedSpellSpeedIndex, LocalizedSpellSpeedVec};
use super::vocabterm::{LocalizedVocabTermIndex, LocalizedVocabTermVec};
use super::format::{LocalizedCardFormatIndex, LocalizedCardFormatVec};
use crate::data::anybundle::outcomes::{LoadingError, LoadingResult};
use std::fs::File;
use std::path::Path;
@ -37,6 +38,9 @@ pub struct LocalizedGlobalsVecs {
/// Card sets.
pub sets: LocalizedCardSetVec,
/// Card formats.
pub formats: LocalizedCardFormatVec,
}
/// A parsed and indexed `globals.json` file from a [Data Dragon] [Core Bundle].
@ -66,6 +70,9 @@ pub struct LocalizedGlobalsIndexes {
/// Card sets.
pub sets: LocalizedCardSetIndex,
/// Card formats.
pub formats: LocalizedCardFormatIndex,
}
impl LocalizedGlobalsVecs {
@ -123,12 +130,20 @@ impl From<LocalizedGlobalsVecs> for LocalizedGlobalsIndexes {
}
hm
},
formats: {
let mut hm = LocalizedCardFormatIndex::new();
for obj in o.formats {
hm.insert(obj.format, obj);
}
hm
},
}
}
}
#[cfg(test)]
mod tests {
use crate::data::corebundle::format::LocalizedCardFormat;
use super::LocalizedGlobalsVecs;
use crate::data::corebundle::keyword::LocalizedCardKeyword;
use crate::data::corebundle::rarity::LocalizedCardRarity;
@ -136,6 +151,7 @@ mod tests {
use crate::data::corebundle::set::LocalizedCardSet;
use crate::data::corebundle::speed::LocalizedSpellSpeed;
use crate::data::corebundle::vocabterm::LocalizedVocabTerm;
use crate::data::setbundle::format::CardFormat;
use crate::data::setbundle::keyword::CardKeyword;
use crate::data::setbundle::rarity::CardRarity;
use crate::data::setbundle::region::CardRegion;
@ -189,6 +205,13 @@ mod tests {
"name": "Call of the Mountain",
"nameRef": "Set3"
}
],
"formats": [
{
"iconAbsolutePath": "http://dd.b.pvp.net/4_3_0/core/en_us/img/formats/queue_select_standard_toggle_active.png",
"name": "Standard",
"nameRef": "client_Formats_Standard_name"
}
]
}
"#
@ -235,6 +258,13 @@ mod tests {
name: "Call of the Mountain".to_string(),
icon_png: "http://dd.b.pvp.net/3_11_0/core/en_us/img/sets/set3_crispmip.png".to_string()
}
],
formats: vec![
LocalizedCardFormat {
format: CardFormat::Standard,
name: "Standard".to_string(),
icon_png: Some("http://dd.b.pvp.net/4_3_0/core/en_us/img/formats/queue_select_standard_toggle_active.png".to_string()),
}
]
}
)

View file

@ -14,6 +14,7 @@ pub mod region;
pub mod set;
pub mod speed;
pub mod vocabterm;
pub mod format;
/// A parsed [Data Dragon] [Core Bundle].
///
@ -111,7 +112,7 @@ mod tests {
};
}
test_fetch!(test_fetch_3_17_0_en_us, "3_17_0", "en_us");
test_fetch!(test_fetch_3_17_0_it_it, "3_17_0", "it_it");
test_fetch!(test_fetch_4_3_0_en_us, "4_3_0", "en_us");
test_fetch!(test_fetch_4_3_0_it_it, "4_3_0", "it_it");
test_fetch!(test_fetch_latest_en_us, "latest", "en_us");
}

View file

@ -10,6 +10,7 @@ use itertools::Itertools;
use std::collections::{HashMap, HashSet};
use std::io::{Cursor, Read, Write};
use varint_rs::{VarintReader, VarintWriter};
use crate::data::setbundle::format::CardFormat;
use crate::data::setbundle::supertype::CardSupertype;
/// A unshuffled Legends of Runeterra card deck.
@ -425,8 +426,8 @@ impl Deck {
/// let champions = deck.champions(&index);
///
/// let champion_codes: Vec<&str> = champions.map(|c| c.code.full.as_str()).collect();
/// const EXPECTED_CODES: [&str; 2] = ["01IO015", "02NX007"];
/// assert_eq!(champion_codes, EXPECTED_CODES)
/// assert!(champion_codes.contains(&"01IO015"));
/// assert!(champion_codes.contains(&"02NX007"));
/// ```
pub fn champions<'a>(&'a self, cards: &'a CardIndex) -> impl Iterator<Item = &'a Card> {
self.contents.keys()
@ -497,6 +498,34 @@ impl Deck {
.sum()
}
/// Check if the cards contained in the deck are allowed in the given format.
///
/// For compatibility reasons, assumes that cards missing from the [`CardIndex`] are always allowed.
///
/// Be aware that this does not verify other conditions that may be requirements for a given format: this method only checks that the cards have the required [`CardFormat`] tags.
///
/// # Example
///
/// ```rust
/// use patched_porobot::deck;
/// use patched_porobot::data::deckcode::deck::Deck;
/// use patched_porobot::data::setbundle::card::CardIndex;
/// use patched_porobot::data::setbundle::create_cardindex_from_wd;
/// use patched_porobot::data::setbundle::format::CardFormat;
///
/// let index: CardIndex = create_cardindex_from_wd();
/// let deck: Deck = deck!("CECQCAQCA4AQIAYKAIAQGLRWAQAQECAPEUXAIAQDAEBQOCIBAIAQEMJYAA");
/// assert!(deck.cards_are_allowed_in(&index, CardFormat::Eternal));
/// ```
///
pub fn cards_are_allowed_in(&self, cards: &CardIndex, format: CardFormat) -> bool {
self.contents.keys()
.map(|cc| cc.to_card(&cards))
.filter(|o| o.is_some())
.map(|o| o.unwrap())
.all(|c| c.formats.contains(&format))
}
/// Find the first possible set of regions that the [`Deck`] fits in.
///
/// Lower amounts of regions are preferred: the limit will be increased from 1 up to `limit` until a valid solution is found.
@ -570,9 +599,29 @@ impl Deck {
let copies_limit = self.contents.values().all(|n| n <= &3);
let cards_limit = self.card_count() == 40;
let champions_limit = self.champions_count(cards) <= 6;
let are_cards_allowed = self.cards_are_allowed_in(cards, CardFormat::Eternal);
let regions = self.regions(cards, 2);
match copies_limit && cards_limit && champions_limit {
match copies_limit && cards_limit && champions_limit && are_cards_allowed {
false => None,
true => regions,
}
}
/// Check if the [`Deck`] is legal for play in the *Standard* format.
///
/// # Returns
///
/// - `None` if the deck is not legal for *Eternal* play.
/// - `Some(regions)` if the deck is legal for *Eternal* play considering the specified region set.
pub fn standard(&self, cards: &CardIndex) -> Option<HashSet<CardRegion>> {
let copies_limit = self.contents.values().all(|n| n <= &3);
let cards_limit = self.card_count() == 40;
let champions_limit = self.champions_count(cards) <= 6;
let are_cards_allowed = self.cards_are_allowed_in(cards, CardFormat::Standard);
let regions = self.regions(cards, 2);
match copies_limit && cards_limit && champions_limit && are_cards_allowed {
false => None,
true => regions,
}
@ -588,16 +637,17 @@ impl Deck {
let copies_limit = self.contents.values().all(|n| n <= &1);
let cards_limit = self.card_count() == 40;
let champions_limit = self.champions_count(cards) <= 6;
let are_cards_allowed = self.cards_are_allowed_in(cards, CardFormat::Eternal); // I think?
let regions = self.regions(cards, 3);
match copies_limit && cards_limit && champions_limit {
match copies_limit && cards_limit && champions_limit && are_cards_allowed {
false => None,
true => regions,
}
}
/// Check if the [`Deck`] is legal to play in the *Unlimited Champions* format.
///
///
/// # Returns
///
/// - `None` if the deck is not legal for *Unlimited Champions* play.
@ -605,9 +655,10 @@ impl Deck {
pub fn unlimited_champions(&self, cards: &CardIndex) -> Option<HashSet<CardRegion>> {
let copies_limit = self.contents.values().all(|n| n <= &3);
let cards_limit = self.card_count() == 40;
let are_cards_allowed = self.cards_are_allowed_in(cards, CardFormat::Eternal); // I think?
let regions = self.regions(cards, 2);
match copies_limit && cards_limit {
match copies_limit && cards_limit && are_cards_allowed {
false => None,
true => regions,
}
@ -892,6 +943,37 @@ mod tests {
}
}
test_legality!(
test_legality_standard_aggroblanc,
deck!("CEDACAIDDMAQEAYFAECAGBABAYBAGAQBAIESUAYHAMAQQCIEAEDAGIABA4BQGAQBAMJRSAQCAMBQIAIBAMBBI"),
Deck::standard, true
);
test_legality!(
test_legality_standard_lonelyporo1,
deck!("CEAAAAIBAEAQQ"),
Deck::standard, false
);
test_legality!(
test_legality_standard_twistedshrimp,
deck!("CICACBAFAEBAGBQICABQCBJLF4YQOAQGAQEQYEQUDITAAAIBAMCQO"),
Deck::standard, false
);
test_legality!(
test_legality_standard_poros,
deck!("CQDQCAQBAMAQGAICAECACDYCAECBIFYCAMCBEEYCAUFIYANAAEBQCAIICA2QCAQBAEVTSAA"),
Deck::standard, false
);
test_legality!(
test_legality_standard_sand,
deck!("CMBAGBAHANTXEBQBAUCAOFJGFIYQEAIBAUOQIBAHGM5HM6ICAECAOOYCAECRSGY"),
Deck::standard, false
);
test_legality!(
test_legality_standard_paltri,
deck!("CQAAADABAICACAIFBLAACAIFAEHQCBQBEQBAGBADAQBAIAIKBUBAKBAWDUBQIBACA4GAMAIBAMCAYHJBGADAMBAOCQKRMKBLA4AQIAQ3D4QSIKZYBACAODJ3JRIW3AABQIAYUAI"),
Deck::standard, false
);
test_legality!(
test_legality_eternal_lonelyporo1,
deck!("CEAAAAIBAEAQQ"),
@ -917,6 +999,11 @@ mod tests {
deck!("CQAAADABAICACAIFBLAACAIFAEHQCBQBEQBAGBADAQBAIAIKBUBAKBAWDUBQIBACA4GAMAIBAMCAYHJBGADAMBAOCQKRMKBLA4AQIAQ3D4QSIKZYBACAODJ3JRIW3AABQIAYUAI"),
Deck::eternal, false
);
test_legality!(
test_legality_eternal_aggroblanc,
deck!("CEDACAIDDMAQEAYFAECAGBABAYBAGAQBAIESUAYHAMAQQCIEAEDAGIABA4BQGAQBAMJRSAQCAMBQIAIBAMBBI"),
Deck::eternal, true
);
test_legality!(
test_legality_singleton_lonelyporo1,
@ -943,6 +1030,11 @@ mod tests {
deck!("CQAAADABAICACAIFBLAACAIFAEHQCBQBEQBAGBADAQBAIAIKBUBAKBAWDUBQIBACA4GAMAIBAMCAYHJBGADAMBAOCQKRMKBLA4AQIAQ3D4QSIKZYBACAODJ3JRIW3AABQIAYUAI"),
Deck::singleton, true
);
test_legality!(
test_legality_singleton_aggroblanc,
deck!("CEDACAIDDMAQEAYFAECAGBABAYBAGAQBAIESUAYHAMAQQCIEAEDAGIABA4BQGAQBAMJRSAQCAMBQIAIBAMBBI"),
Deck::singleton, false
);
// From https://lor.cardsrealm.com/en-us/articles/new-game-modes-in-lor-unlimited-and-free-decks-to-discover
test_legality!(
@ -964,5 +1056,5 @@ mod tests {
test_legality_unlchamp_paltri,
deck!("CQAAADABAICACAIFBLAACAIFAEHQCBQBEQBAGBADAQBAIAIKBUBAKBAWDUBQIBACA4GAMAIBAMCAYHJBGADAMBAOCQKRMKBLA4AQIAQ3D4QSIKZYBACAODJ3JRIW3AABQIAYUAI"),
Deck::unlimited_champions, false
);
);
}

View file

@ -12,6 +12,7 @@ use crate::data::setbundle::subtype::CardSubtype;
use crate::data::setbundle::supertype::CardSupertype;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use crate::data::setbundle::format::CardFormat;
/// A single Legends of Runeterra card, as represented in a `set*.json` file.
///
@ -144,6 +145,10 @@ pub struct Card {
/// The supertype the card belongs to, such as [`Champion`](CardSupertype::Champion) or [`None`](CardSupertype::None).
pub supertype: CardSupertype,
/// The formats the card can be played in, such as [`Standard`](CardFormat::Standard) and [`Eternal`](CardFormat::Eternal).
#[serde(rename = "formatRefs")]
pub formats: Vec<CardFormat>
}
impl Card {
@ -192,14 +197,14 @@ mod tests {
{
"associatedCards": [],
"associatedCardRefs": [
"06RU025T14",
"06RU025T6",
"06RU025T5"
"06RU025T14",
"06RU025T6",
"06RU025T5"
],
"assets": [
{
"gameAbsolutePath": "http://dd.b.pvp.net/3_11_0/set6/en_us/img/cards/06RU025.png",
"fullAbsolutePath": "http://dd.b.pvp.net/3_11_0/set6/en_us/img/cards/06RU025-full.png"
"gameAbsolutePath": "http://dd.b.pvp.net/4_3_0/set6/en_us/img/cards/06RU025.png",
"fullAbsolutePath": "http://dd.b.pvp.net/4_3_0/set6/en_us/img/cards/06RU025-full.png"
}
],
"regions": [
@ -213,8 +218,8 @@ mod tests {
"health": 5,
"description": "<link=vocab.Origin><style=Vocab>Origin</style></link>: <link=card.origin><style=AssociatedCard>Agony's Embrace</style></link>.\r\nWhen I'm summoned, summon a random Husk.",
"descriptionRaw": "Origin: Agony's Embrace.\r\nWhen I'm summoned, summon a random Husk.",
"levelupDescription": "When you or an ally kill an allied Husk, give me its positive keywords this round and I level up.",
"levelupDescriptionRaw": "When you or an ally kill an allied Husk, give me its positive keywords this round and I level up.",
"levelupDescription": "When I see you or an ally kill an allied Husk, give me its positive keywords this round and I level up.",
"levelupDescriptionRaw": "When I see you or an ally kill an allied Husk, give me its positive keywords this round and I level up.",
"flavorText": "The priestess' pupils were blown wide, and her hand trembled with nervous excitement. She was ready. This was the single moment Evelynn craved more than any other. She grinned, and slowly shed her visage. Then, as always, the screaming began.",
"artistName": "Kudos Productions",
"name": "Evelynn",
@ -229,8 +234,18 @@ mod tests {
"supertype": "Champion",
"type": "Unit",
"collectible": true,
"set": "Set6"
}
"set": "Set6",
"formats": [
"Commons Only",
"Eternal",
"Standard"
],
"formatRefs": [
"client_Formats_CommonsOnly_name",
"client_Formats_Eternal_name",
"client_Formats_Standard_name"
]
}
"#).unwrap(),
Card {
code: CardCode::from("06RU025".to_string()),
@ -272,6 +287,11 @@ mod tests {
artist_name: String::from("Kudos Productions"),
subtypes: vec![],
supertype: CardSupertype::Champion,
formats: vec![
CardFormat::CommonsOnly,
CardFormat::Eternal,
CardFormat::Standard,
],
}
)
}

View file

@ -0,0 +1,75 @@
//! Module defining [CardFormat].
use crate::data::corebundle::format::{LocalizedCardFormat, LocalizedCardFormatIndex};
/// A format in which [Card](super::card::Card)s can be played in.
///
/// Since more keywords will probably be added in the future, this enum is [non_exaustive](https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute).
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub enum CardFormat {
/// Standard.
#[serde(rename = "client_Formats_Standard_name")]
Standard,
/// Singleton.
///
/// Note that this format does not currently appear in card data, as it seems to be used only for the deckbuilder.
#[serde(rename = "client_Deckbuilder_RulesFilters_Singleton")]
Singleton,
/// Eternal.
#[serde(rename = "client_Formats_Eternal_name")]
Eternal,
/// Commons only.
#[serde(rename = "client_Formats_CommonsOnly_name")]
CommonsOnly,
/// Even-cost cards only.
#[serde(rename = "client_Formats_EvenCostCards_name")]
EvenCostCards,
/// Unsupported format.
#[serde(other)]
Unsupported,
}
impl CardFormat {
/// Get the [LocalizedCardFormat] associated with this [CardFormat].
///
/// Returns [None] if no matching [LocalizedCardFormat] was found, for example formats missing from the index.
///
/// Equivalent to calling [LocalizedCardFormatIndex::get].
pub fn localized<'hm>(
&self,
hm: &'hm LocalizedCardFormatIndex,
) -> Option<&'hm LocalizedCardFormat> {
hm.get(self)
}
}
#[cfg(test)]
mod tests {
use super::CardFormat;
macro_rules! test_deserialization {
( $id:ident, $src:literal, $res:expr ) => {
#[test]
fn $id() {
assert_eq!(
serde_json::de::from_str::<'static, CardFormat>($src).unwrap(),
$res
);
}
};
}
test_deserialization!(deserialize_standard, r#""client_Formats_Standard_name""#, CardFormat::Standard);
test_deserialization!(deserialize_singleton, r#""client_Deckbuilder_RulesFilters_Singleton""#, CardFormat::Singleton);
test_deserialization!(deserialize_eternal, r#""client_Formats_Eternal_name""#, CardFormat::Eternal);
test_deserialization!(deserialize_commonsonly, r#""client_Formats_CommonsOnly_name""#, CardFormat::CommonsOnly);
test_deserialization!(deserialize_evencostcards, r#""client_Formats_EvenCostCards_name""#, CardFormat::EvenCostCards);
test_deserialization!(deserialize_unsupported, r#""xyzzy""#, CardFormat::Unsupported);
}

View file

@ -19,6 +19,7 @@ pub mod speed;
pub mod subtype;
pub mod supertype;
pub mod r#type;
pub mod format;
/// A parsed [Data Dragon] [Set Bundle].
///
@ -94,21 +95,23 @@ mod tests {
};
}
test_fetch!(test_fetch_3_17_0_en_us_set1, "3_17_0", "en_us", "set1");
test_fetch!(test_fetch_3_17_0_en_us_set2, "3_17_0", "en_us", "set2");
test_fetch!(test_fetch_3_17_0_en_us_set3, "3_17_0", "en_us", "set3");
test_fetch!(test_fetch_3_17_0_en_us_set4, "3_17_0", "en_us", "set4");
test_fetch!(test_fetch_3_17_0_en_us_set5, "3_17_0", "en_us", "set5");
test_fetch!(test_fetch_3_17_0_en_us_set6, "3_17_0", "en_us", "set6");
test_fetch!(test_fetch_3_17_0_en_us_set6cde, "3_17_0", "en_us", "set6cde");
test_fetch!(test_fetch_4_3_0_en_us_set1, "4_3_0", "en_us", "set1");
test_fetch!(test_fetch_4_3_0_en_us_set2, "4_3_0", "en_us", "set2");
test_fetch!(test_fetch_4_3_0_en_us_set3, "4_3_0", "en_us", "set3");
test_fetch!(test_fetch_4_3_0_en_us_set4, "4_3_0", "en_us", "set4");
test_fetch!(test_fetch_4_3_0_en_us_set5, "4_3_0", "en_us", "set5");
test_fetch!(test_fetch_4_3_0_en_us_set6, "4_3_0", "en_us", "set6");
test_fetch!(test_fetch_4_3_0_en_us_set6cde, "4_3_0", "en_us", "set6cde");
test_fetch!(test_fetch_4_3_0_en_us_set7, "4_3_0", "en_us", "set7");
test_fetch!(test_fetch_3_17_0_it_it_set1, "3_17_0", "it_it", "set1");
test_fetch!(test_fetch_3_17_0_it_it_set2, "3_17_0", "it_it", "set2");
test_fetch!(test_fetch_3_17_0_it_it_set3, "3_17_0", "it_it", "set3");
test_fetch!(test_fetch_3_17_0_it_it_set4, "3_17_0", "it_it", "set4");
test_fetch!(test_fetch_3_17_0_it_it_set5, "3_17_0", "it_it", "set5");
test_fetch!(test_fetch_3_17_0_it_it_set6, "3_17_0", "it_it", "set6");
test_fetch!(test_fetch_3_17_0_it_it_set6cde, "3_17_0", "it_it", "set6cde");
test_fetch!(test_fetch_4_3_0_it_it_set1, "4_3_0", "it_it", "set1");
test_fetch!(test_fetch_4_3_0_it_it_set2, "4_3_0", "it_it", "set2");
test_fetch!(test_fetch_4_3_0_it_it_set3, "4_3_0", "it_it", "set3");
test_fetch!(test_fetch_4_3_0_it_it_set4, "4_3_0", "it_it", "set4");
test_fetch!(test_fetch_4_3_0_it_it_set5, "4_3_0", "it_it", "set5");
test_fetch!(test_fetch_4_3_0_it_it_set6, "4_3_0", "it_it", "set6");
test_fetch!(test_fetch_4_3_0_it_it_set6cde, "4_3_0", "it_it", "set6cde");
test_fetch!(test_fetch_4_3_0_it_it_set7, "4_3_0", "it_it", "set7");
test_fetch!(test_fetch_latest_en_us_set1, "latest", "en_us", "set1");
test_fetch!(test_fetch_latest_en_us_set2, "latest", "en_us", "set2");
@ -117,6 +120,7 @@ mod tests {
test_fetch!(test_fetch_latest_en_us_set5, "latest", "en_us", "set5");
test_fetch!(test_fetch_latest_en_us_set6, "latest", "en_us", "set6");
test_fetch!(test_fetch_latest_en_us_set6cde, "latest", "en_us", "set6cde");
test_fetch!(test_fetch_latest_en_us_set7, "latest", "en_us", "set7");
}

View file

@ -229,13 +229,15 @@ impl EventHandler {
});
let (format, regions) = if let Some(regions) = deck.eternal(&engine.cards) {
("<:neutral:1056022926660481094> Eternal", regions)
("<:eternal:1095374779130839151> Eternal", regions)
} else if let Some(regions) = deck.standard(&engine.cards) {
("<:standard:1095374776492638208> Standard", regions)
} else if let Some(regions) = deck.unlimited_champions(&engine.cards) {
("<:neutral:1056022926660481094> Unlimited Champions", regions)
("Unlimited Champions", regions)
} else if let Some(regions) = deck.singleton(&engine.cards) {
("<:neutral:1056022926660481094> Singleton", regions)
("Singleton", regions)
} else {
("<:invaliddeck:1056022952396730438> Unknown", HashSet::new())
("Unknown", HashSet::new())
};
response.embed(|e| {