1
Fork 0
mirror of https://github.com/Steffo99/patched-porobot.git synced 2024-10-16 09:37:27 +00:00

Add CardType::Equipment and rewrite Telegram rendering code

This commit is contained in:
Steffo 2023-07-03 05:27:50 +02:00
parent 933907cd5f
commit 140a35e6a4
Signed by: steffo
GPG key ID: 2A24051445686895
2 changed files with 198 additions and 98 deletions

View file

@ -9,6 +9,9 @@ pub enum CardType {
/// A spell.
Spell,
/// A equipment.
Equipment,
/// An unit: either a minion, or a champion.
///
/// Champions have their [supertype](super::card::Card::supertype) set to `Champion`, and their [rarity](super::card::Card::rarity) set to [CardRarity::Champion](super::rarity::CardRarity::Champion) as well.
@ -33,6 +36,7 @@ pub enum CardType {
impl From<&CardType> for &'static str {
fn from(r#type: &CardType) -> Self {
match r#type {
CardType::Equipment => "Equipment",
CardType::Spell => "Spell",
CardType::Unit => "Unit",
CardType::Ability => "Ability",

View file

@ -23,118 +23,163 @@ use teloxide::utils::html::escape;
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
pub fn display_card(globals: &LocalizedGlobalsIndexes, card: &Card) -> String {
let title = format!("<b><u>{}</u></b>\n", escape(&card.name),);
let stats = match &card.r#type {
CardType::Spell => format!("{} mana\n\n", escape(&card.cost.to_string()),),
let title: String = display_title(&card.name);
let r#type: String = display_type(globals, card);
let stats = display_stats(card);
let subtypes: String = display_subtypes(&card.subtypes);
let header = format!("{} ({})\n{}\n{}\n", &title, &r#type, &stats, &subtypes);
let keywords = display_keywords(&card.keywords, &globals.keywords);
let description = display_description(&card.localized_description_text);
let levelup = display_levelup(&card.localized_levelup_text);
let body = format!("{}{}{}", &keywords, &description, &levelup);
let set = display_set(&card.set, &globals.sets);
let regions = display_regions(&card.regions, &globals.regions);
let flavor = display_flavor(&card.main_art().expect("Card to have at least one illustration").full_png, &card.localized_flavor_text);
let footer = format!("{}{}\n{}", &set, &regions, &flavor);
format!("{}\n\n{}\n\n{}", &header, &body, &footer)
}
/// Render a [Card]'s title in [Telegram Bot HTML].
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
fn display_title(name: &str) -> String {
format!("<b><u>{}</u></b>", escape(name))
}
/// Render the [Card]'s in-game type in [Telegram Bot HTML].
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
fn display_type(globals: &LocalizedGlobalsIndexes, card: &Card) -> String {
match card.r#type {
CardType::Spell => {
"Spell".to_string()
}
CardType::Equipment => {
CardKeyword::Equipment.localized(&globals.keywords).map(|l| l.name.clone()).unwrap_or_else(|| "EQUIPMENT".to_string())
}
CardType::Unit => {
if card.supertype.eq(&CardSupertype::Champion) {
"Champion".to_string()
}
else {
"Unit".to_string()
}
}
CardType::Ability => {
if card.keywords.contains(&CardKeyword::Skill) {
CardKeyword::Skill.localized(&globals.keywords).map(|l| l.name.clone()).unwrap_or_else(|| "SKILL".to_string())
}
else {
"Ability".to_string() // Does this exist?
}
}
CardType::Landmark => {
CardKeyword::Landmark.localized(&globals.keywords).map(|l| l.name.clone()).unwrap_or_else(|| "LANDMARK".to_string())
}
CardType::Trap => {
if card.keywords.contains(&CardKeyword::Trap) {
CardKeyword::Trap.localized(&globals.keywords).map(|l| l.name.clone()).unwrap_or_else(|| "TRAP".to_string())
}
else if card.keywords.contains(&CardKeyword::Boon) {
CardKeyword::Boon.localized(&globals.keywords).map(|l| l.name.clone()).unwrap_or_else(|| "Boon".to_string())
}
else {
"Trigger".to_string() // Does this exist?
}
}
CardType::Unsupported => {
"UNKNOWN?".to_string()
}
}
}
fn display_stats(card: &Card) -> String {
match &card.r#type {
CardType::Spell => format!("{} mana", escape(&card.cost.to_string())),
CardType::Unit => format!(
"{} mana {}|{}\n\n",
"{} mana · {}|{}",
escape(&card.cost.to_string()),
escape(&card.attack.to_string()),
escape(&card.health.to_string()),
),
CardType::Landmark => format!("{} mana\n\n", &card.cost),
CardType::Landmark => format!("{} mana", &card.cost),
_ => "".to_string(),
};
let set = display_set(&card.set, &globals.sets);
let regions = display_regions(&card.regions, &globals.regions);
let r#type = display_types(&card.r#type, &card.supertype, &card.subtypes);
let breadcrumbs = format!("{} {} {}\n\n", &set, &regions, &r#type);
let keywords = display_keywords(&card.keywords, &globals.keywords);
let description = display_description(&card.localized_description_text);
let levelup = display_levelup(&card.localized_levelup_text);
let flavor = format!("<i>{}</i>\n", escape(&card.localized_flavor_text));
let artist = format!(
r#"<a href="{}">Illustration</a> by {}"#,
&card
.main_art()
.expect("Card to have at least one illustration")
.full_png,
escape(&card.artist_name)
);
format!(
"{}{}{}{}{}{}-----\n{}{}",
&title, &breadcrumbs, &keywords, &stats, &description, &levelup, &flavor, &artist,
)
}
/// Render a [CardSet] in [Telegram Bot HTML].
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
fn display_set(set: &CardSet, hm: &LocalizedCardSetIndex) -> String {
format!(
"<i>{}</i>",
set.localized(hm)
.map(|o| format!("<i>{}</i>", escape(&o.name)))
.unwrap_or_else(|| "Unknown".to_string())
)
}
/// Render a slice of [CardRegion]s in [Telegram Bot HTML].
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
fn display_regions(regions: &[CardRegion], hm: &LocalizedCardRegionIndex) -> String {
regions
.iter()
.map(|region| {
region
.localized(hm)
.map(|o| format!("<i>{}</i>", escape(&o.name)))
.unwrap_or_else(|| "Unknown".to_string())
})
.join(", ")
}
/// Render the [CardType], the [CardSupertype] and the [CardSubtype]s in [Telegram Bot HTML].
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
fn display_types(r#type: &CardType, supertype: &CardSupertype, subtypes: &[CardSubtype]) -> String {
let mut result = String::new();
result.push_str(
match supertype {
CardSupertype::Champion => "<i>Champion</i> ",
CardSupertype::Unsupported => "<i>Unknown</i> ",
_ => "",
}
);
result.push_str(&format!("<i>{}</i>", escape(&String::from(r#type)),));
if !subtypes.is_empty() {
result.push_str(&format!(
" {}",
subtypes
.iter()
.map(|subtype| format!("<i>{}</i>", escape(subtype)))
.join(", ")
))
}
}
result
/// Render the [CardSubtype]s in [Telegram Bot HTML].
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
fn display_subtypes(subtypes: &[CardSubtype]) -> String {
let result = subtypes
.iter()
.map(|s| titlecase(&s))
.map(|s| escape(&s))
.map(|s| format!("<i>{s}</i>"))
.join(", ");
if result.is_empty() {
result
} else {
result + "\n"
}
}
/// Render a slice of [CardKeyword]s in [Telegram Bot HTML].
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
fn display_keywords(keywords: &[CardKeyword], hm: &LocalizedCardKeywordIndex) -> String {
format!(
"{}\n",
keywords
.iter()
.map(|keyword| keyword
.localized(hm)
.map(|o| format!("[<b>{}</b>]", escape(&o.name)))
.unwrap_or_else(|| "Unknown".to_string()))
.join(" ")
)
let result = keywords
.iter()
.filter(|keyword| match keyword {
CardKeyword::Countdown => false,
CardKeyword::OnPlay => false,
CardKeyword::Landmark => false,
CardKeyword::Shurima => false,
CardKeyword::Noxus => false,
CardKeyword::ClobberNoEmptySlotRequirement => false,
CardKeyword::Nab => false,
CardKeyword::Enlightened => false,
CardKeyword::Invoke => false,
CardKeyword::Drain => false,
CardKeyword::LastBreath => false,
CardKeyword::Demacia => false,
CardKeyword::BandleCity => false,
CardKeyword::Bilgewater => false,
CardKeyword::Runeterra => false,
CardKeyword::Recall => false,
CardKeyword::Weakest => false,
CardKeyword::Support => false,
CardKeyword::Obliterate => false,
CardKeyword::Imbue => false,
CardKeyword::Targon => false,
CardKeyword::ShadowIsles => false,
CardKeyword::AuraVisualFakeKeyword => false,
CardKeyword::Ionia => false,
CardKeyword::PiltoverZaun => false,
CardKeyword::SilenceIndividualKeyword => false,
CardKeyword::Plunder => false,
CardKeyword::Silenced => false,
_ => true,
})
.map(|keyword| keyword
.localized(hm)
.map(|o| format!("[<b>{}</b>: {}]\n", escape(&o.name), escape(&o.description)))
.unwrap_or_else(|| "[<b>UNKNOWN?</b>]\n".to_string()))
.join("");
if result.is_empty() {
result
} else {
result + "\n"
}
}
/// Render a [Card::localized_description_text] in [Telegram Bot HTML].
@ -159,6 +204,46 @@ fn display_levelup(levelup: &String) -> String {
}
}
/// Render a [CardSet] in [Telegram Bot HTML].
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
fn display_set(set: &CardSet, hm: &LocalizedCardSetIndex) -> String {
format!(
"<i>{}</i>",
set.localized(hm)
.map(|o| format!("<i>{}</i>", escape(&o.name)))
.unwrap_or_else(|| "UNKNOWN?".to_string())
)
}
/// Render a slice of [CardRegion]s in [Telegram Bot HTML].
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
fn display_regions(regions: &[CardRegion], hm: &LocalizedCardRegionIndex) -> String {
let result = regions
.iter()
.map(|region| {
region
.localized(hm)
.map(|o| format!("<u>{}</u>", escape(&o.name)))
.unwrap_or_else(|| "UNKNOWN?".to_string())
})
.join(", ");
if result.is_empty() {
result
} else {
format!(" · {}", &result)
}
}
/// Render the flavor text of a [Card] in [Telegram Bot HTML], linking to the given art.
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
fn display_flavor(art_url: &str, localized_flavor_text: &str) -> String {
format!("<a href=\"{}\"><i>{}</i></a>", &art_url, escape(localized_flavor_text))
}
/// Render a [Deck] in [Telegram Bot HTML], with an optional `name`.
///
/// [Telegram Bot HTML]: https://core.telegram.org/bots/api#html-style
@ -205,7 +290,7 @@ pub fn display_deck(index: &CardIndex, deck: &Deck, code: &str, name: &Option<&s
let mut tags: Vec<&'static str> = vec![];
let regions = if let Some(regions) = deck.standard(index) {
tags.push("#Standard_4_3");
tags.push("#Standard_4_5");
regions
} else if let Some(regions) = deck.eternal(index) {
tags.push("#Eternal");
@ -245,3 +330,14 @@ pub fn display_deck(index: &CardIndex, deck: &Deck, code: &str, name: &Option<&s
None => format!("<code>{}</code>\n{}\n{}", &code, &tags, &cards),
}
}
// https://stackoverflow.com/a/38406885/4334568
fn titlecase(s: &str) -> String {
let s = s.to_lowercase();
let mut c = s.chars();
match c.next() {
None => String::new(),
Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
}
}