1
Fork 0
mirror of https://github.com/Steffo99/patched-porobot.git synced 2024-12-22 09:34:21 +00:00

Rewrite the whole card schema in a better way

This commit is contained in:
Steffo 2022-08-02 14:13:31 +02:00
parent bbd01ffdc2
commit 1135f5b09c
Signed by: steffo
GPG key ID: 6965406171929D01
11 changed files with 677 additions and 219 deletions

2
.gitignore vendored
View file

@ -1,3 +1,5 @@
/card-data/
# Generated by Cargo
# will have compiled files and executables
/target/

View file

@ -1,219 +0,0 @@
use std::collections::HashMap;
/// A single Legends of Runeterra card as represented in the data files from [Data Dragon](https://developer.riotgames.com/docs/lor).
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
#[serde(rename_all="camelCase")]
pub struct Card {
/// Codes of other cards associated with this one.
///
/// To access references to the cards themselves, use [associated_cards].
#[serde(rename = "associated_card_refs")]
pub associated_card_codes: Vec<String>,
/// Art assets of this card.
pub assets: Vec<Asset>,
/// Regions this card belongs to.
#[serde(rename = "region_refs")]
pub regions: Vec<CardRegion>,
/// Base attack of the card.
pub attack: u64,
/// Base cost of the card.
pub cost: u64,
/// Base health of the card.
pub health: u64,
/// Localized description of the card, in XML.
pub description: String,
/// Localized description of the card, in plain text.
pub description_raw: String,
/// Localized level up text of the card, in XML.
pub levelup_description: String,
/// Localized level up text of the card, in plain text.
pub levelup_description_raw: String,
/// Flavor text of the card, displayed when its image is inspected.
pub flavor_text: String,
/// Name of the artist who drew the card.
pub artist_name: String,
/// Localized name of the card.
pub name: String,
/// Unique seven-character identifier of the card.
#[serde(rename = "card_code")]
pub code: String,
/// List of keywords of this card, with their localized names.
pub keywords: Vec<String>,
/// List of keywords of this card, with their internal names.
pub keyword_refs: Vec<String>,
/// [SpellSpeed] of the card.
#[serde(rename = "spell_speed_ref")]
pub spell_speed: SpellSpeed,
/// [CardRarity] of the card.
#[serde(rename = "rarity_ref")]
pub rarity: CardRarity,
/// The subtypes the card has, such as `PORO`.
pub subtypes: Vec<String>,
/// The [CardSupertype] the card belongs to, such as `Champion`.
pub supertype: String,
/// If `true`, the card can be found in chests, crafted, or used in decks.
/// If `false`, the card is not available for direct use, as it is probably created by another card.
pub collectible: bool,
/// The [CardSet] the card belongs to.
pub set: String,
#[serde(rename(serialize = "type", deserialize = "type"))]
pub card_type: CardType,
}
impl Card {
/// Get references to the cards associated with this one, given an hashmap of all cards.
pub fn associated_cards<'c, 'hm: 'c>(&'c self, hashmap: &'hm HashMap<String, Card>) -> impl Iterator<Item=Option<&'hm Card>> + 'c {
self.associated_card_codes.iter().map(|r| hashmap.get(r))
}
}
/// A region to which cards can belong to.
#[non_exhaustive]
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub enum CardRegion {
/// Noxus.
Noxus,
/// Demacia.
Demacia,
/// Freljord.
Freljord,
/// Shadow Isles.
ShadowIsles,
/// Targon.
Targon,
/// Ionia.
Ionia,
/// Shurima.
Shurima,
/// Piltover & Zaun.
PiltoverZaun,
/// Bandle City.
BandleCity,
/// Runeterra.
Runeterra,
/// Origin: The Virtuoso.
Jhin,
/// Origin: Agony's Embrace.
Evelynn,
/// Origin: The Wandering Caretaker.
Bard,
/// Unsupported region.
#[serde(other)]
Unsupported,
}
/// An art asset associated with a given card.
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
#[serde(rename_all="camelCase")]
pub struct Asset {
/// URL to the card art as it is displayed in-game.
pub game_absolute_path: String,
/// URL to the full-size card art as it is displayed when the card is inspected.
pub full_absolute_path: String,
}
/// A possible card type.
#[non_exhaustive]
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub enum CardType {
/// A spell.
Spell,
/// An unit: either a minion, or a champion.
/// Champions have their `supertype` set to `Champion`, and their `rarity` set to `Champion` as well.
Unit,
/// An ability triggered by an unit.
Ability,
/// A landmark.
Landmark,
/// A trap or boon.
Trap,
/// Unsupported card type.
#[serde(other)]
Unsupported,
}
/// A possible card rarity.
#[non_exhaustive]
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub enum CardRarity {
/// The card has no rarity, as it probably is not collectible.
#[serde(alias = "NONE")]
None,
/// A common card.
#[serde(alias = "COMMON")]
Common,
/// A rare card.
#[serde(alias = "RARE")]
Rare,
/// An epic card.
#[serde(alias = "EPIC")]
Epic,
/// A champion.
#[serde(alias = "CHAMPION")]
Champion,
/// Unsupported card rarity.
#[serde(other)]
Unsupported,
}
/// Possible spell speeds.
#[non_exhaustive]
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub enum SpellSpeed {
/// Non-spell cards have this speed.
#[serde(alias = "")]
None,
Slow,
Fast,
/// Both Focus and Burst cards have `Burst` speed; to disambiguate between the two, check for the `Focus` keyword.
Burst,
}
/// Release sets [Card]s may belong to.
#[non_exhaustive]
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub enum CardSet {
#[serde(rename = "Set1")]
Foundations,
#[serde(rename = "Set2")]
RisingTides,
#[serde(rename = "Set3")]
CallOfTheMountain,
#[serde(rename = "Set4")]
EmpiresOfTheAscended,
#[serde(rename = "Set5")]
BeyondTheBandlewood,
#[serde(rename = "Set6")]
Worldwalker,
#[serde(rename = "SetEvent")]
Events,
}

54
src/data/schema/art.rs Normal file
View file

@ -0,0 +1,54 @@
//! Module defining [CardArt].
/// An art asset associated with a [Card].
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct CardArt {
/// URL to the `.png` image of the rendered card.
///
/// # Example
///
/// `https://dd.b.pvp.net/latest/set1/en_us/img/cards/01DE001.png`
///
#[serde(rename = "gameAbsolutePath")]
pub card_png: String,
/// URL to the `.png` image of the full card art.
///
/// # Example
///
/// `https://dd.b.pvp.net/latest/set1/en_us/img/cards/01DE001-full.png`
///
#[serde(rename = "fullAbsolutePath")]
pub full_png: String,
}
impl CardArt {
/// URL to the `.jpg` image of the rendered card, via `poro.steffo.eu`.
///
/// Please do not overload this endpoint, as it currently does not use a CDN!
///
/// # Example
///
/// `https://poro.steffo.eu/set1-en_us/en_us/img/cards/01DE001.jpg`
///
pub fn card_jpg(&self) -> String {
self.card_png
.replace("https://dd.b.pvp.net/latest/set1", "https://poro.steffo.eu/set1-en_us")
.replace(".png", ".jpg")
}
/// URL to the `.jpg` image of the full card art, via `poro.steffo.eu`.
///
/// Please do not overload this endpoint, as it currently does not use a CDN!
///
/// # Example
///
/// `https://poro.steffo.eu/set1-en_us/en_us/img/cards/01DE001-full.jpg`
///
pub fn full_jpg(&self) -> String {
self.full_png
.replace("https://dd.b.pvp.net/latest/set1", "https://poro.steffo.eu/set1-en_us")
.replace(".png", ".jpg")
}
}

128
src/data/schema/card.rs Normal file
View file

@ -0,0 +1,128 @@
//! Module defining [Card].
use std::collections::HashMap;
use super::art::CardArt;
use super::set::CardSet;
use super::r#type::CardType;
use super::region::CardRegion;
use super::keyword::CardKeyword;
use super::rarity::CardRarity;
use super::speed::SpellSpeed;
/// A single Legends of Runeterra card as represented in the data files from [Data Dragon](https://developer.riotgames.com/docs/lor).
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
#[serde(rename_all="camelCase")]
pub struct Card {
/// Unique seven-character identifier of the card.
#[serde(rename = "card_code")]
pub code: String,
/// Localized name of the card.
pub name: String,
/// The [CardType] of the card.
#[serde(rename = "type")]
pub r#type: CardType,
/// The [CardSet] the card belongs to.
pub set: CardSet,
/// [CardRarity] of the card.
#[serde(rename = "rarityRef")]
pub rarity: CardRarity,
/// If `true`, the card can be found in chests, crafted, or used in decks.
/// If `false`, the card is not available for direct use, as it is probably created by another card.
pub collectible: bool,
/// Regions this card belongs to.
#[serde(rename = "regionRefs")]
pub regions: Vec<CardRegion>,
/// Localized names of the regions this card belongs to.
#[deprecated = "Only for re-serialization purposes, use regions instead!"]
#[serde(rename = "regions")]
pub regions_localized: Vec<String>,
/// A [Vec] of [CardArt] assets of the card.
///
/// Should always contain at least an element; may sometimes contain two or more.
///
/// To quickly access the first element, use [main_art].
#[serde(rename = "assets")]
pub art: Vec<CardArt>,
/// Base attack of the card.
pub attack: u64,
/// Base cost of the card.
pub cost: u64,
/// Base health of the card.
pub health: u64,
/// [SpellSpeed] of the card.
#[serde(rename = "spell_speed_ref")]
pub spell_speed: SpellSpeed,
/// Localized name of the [SpellSpeed] of the card.
#[deprecated = "Only for re-serialization purposes, use spell_speed instead!"]
pub spell_speed_localized: String,
/// List of keywords of this card.
#[serde(rename="keyword_refs")]
pub keywords: Vec<CardKeyword>,
/// Localized names of keywords of this card.
#[deprecated = "Only for re-serialization purposes, use keywords instead!"]
#[serde(rename="keywords")]
pub keywords_localized: Vec<String>,
/// Localized description of the card, in XML.
pub description: String,
/// Localized description of the card, in plain text.
pub description_raw: String,
/// Localized level up text of the card, in XML.
///
/// If the card has no level up text, contains an empty string.
pub levelup_description: String,
/// Localized level up text of the card, in plain text.
///
/// If the card has no level up text, contains an empty string.
pub levelup_description_raw: String,
/// [Codes](code) of other cards associated with this one.
///
/// To access references to the cards themselves, use [associated_cards].
#[serde(rename = "associatedCardRefs")]
pub associated_card_codes: Vec<String>,
/// [Names](name) of other cards associated with this one.
#[deprecated = "Only for re-serialization purposes, use associated_card_codes instead!"]
#[serde(rename = "associatedCards")]
pub associated_card_names_localized: Vec<String>,
/// Flavor text of the card, displayed when its image is inspected.
pub flavor_text: String,
/// Name of the artist who drew the card.
pub artist_name: String,
/// The subtypes the card has, such as `PORO`.
pub subtypes: Vec<String>,
/// The [CardSupertype] the card belongs to, such as `Champion`.
pub supertype: String,
}
impl Card {
/// Get references to the cards associated with this one, given an hashmap of all cards.
pub fn associated_cards<'c, 'hm: 'c>(&'c self, hashmap: &'hm HashMap<String, Card>) -> impl Iterator<Item=Option<&'hm Card>> + 'c {
self.associated_card_codes.iter().map(|r| hashmap.get(r))
}
/// Get a reference to the first [CardArt] of the card.
///
/// # Panics
///
/// If the card has no associated [CardArt].
pub fn main_art(&self) -> &CardArt {
self.art.get(0).expect("card to have at least one art asset")
}
}

333
src/data/schema/keyword.rs Normal file
View file

@ -0,0 +1,333 @@
//! Module defining [CardKeyword].
/// A keyword which cards can have.
///
/// 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(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub enum CardKeyword {
/// Overwhelm on spells.
///
/// > Inflicts damage beyond what would kill the target(s) to the enemy Nexus.
SpellOverwhelm,
/// [SpellSpeed::Burst].
///
/// > Can be played whenever you may act. Happens instantly and allows you to continue to play other cards.
Burst,
/// Countdown.
///
/// > Round Start: I count down 1. At 0, activate the Countdown effect, then destroy me.
Countdown,
/// "Marked" play.
///
/// > Get this effect when you play this unit from hand.
#[serde(rename = "PlaySkillMark")]
OnPlay,
/// [CardType::Landmark].
///
/// > Landmarks take up a space on the board. They can't attack, block, or take damage.
#[serde(rename = "LandmarkVisualOnly")]
Landmark,
/// ???
Shurima,
/// Attach.
///
/// > Attach me to an ally to give it my stats and keywords while I'm attached. When that ally leaves play, Recall me.
Attach,
/// ???
Noxus,
/// Fleeting cards discard from hand when the round ends.
Fleeting,
/// ??????
ClobberNoEmptySlotRequirement,
/// Nab.
///
/// > Draw a non-champion card from the bottom of the enemy deck.
Nab,
/// Focus.
///
/// Used to disambiguate between Burst and Focus with [SpellSpeed::Burst].
///
/// > Can be played outside combat or when no other spells or skills are pending. Happens instantly and allows you to continue to play other cards.
Focus,
/// Enlightened.
///
/// > You're Enlightened when you have 10 max mana.
Enlightened,
/// Invoke.
///
/// > Pick a Celestial card from among 3 to create in hand.
Invoke,
/// Boon.
///
/// > Attaches to another card in a deck. When that card is drawn, activate the effect.
Boon,
/// Trap.
///
/// > Attaches to another card in a deck. When that card is drawn, activate the effect.
#[serde(rename = "Autoplay")]
Trap,
/// Drain.
///
/// > Heal your Nexus for the amount of damage dealt.
Drain,
/// Last Breath.
///
/// > These abilities take effect when the unit dies.
LastBreath,
/// ???
Demacia,
/// ???
BandleCity,
/// [SpellSpeed::Fast].
///
/// > Can be played whenever you may act. Happens after your opponent has a chance to react.
Fast,
/// ???
Bilgewater,
/// ???
Runeterra,
/// Recall.
///
/// > Return a unit to hand and remove all effects applied to it.
Recall,
/// Weakest.
///
/// > Lowest Power, with ties broken by lowest Health then lowest Cost
Weakest,
/// Support.
///
/// > Attacking with a support unit will buff the unit to its right.
Support,
/// Slow.
///
/// > Can be played outside of combat when no spells or skills are pending. Happens after your opponent has a chance to react.
Slow,
/// Obliterate.
///
/// > Completely removed from the game. Doesn't cause Last Breath and can't be revived.
Obliterate,
/// Imbue, an unused keyword.
///
/// > These abilities trigger when you resolve a spell.
Imbue,
/// ???
#[serde(rename = "MtTargon")]
Targon,
/// ???
ShadowIsles,
/// ??????
AuraVisualFakeKeyword,
/// ???
Ionia,
/// Nightfall.
///
/// > Bonus if this is NOT the first card you play in a round.
Nightfall,
/// ???
PiltoverZaun,
/// Attune.
///
/// > When I'm summoned, refill 1 spell mana.
Attune,
/// Daybreak.
///
/// > Bonus if this is the FIRST card you play in a round.
Daybreak,
/// ???
SilenceIndividualKeyword,
/// Skill.
///
/// > A unit's spell-like effect that allows enemy reactions.
Skill,
/// Plunder,
///
/// > A card triggers its plunder ability when played if you damaged the enemy Nexus this round.
Plunder,
/// Double Attack.
///
/// > While attacking, it strikes both before AND at the same time as its blocker.
DoubleAttack,
/// Vulnerable.
///
/// > The enemy can challenge this unit, forcing it to block.
Vulnerable,
/// Elusive.
///
/// > Can only be blocked by an Elusive unit.
Elusive,
/// Stun.
///
/// > Remove a unit from combat. It can't attack or block for the rest of the round.
Stun,
/// Fated.
///
/// > Each round, the first time an allied card targets me, grant me +1|+1.
Fated,
/// ???
///
/// > Can block Elusives.
BlockElusive,
/// Fury.
///
/// > When I kill a unit, grant me +1|+1.
Fury,
/// Barrier.
///
/// > Negates the next damage the unit would take. Lasts one round.
Barrier,
/// Immobile.
///
/// > Can't attack or block.
Immobile,
/// Hallowed.
///
/// > After I die, for the rest of the game when allies attack, hallow your first attacker giving it +1|+0 that round.
Hallowed,
/// Evolve.
///
/// > I have +2|+2 once you've given or summoned allies with 6+ other positive keywords this game.
Evolve,
/// Frostbite.
///
/// > Set a unit's Power to 0 this round. It can be changed after.
Frostbite,
/// Overwhelm on units.
///
/// > Excess damage I deal to my blocker is dealt to the enemy Nexus.
Overwhelm,
/// Quick Attack.
///
/// > While attacking, strikes before its blocker.
#[serde(rename="QuickStrike")]
QuickAttack,
/// Tough.
///
/// > Takes 1 less damage from all sources.
Tough,
/// Regeneration.
///
/// > Heals fully at the end of each round.
Regeneration,
/// Silenced.
///
/// > Removes all text and keywords from a unit.
Silenced,
/// SpellShield.
///
/// > Negates the next enemy spell or skill that would affect me.
SpellShield,
/// Lifesteal.
///
/// > Damage this unit deals heals its Nexus that amount.
Lifesteal,
/// Augment.
///
/// > When you play a created card, grant me +1|+0.
Augment,
/// Impact.
///
/// > When this strikes while attacking, it deals 1 to the enemy Nexus. This keyword can stack.
Impact,
/// Scout.
///
/// > The first time only Scout units attack each round, ready your attack.
Scout,
/// Ephemereal.
///
/// > This unit dies when it strikes or when the round ends.
Ephemeral,
/// Lurk.
///
/// > When you attack while I'm on top of your deck, I Lurk, granting Lurker allies everywhere +1|+0. Max once per round.
#[serde(rename="Lurker")]
Lurk,
/// Formidable.
///
/// > I strike with my Health instead of my Power.
Formidable,
/// Challenger.
///
/// > Can choose which enemy unit blocks.
Challenger,
/// Fearsome.
///
/// > Can only be blocked by enemies with 3 or more Power.
Fearsome,
/// Can't Block.
CantBlock,
/// Deep.
Deep,
/// Unsupported card keyword.
#[serde(other)]
Unsupported,
}

19
src/data/schema/mod.rs Normal file
View file

@ -0,0 +1,19 @@
//! This module defines the [Card] type and the types used in it to better describe attributes.
mod card;
mod art;
mod r#type;
mod rarity;
mod region;
mod set;
mod speed;
mod keyword;
pub use card::Card;
pub use art::CardArt;
pub use r#type::CardType;
pub use rarity::CardRarity;
pub use region::CardRegion;
pub use set::CardSet;
pub use speed::SpellSpeed;
pub use keyword::CardKeyword;

21
src/data/schema/rarity.rs Normal file
View file

@ -0,0 +1,21 @@
//! Module defining [CardRarity].
/// A possible card rarity.
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub enum CardRarity {
/// The card has no rarity, as it probably is not collectible.
#[serde(alias = "NONE")]
None,
/// A common card.
#[serde(alias = "COMMON")]
Common,
/// A rare card.
#[serde(alias = "RARE")]
Rare,
/// An epic card.
#[serde(alias = "EPIC")]
Epic,
/// A champion.
#[serde(alias = "CHAMPION")]
Champion,
}

41
src/data/schema/region.rs Normal file
View file

@ -0,0 +1,41 @@
//! Module defining [CardRegion].
/// A region to which cards can belong to.
///
/// Since more regions might be added in the future, especially Origin ones, this enum is [non_exaustive](https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute).
#[non_exhaustive]
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub enum CardRegion {
/// Noxus.
Noxus,
/// Demacia.
Demacia,
/// Freljord.
Freljord,
/// Shadow Isles.
ShadowIsles,
/// Targon.
Targon,
/// Ionia.
Ionia,
/// Shurima.
Shurima,
/// Piltover & Zaun.
PiltoverZaun,
/// Bandle City.
BandleCity,
/// Runeterra.
Runeterra,
/// Origin: The Virtuoso.
Jhin,
/// Origin: Agony's Embrace.
Evelynn,
/// Origin: The Wandering Caretaker.
Bard,
/// Unsupported region.
#[serde(other)]
Unsupported,
}

40
src/data/schema/set.rs Normal file
View file

@ -0,0 +1,40 @@
//! Module defining [CardSet].
/// The release set a [Card] may belong to.
///
/// Since more sets will definitely 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(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub enum CardSet {
/// Foundations, or "base".
#[serde(rename = "Set1")]
Foundations,
/// Rising Tides.
#[serde(rename = "Set2")]
RisingTides,
/// Call of the Mountain.
#[serde(rename = "Set3")]
CallOfTheMountain,
/// Empires of the Ascended.
#[serde(rename = "Set4")]
EmpiresOfTheAscended,
/// Beyond the Bandlewood.
#[serde(rename = "Set5")]
BeyondTheBandlewood,
/// Worldwalker.
#[serde(rename = "Set6")]
Worldwalker,
/// Events, with cards released "outside" a set.
#[serde(rename = "SetEvent")]
Events,
/// Unsupported card set.
#[serde(other)]
Unsupported,
}

15
src/data/schema/speed.rs Normal file
View file

@ -0,0 +1,15 @@
//! Module defining [SpellSpeed].
/// A possible spell speed.
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub enum SpellSpeed {
/// Non-spell cards have this speed.
#[serde(alias = "")]
None,
/// A Slow spell.
Slow,
/// A Fast spell.
Fast,
/// Either a Burst or a Focus spell; to disambiguate between the two, check for the `Focus` keyword.
Burst,
}

24
src/data/schema/type.rs Normal file
View file

@ -0,0 +1,24 @@
//! Module defining [Type].
/// A possible card type.
///
/// Since more types might be added in the future, as it happened with landmarks, this enum is [non_exaustive](https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute).
#[non_exhaustive]
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub enum CardType {
/// A spell.
Spell,
/// An unit: either a minion, or a champion.
/// Champions have their `supertype` set to `Champion`, and their `rarity` set to `Champion` as well.
Unit,
/// An ability triggered by an unit.
Ability,
/// A landmark.
Landmark,
/// A trap or boon.
Trap,
/// Unsupported card type.
#[serde(other)]
Unsupported,
}