diff --git a/.golangci.yml b/.golangci.yml
index c7e78fa..2e0b085 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -23,9 +23,10 @@ linters:
- unused
settings:
gocyclo:
- # handleLoldle / handleEmoji dispatch on game outcome (won / lost /
- # ongoing) plus error returns; 19 reads cleaner inline than as 3 helpers.
- min-complexity: 20
+ # The loldle handlers dispatch on game outcome (won / lost / ongoing)
+ # plus error returns plus pre-flight validation. Reads cleaner inline
+ # than as 4 nano-helpers; cap is empirical, not a design target.
+ min-complexity: 22
gosec:
excludes:
# G104 (unhandled errors) — already enforced via errcheck with
diff --git a/cmd/server/main.go b/cmd/server/main.go
index 58ea4a4..1828092 100644
--- a/cmd/server/main.go
+++ b/cmd/server/main.go
@@ -14,6 +14,7 @@ import (
"github.com/tiennm99/miti99bot-go/internal/log"
"github.com/tiennm99/miti99bot-go/internal/modules"
"github.com/tiennm99/miti99bot-go/internal/modules/loldle"
+ "github.com/tiennm99/miti99bot-go/internal/modules/loldleability"
"github.com/tiennm99/miti99bot-go/internal/modules/loldleemoji"
"github.com/tiennm99/miti99bot-go/internal/modules/loldlequote"
"github.com/tiennm99/miti99bot-go/internal/modules/misc"
@@ -32,9 +33,10 @@ func factories() map[string]modules.Factory {
"util": util.New,
"misc": misc.New,
"wordle": wordle.New,
- "loldle": loldle.New,
- "loldle-emoji": loldleemoji.New,
- "loldle-quote": loldlequote.New,
+ "loldle": loldle.New,
+ "loldle-ability": loldleability.New,
+ "loldle-emoji": loldleemoji.New,
+ "loldle-quote": loldlequote.New,
}
}
diff --git a/internal/modules/loldleability/champions.go b/internal/modules/loldleability/champions.go
new file mode 100644
index 0000000..727984f
--- /dev/null
+++ b/internal/modules/loldleability/champions.go
@@ -0,0 +1,63 @@
+// Package loldleability ports the JS loldle-ability variant — guess the
+// champion from a single ability icon. Pool seeded from Riot Data Dragon
+// (passive + Q/W/E/R for each champion). Uses Telegram's sendPhoto with the
+// DDragon CDN URL as the file source — no binary embedding.
+//
+// Round state persists `{target, slot, guesses, startedAt}` so the SAME
+// ability icon shows across all turns until the round ends.
+package loldleability
+
+import (
+ _ "embed"
+ "encoding/json"
+ "fmt"
+)
+
+// Ability is one of P/Q/W/E/R for a champion.
+type Ability struct {
+ Slot string `json:"slot"` // P, Q, W, E, R
+ Name string `json:"name"`
+ Icon string `json:"icon"` // absolute DDragon CDN URL
+}
+
+// AbilityChampion is one record of abilities.json — championName + the full
+// ability list.
+type AbilityChampion struct {
+ ChampionName string `json:"championName"`
+ Key string `json:"key"` // DDragon internal id; not used by handlers but kept for parity
+ Abilities []Ability `json:"abilities"`
+}
+
+//go:embed data/abilities.json
+var rawAbilities []byte
+
+// loadPool parses abilities.json and drops champions with no abilities.
+// Panics on malformed data — corrupt regen is a build-time bug.
+func loadPool() []AbilityChampion {
+ var all []AbilityChampion
+ if err := json.Unmarshal(rawAbilities, &all); err != nil {
+ panic(fmt.Sprintf("loldleability: cannot decode abilities.json: %v", err))
+ }
+ out := make([]AbilityChampion, 0, len(all))
+ for _, c := range all {
+ if len(c.Abilities) > 0 {
+ out = append(out, c)
+ }
+ }
+ if len(out) == 0 {
+ panic("loldleability: abilities.json contained no usable records")
+ }
+ return out
+}
+
+// abilityBySlot finds the ability with the given slot ("Q", "W", ...).
+// Returns nil when the slot is unknown — caller treats that as a refresh
+// signal (start over).
+func abilityBySlot(c *AbilityChampion, slot string) *Ability {
+ for i := range c.Abilities {
+ if c.Abilities[i].Slot == slot {
+ return &c.Abilities[i]
+ }
+ }
+ return nil
+}
diff --git a/internal/modules/loldleability/data/abilities.json b/internal/modules/loldleability/data/abilities.json
new file mode 100644
index 0000000..44de7f9
--- /dev/null
+++ b/internal/modules/loldleability/data/abilities.json
@@ -0,0 +1,5334 @@
+[
+ {
+ "championName": "Aatrox",
+ "key": "Aatrox",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Deathbringer Stance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Aatrox_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "The Darkin Blade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AatroxQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Infernal Chains",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AatroxW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Umbral Dash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AatroxE.png"
+ },
+ {
+ "slot": "R",
+ "name": "World Ender",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AatroxR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Ahri",
+ "key": "Ahri",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Essence Theft",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Ahri_SoulEater2.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Orb of Deception",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AhriQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Fox-Fire",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AhriW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Charm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AhriE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Spirit Rush",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AhriR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Akali",
+ "key": "Akali",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Assassin's Mark",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Akali_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Five Point Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AkaliQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Twilight Shroud",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AkaliW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Shuriken Flip",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AkaliE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Perfect Execution",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AkaliR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Akshan",
+ "key": "Akshan",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Dirty Fighting",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/akshan_p.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Avengerang",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AkshanQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Going Rogue",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AkshanW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Heroic Swing",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AkshanE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Comeuppance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AkshanR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Alistar",
+ "key": "Alistar",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Triumphant Roar",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Alistar_E.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Pulverize",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Pulverize.png"
+ },
+ {
+ "slot": "W",
+ "name": "Headbutt",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Headbutt.png"
+ },
+ {
+ "slot": "E",
+ "name": "Trample",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AlistarE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Unbreakable Will",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FerociousHowl.png"
+ }
+ ]
+ },
+ {
+ "championName": "Ambessa",
+ "key": "Ambessa",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Drakehound's Step",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Icon_Ambessa_Passive.Domina.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Cunning Sweep / Sundering Slam",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AmbessaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Repudiation",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AmbessaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Lacerate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AmbessaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Public Execution",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AmbessaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Amumu",
+ "key": "Amumu",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Cursed Touch",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Amumu_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Bandage Toss",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BandageToss.png"
+ },
+ {
+ "slot": "W",
+ "name": "Despair",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AuraofDespair.png"
+ },
+ {
+ "slot": "E",
+ "name": "Tantrum",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Tantrum.png"
+ },
+ {
+ "slot": "R",
+ "name": "Curse of the Sad Mummy",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CurseoftheSadMummy.png"
+ }
+ ]
+ },
+ {
+ "championName": "Anivia",
+ "key": "Anivia",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Rebirth",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Anivia_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Flash Frost",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FlashFrost.png"
+ },
+ {
+ "slot": "W",
+ "name": "Crystallize",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Crystallize.png"
+ },
+ {
+ "slot": "E",
+ "name": "Frostbite",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Frostbite.png"
+ },
+ {
+ "slot": "R",
+ "name": "Glacial Storm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GlacialStorm.png"
+ }
+ ]
+ },
+ {
+ "championName": "Annie",
+ "key": "Annie",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Pyromania",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Annie_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Disintegrate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AnnieQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Incinerate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AnnieW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Molten Shield",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AnnieE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Summon: Tibbers",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AnnieR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Aphelios",
+ "key": "Aphelios",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "The Hitman and the Seer",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/ApheliosP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Weapon Abilites",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ApheliosQ_ClientTooltipWrapper.png"
+ },
+ {
+ "slot": "W",
+ "name": "Phase",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ApheliosW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Weapon Queue System",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ApheliosE_ClientTooltipWrapper.png"
+ },
+ {
+ "slot": "R",
+ "name": "Moonlight Vigil",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ApheliosR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Ashe",
+ "key": "Ashe",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Frost Shot",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Ashe_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Ranger's Focus",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AsheQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Volley",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Volley.png"
+ },
+ {
+ "slot": "E",
+ "name": "Hawkshot",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AsheSpiritOfTheHawk.png"
+ },
+ {
+ "slot": "R",
+ "name": "Enchanted Crystal Arrow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EnchantedCrystalArrow.png"
+ }
+ ]
+ },
+ {
+ "championName": "Aurelion Sol",
+ "key": "AurelionSol",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Cosmic Creator",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/AurelionSolP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Breath of Light",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AurelionSolQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Astral Flight",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AurelionSolW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Singularity",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AurelionSolE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Falling Star / The Skies Descend",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AurelionSolR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Aurora",
+ "key": "Aurora",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Spirit Abjuration",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/AuroraPassive.Aurora.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Twofold Hex",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AuroraQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Across the Veil",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AuroraW.png"
+ },
+ {
+ "slot": "E",
+ "name": "The Weirding",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AuroraE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Between Worlds",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AuroraR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Azir",
+ "key": "Azir",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Shurima's Legacy",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Azir_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Conquering Sands",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AzirQWrapper.png"
+ },
+ {
+ "slot": "W",
+ "name": "Arise!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AzirW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Shifting Sands",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AzirEWrapper.png"
+ },
+ {
+ "slot": "R",
+ "name": "Emperor's Divide",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AzirR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Bard",
+ "key": "Bard",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Traveler's Call",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Bard_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Cosmic Binding",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BardQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Caretaker's Shrine",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BardW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Magical Journey",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BardE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Tempered Fate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BardR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Bel'Veth",
+ "key": "Belveth",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Death in Lavender ",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Belveth_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Void Surge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BelvethQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Above and Below",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BelvethW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Royal Maelstrom",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BelvethE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Endless Banquet",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BelvethR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Blitzcrank",
+ "key": "Blitzcrank",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Mana Barrier",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Blitzcrank_ManaBarrier.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Rocket Grab",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RocketGrab.png"
+ },
+ {
+ "slot": "W",
+ "name": "Overdrive",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Overdrive.png"
+ },
+ {
+ "slot": "E",
+ "name": "Power Fist",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PowerFist.png"
+ },
+ {
+ "slot": "R",
+ "name": "Static Field",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/StaticField.png"
+ }
+ ]
+ },
+ {
+ "championName": "Brand",
+ "key": "Brand",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Blaze",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/BrandP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Sear",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BrandQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Pillar of Flame",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BrandW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Conflagration",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BrandE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Pyroclasm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BrandR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Braum",
+ "key": "Braum",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Concussive Blows",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Braum_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Winter's Bite",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BraumQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Stand Behind Me",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BraumW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Unbreakable",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BraumE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Glacial Fissure",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BraumRWrapper.png"
+ }
+ ]
+ },
+ {
+ "championName": "Briar",
+ "key": "Briar",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Crimson Curse",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/BriarP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Head Rush",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BriarQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Blood Frenzy / Snack Attack",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BriarW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Chilling Scream",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BriarE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Certain Death",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/BriarR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Caitlyn",
+ "key": "Caitlyn",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Headshot",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Caitlyn_Headshot.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Piltover Peacemaker",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CaitlynQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Yordle Snap Trap",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CaitlynW.png"
+ },
+ {
+ "slot": "E",
+ "name": "90 Caliber Net",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CaitlynE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Ace in the Hole",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CaitlynR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Camille",
+ "key": "Camille",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Adaptive Defenses",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Camille_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Precision Protocol",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CamilleQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Tactical Sweep",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CamilleW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Hookshot",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CamilleE.png"
+ },
+ {
+ "slot": "R",
+ "name": "The Hextech Ultimatum",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CamilleR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Cassiopeia",
+ "key": "Cassiopeia",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Serpentine Grace",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Cassiopeia_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Noxious Blast",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CassiopeiaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Miasma",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CassiopeiaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Twin Fang",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CassiopeiaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Petrifying Gaze",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CassiopeiaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Cho'Gath",
+ "key": "Chogath",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Carnivore",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/GreenTerror_TailSpike.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Rupture",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Rupture.png"
+ },
+ {
+ "slot": "W",
+ "name": "Feral Scream",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FeralScream.png"
+ },
+ {
+ "slot": "E",
+ "name": "Vorpal Spikes",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VorpalSpikes.png"
+ },
+ {
+ "slot": "R",
+ "name": "Feast",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Feast.png"
+ }
+ ]
+ },
+ {
+ "championName": "Corki",
+ "key": "Corki",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Hextech Munitions",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Corki_RapidReload.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Phosphorus Bomb",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PhosphorusBomb.png"
+ },
+ {
+ "slot": "W",
+ "name": "Valkyrie",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CarpetBomb.png"
+ },
+ {
+ "slot": "E",
+ "name": "Gatling Gun",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GGun.png"
+ },
+ {
+ "slot": "R",
+ "name": "Missile Barrage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MissileBarrage.png"
+ }
+ ]
+ },
+ {
+ "championName": "Darius",
+ "key": "Darius",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Hemorrhage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Darius_Icon_Hemorrhage.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Decimate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DariusCleave.png"
+ },
+ {
+ "slot": "W",
+ "name": "Crippling Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DariusNoxianTacticsONH.png"
+ },
+ {
+ "slot": "E",
+ "name": "Apprehend",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DariusAxeGrabCone.png"
+ },
+ {
+ "slot": "R",
+ "name": "Noxian Guillotine",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DariusExecute.png"
+ }
+ ]
+ },
+ {
+ "championName": "Diana",
+ "key": "Diana",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Moonsilver Blade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Diana_Passive_LunarBlade.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Crescent Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DianaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Pale Cascade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DianaOrbs.png"
+ },
+ {
+ "slot": "E",
+ "name": "Lunar Rush",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DianaTeleport.png"
+ },
+ {
+ "slot": "R",
+ "name": "Moonfall",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DianaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Dr. Mundo",
+ "key": "DrMundo",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Goes Where He Pleases",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/DrMundo_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Infected Bonesaw",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DrMundoQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Heart Zapper",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DrMundoW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Blunt Force Trauma",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DrMundoE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Maximum Dosage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DrMundoR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Draven",
+ "key": "Draven",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "League of Draven",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Draven_passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Spinning Axe",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DravenSpinning.png"
+ },
+ {
+ "slot": "W",
+ "name": "Blood Rush",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DravenFury.png"
+ },
+ {
+ "slot": "E",
+ "name": "Stand Aside",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DravenDoubleShot.png"
+ },
+ {
+ "slot": "R",
+ "name": "Whirling Death",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DravenRCast.png"
+ }
+ ]
+ },
+ {
+ "championName": "Ekko",
+ "key": "Ekko",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Z-Drive Resonance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Ekko_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Timewinder",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EkkoQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Parallel Convergence",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EkkoW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Phase Dive",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EkkoE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Chronobreak",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EkkoR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Elise",
+ "key": "Elise",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Spider Queen",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/ElisePassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Neurotoxin / Venomous Bite",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EliseHumanQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Volatile Spiderling / Skittering Frenzy",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EliseHumanW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Cocoon / Rappel",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EliseHumanE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Spider Form",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EliseR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Evelynn",
+ "key": "Evelynn",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Demon Shade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Evelynn_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Hate Spike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EvelynnQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Allure",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EvelynnW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Whiplash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EvelynnE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Last Caress",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EvelynnR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Ezreal",
+ "key": "Ezreal",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Rising Spell Force",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Ezreal_RisingSpellForce.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Mystic Shot",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EzrealQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Essence Flux",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EzrealW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Arcane Shift",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EzrealE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Trueshot Barrage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EzrealR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Fiddlesticks",
+ "key": "Fiddlesticks",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "A Harmless Scarecrow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/FiddlesticksP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Terrify",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FiddleSticksQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Bountiful Harvest",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FiddleSticksW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Reap",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FiddleSticksE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Crowstorm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FiddleSticksR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Fiora",
+ "key": "Fiora",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Duelist's Dance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Fiora_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Lunge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FioraQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Riposte",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FioraW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Bladework",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FioraE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Grand Challenge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FioraR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Fizz",
+ "key": "Fizz",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Nimble Fighter",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Fizz_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Urchin Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FizzQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Seastone Trident",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FizzW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Playful / Trickster",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FizzE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Chum the Waters",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/FizzR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Galio",
+ "key": "Galio",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Colossal Smash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Galio_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Winds of War",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GalioQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Shield of Durand",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GalioW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Justice Punch",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GalioE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Hero's Entrance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GalioR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Gangplank",
+ "key": "Gangplank",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Trial by Fire",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Gangplank_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Parrrley",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GangplankQWrapper.png"
+ },
+ {
+ "slot": "W",
+ "name": "Remove Scurvy",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GangplankW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Powder Keg",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GangplankE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Cannon Barrage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GangplankR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Garen",
+ "key": "Garen",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Perseverance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Garen_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Decisive Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GarenQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Courage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GarenW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Judgment",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GarenE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Demacian Justice",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GarenR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Gnar",
+ "key": "Gnar",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Rage Gene",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Gnar_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Boomerang Throw / Boulder Toss",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GnarQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Hyper / Wallop",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GnarW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Hop / Crunch",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GnarE.png"
+ },
+ {
+ "slot": "R",
+ "name": "GNAR!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GnarR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Gragas",
+ "key": "Gragas",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Happy Hour",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/GragasPassiveHeal.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Barrel Roll",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GragasQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Drunken Rage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GragasW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Body Slam",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GragasE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Explosive Cask",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GragasR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Graves",
+ "key": "Graves",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "New Destiny",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/GravesTrueGrit.png"
+ },
+ {
+ "slot": "Q",
+ "name": "End of the Line",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GravesQLineSpell.png"
+ },
+ {
+ "slot": "W",
+ "name": "Smoke Screen",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GravesSmokeGrenade.png"
+ },
+ {
+ "slot": "E",
+ "name": "Quickdraw",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GravesMove.png"
+ },
+ {
+ "slot": "R",
+ "name": "Collateral Damage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GravesChargeShot.png"
+ }
+ ]
+ },
+ {
+ "championName": "Gwen",
+ "key": "Gwen",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "A Thousand Cuts",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Gwen_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Snip Snip!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GwenQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Hallowed Mist",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GwenW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Skip 'n Slash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GwenE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Needlework",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/GwenR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Hecarim",
+ "key": "Hecarim",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Warpath",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Hecarim_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Rampage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HecarimRapidSlash.png"
+ },
+ {
+ "slot": "W",
+ "name": "Spirit of Dread",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HecarimW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Devastating Charge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HecarimRamp.png"
+ },
+ {
+ "slot": "R",
+ "name": "Onslaught of Shadows",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HecarimUlt.png"
+ }
+ ]
+ },
+ {
+ "championName": "Heimerdinger",
+ "key": "Heimerdinger",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Hextech Affinity",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Heimerdinger_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "H-28 G Evolution Turret",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HeimerdingerQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Hextech Micro-Rockets",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HeimerdingerW.png"
+ },
+ {
+ "slot": "E",
+ "name": "CH-2 Electron Storm Grenade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HeimerdingerE.png"
+ },
+ {
+ "slot": "R",
+ "name": "UPGRADE!!!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HeimerdingerR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Hwei",
+ "key": "Hwei",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Signature of the Visionary",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/HweiPassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Subject: Disaster",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HweiQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Subject: Serenity",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HweiW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Subject: Torment",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HweiE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Spiraling Despair",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HweiR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Illaoi",
+ "key": "Illaoi",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Prophet of an Elder God",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Illaoi_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Tentacle Smash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IllaoiQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Harsh Lesson",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IllaoiW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Test of Spirit",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IllaoiE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Leap of Faith",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IllaoiR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Irelia",
+ "key": "Irelia",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Ionian Fervor",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Irelia_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Bladesurge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IreliaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Defiant Dance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IreliaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Flawless Duet",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IreliaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Vanguard's Edge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IreliaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Ivern",
+ "key": "Ivern",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Friend of the Forest",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/IvernP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Rootcaller",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IvernQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Brushmaker",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IvernW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Triggerseed",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IvernE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Daisy!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/IvernR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Janna",
+ "key": "Janna",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Tailwind",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/JannaP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Howling Gale",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HowlingGale.png"
+ },
+ {
+ "slot": "W",
+ "name": "Zephyr",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SowTheWind.png"
+ },
+ {
+ "slot": "E",
+ "name": "Eye Of The Storm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/EyeOfTheStorm.png"
+ },
+ {
+ "slot": "R",
+ "name": "Monsoon",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ReapTheWhirlwind.png"
+ }
+ ]
+ },
+ {
+ "championName": "Jarvan IV",
+ "key": "JarvanIV",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Martial Cadence",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/JarvanIVP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Dragon Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JarvanIVDragonStrike.png"
+ },
+ {
+ "slot": "W",
+ "name": "Golden Aegis",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JarvanIVGoldenAegis.png"
+ },
+ {
+ "slot": "E",
+ "name": "Demacian Standard",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JarvanIVDemacianStandard.png"
+ },
+ {
+ "slot": "R",
+ "name": "Cataclysm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JarvanIVCataclysm.png"
+ }
+ ]
+ },
+ {
+ "championName": "Jax",
+ "key": "Jax",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Relentless Assault",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Armsmaster_MasterOfArms.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Leap Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JaxQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Empower",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JaxW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Counter Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JaxE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Grandmaster-at-Arms",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JaxR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Jayce",
+ "key": "Jayce",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Hextech Capacitor",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Jayce_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "To the Skies! / Shock Blast",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JayceToTheSkies.png"
+ },
+ {
+ "slot": "W",
+ "name": "Lightning Field / Hyper Charge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JayceStaticField.png"
+ },
+ {
+ "slot": "E",
+ "name": "Thundering Blow / Acceleration Gate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JayceThunderingBlow.png"
+ },
+ {
+ "slot": "R",
+ "name": "Mercury Cannon / Mercury Hammer",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JayceStanceHtG.png"
+ }
+ ]
+ },
+ {
+ "championName": "Jhin",
+ "key": "Jhin",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Whisper",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Jhin_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Dancing Grenade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JhinQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Deadly Flourish",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JhinW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Captive Audience",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JhinE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Curtain Call",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JhinR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Jinx",
+ "key": "Jinx",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Get Excited!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Jinx_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Switcheroo!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JinxQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Zap!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JinxW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Flame Chompers!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JinxE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Super Mega Death Rocket!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JinxR.png"
+ }
+ ]
+ },
+ {
+ "championName": "K'Sante",
+ "key": "KSante",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Dauntless Instinct",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Icons_KSante_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Ntofo Strikes",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KSanteQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Path Maker",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KSanteW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Footwork",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KSanteE.png"
+ },
+ {
+ "slot": "R",
+ "name": "All Out",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KSanteR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Kai'Sa",
+ "key": "Kaisa",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Second Skin",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Kaisa_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Icathian Rain",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KaisaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Void Seeker",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KaisaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Supercharge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KaisaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Killer Instinct",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KaisaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Kalista",
+ "key": "Kalista",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Martial Poise",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Kalista_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Pierce",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KalistaMysticShot.png"
+ },
+ {
+ "slot": "W",
+ "name": "Sentinel",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KalistaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Rend",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KalistaExpungeWrapper.png"
+ },
+ {
+ "slot": "R",
+ "name": "Fate's Call",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KalistaRx.png"
+ }
+ ]
+ },
+ {
+ "championName": "Karma",
+ "key": "Karma",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Gathering Fire",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Karma_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Inner Flame",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KarmaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Focused Resolve",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KarmaSpiritBind.png"
+ },
+ {
+ "slot": "E",
+ "name": "Inspire",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KarmaSolKimShield.png"
+ },
+ {
+ "slot": "R",
+ "name": "Mantra",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KarmaMantra.png"
+ }
+ ]
+ },
+ {
+ "championName": "Karthus",
+ "key": "Karthus",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Death Defied",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Karthus_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Lay Waste",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KarthusLayWasteA1.png"
+ },
+ {
+ "slot": "W",
+ "name": "Wall of Pain",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KarthusWallOfPain.png"
+ },
+ {
+ "slot": "E",
+ "name": "Defile",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KarthusDefile.png"
+ },
+ {
+ "slot": "R",
+ "name": "Requiem",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KarthusFallenOne.png"
+ }
+ ]
+ },
+ {
+ "championName": "Kassadin",
+ "key": "Kassadin",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Void Stone",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Kassadin_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Null Sphere",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NullLance.png"
+ },
+ {
+ "slot": "W",
+ "name": "Nether Blade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NetherBlade.png"
+ },
+ {
+ "slot": "E",
+ "name": "Force Pulse",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ForcePulse.png"
+ },
+ {
+ "slot": "R",
+ "name": "Riftwalk",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RiftWalk.png"
+ }
+ ]
+ },
+ {
+ "championName": "Katarina",
+ "key": "Katarina",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Voracity",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Katarina_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Bouncing Blade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KatarinaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Preparation",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KatarinaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Shunpo",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KatarinaEWrapper.png"
+ },
+ {
+ "slot": "R",
+ "name": "Death Lotus",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KatarinaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Kayle",
+ "key": "Kayle",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Divine Ascent",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Kayle_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Radiant Blast",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KayleQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Celestial Blessing",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KayleW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Starfire Spellblade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KayleE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Divine Judgment",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KayleR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Kayn",
+ "key": "Kayn",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "The Darkin Scythe",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Kayn_Passive_Primary.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Reaping Slash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KaynQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Blade's Reach",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KaynW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Shadow Step",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KaynE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Umbral Trespass",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KaynR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Kennen",
+ "key": "Kennen",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Mark of the Storm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Kennen_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Thundering Shuriken",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KennenShurikenHurlMissile1.png"
+ },
+ {
+ "slot": "W",
+ "name": "Electrical Surge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KennenBringTheLight.png"
+ },
+ {
+ "slot": "E",
+ "name": "Lightning Rush",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KennenLightningRush.png"
+ },
+ {
+ "slot": "R",
+ "name": "Slicing Maelstrom",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KennenShurikenStorm.png"
+ }
+ ]
+ },
+ {
+ "championName": "Kha'Zix",
+ "key": "Khazix",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Unseen Threat",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Khazix_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Taste Their Fear",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KhazixQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Void Spike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KhazixW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Leap",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KhazixE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Void Assault",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KhazixR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Kindred",
+ "key": "Kindred",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Mark of the Kindred",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Kindred_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Dance of Arrows",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KindredQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Wolf's Frenzy",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KindredW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Mounting Dread",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KindredEWrapper.png"
+ },
+ {
+ "slot": "R",
+ "name": "Lamb's Respite",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KindredR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Kled",
+ "key": "Kled",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Skaarl, the Cowardly Lizard",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Kled_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Bear Trap on a Rope",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KledQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Violent Tendencies",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KledW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Jousting",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KledE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Chaaaaaaaarge!!!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KledR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Kog'Maw",
+ "key": "KogMaw",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Icathian Surprise",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/KogMaw_IcathianSurprise.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Caustic Spittle",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KogMawQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Bio-Arcane Barrage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KogMawBioArcaneBarrage.png"
+ },
+ {
+ "slot": "E",
+ "name": "Void Ooze",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KogMawVoidOoze.png"
+ },
+ {
+ "slot": "R",
+ "name": "Living Artillery",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/KogMawLivingArtillery.png"
+ }
+ ]
+ },
+ {
+ "championName": "LeBlanc",
+ "key": "Leblanc",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Mirror Image",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/LeblancP.Leblanc_Rework.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Sigil of Malice",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeblancQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Distortion",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeblancW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Ethereal Chains",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeblancE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Mimic",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeblancR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Lee Sin",
+ "key": "LeeSin",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Flurry",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/LeeSinPassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Sonic Wave / Resonating Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeeSinQOne.png"
+ },
+ {
+ "slot": "W",
+ "name": "Safeguard / Iron Will",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeeSinWOne.png"
+ },
+ {
+ "slot": "E",
+ "name": "Tempest / Cripple",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeeSinEOne.png"
+ },
+ {
+ "slot": "R",
+ "name": "Dragon's Rage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeeSinR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Leona",
+ "key": "Leona",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Sunlight",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/LeonaSunlight.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Shield of Daybreak",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeonaShieldOfDaybreak.png"
+ },
+ {
+ "slot": "W",
+ "name": "Eclipse",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeonaSolarBarrier.png"
+ },
+ {
+ "slot": "E",
+ "name": "Zenith Blade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeonaZenithBlade.png"
+ },
+ {
+ "slot": "R",
+ "name": "Solar Flare",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LeonaSolarFlare.png"
+ }
+ ]
+ },
+ {
+ "championName": "Lillia",
+ "key": "Lillia",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Dream-Laden Bough",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Lillia_Icon_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Blooming Blows",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LilliaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Watch Out! Eep!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LilliaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Swirlseed",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LilliaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Lilting Lullaby",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LilliaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Lissandra",
+ "key": "Lissandra",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Iceborn Subjugation",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Lissandra_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Ice Shard",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LissandraQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Ring of Frost",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LissandraW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Glacial Path",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LissandraE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Frozen Tomb",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LissandraR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Lucian",
+ "key": "Lucian",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Lightslinger",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Lucian_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Piercing Light",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LucianQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Ardent Blaze",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LucianW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Relentless Pursuit",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LucianE.png"
+ },
+ {
+ "slot": "R",
+ "name": "The Culling",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LucianR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Lulu",
+ "key": "Lulu",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Pix, Faerie Companion",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Lulu_PixFaerieCompanion.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Glitterlance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LuluQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Whimsy",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LuluW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Help, Pix!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LuluE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Wild Growth",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LuluR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Lux",
+ "key": "Lux",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Illumination",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/LuxIlluminatingFraulein.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Light Binding",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LuxLightBinding.png"
+ },
+ {
+ "slot": "W",
+ "name": "Prismatic Barrier",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LuxPrismaticWave.png"
+ },
+ {
+ "slot": "E",
+ "name": "Lucent Singularity",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LuxLightStrikeKugel.png"
+ },
+ {
+ "slot": "R",
+ "name": "Final Spark",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/LuxR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Malphite",
+ "key": "Malphite",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Granite Shield",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Malphite_GraniteShield.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Seismic Shard",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SeismicShard.png"
+ },
+ {
+ "slot": "W",
+ "name": "Thunderclap",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Obduracy.png"
+ },
+ {
+ "slot": "E",
+ "name": "Ground Slam",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Landslide.png"
+ },
+ {
+ "slot": "R",
+ "name": "Unstoppable Force",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/UFSlash.png"
+ }
+ ]
+ },
+ {
+ "championName": "Malzahar",
+ "key": "Malzahar",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Void Shift",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Malzahar_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Call of the Void",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MalzaharQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Void Swarm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MalzaharW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Malefic Visions",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MalzaharE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Nether Grasp",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MalzaharR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Maokai",
+ "key": "Maokai",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Sap Magic",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Maokai_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Bramble Smash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MaokaiQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Twisted Advance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MaokaiW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Sapling Toss",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MaokaiE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Nature's Grasp",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MaokaiR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Master Yi",
+ "key": "MasterYi",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Double Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/MasterYi_Passive1.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Alpha Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AlphaStrike.png"
+ },
+ {
+ "slot": "W",
+ "name": "Meditate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Meditate.png"
+ },
+ {
+ "slot": "E",
+ "name": "Wuju Style",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/WujuStyle.png"
+ },
+ {
+ "slot": "R",
+ "name": "Highlander",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Highlander.png"
+ }
+ ]
+ },
+ {
+ "championName": "Mel",
+ "key": "Mel",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Searing Brilliance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Mel_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Radiant Volley",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MelQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Rebuttal",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MelW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Solar Snare",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MelE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Golden Eclipse",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MelR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Milio",
+ "key": "Milio",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Fired Up!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Milio_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Ultra Mega Fire Kick",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MilioQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Cozy Campfire",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MilioW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Warm Hugs",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MilioE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Breath of Life",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MilioR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Miss Fortune",
+ "key": "MissFortune",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Love Tap",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/MissFortune_W.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Double Up",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MissFortuneRicochetShot.png"
+ },
+ {
+ "slot": "W",
+ "name": "Strut",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MissFortuneViciousStrikes.png"
+ },
+ {
+ "slot": "E",
+ "name": "Make It Rain",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MissFortuneScattershot.png"
+ },
+ {
+ "slot": "R",
+ "name": "Bullet Time",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MissFortuneBulletTime.png"
+ }
+ ]
+ },
+ {
+ "championName": "Mordekaiser",
+ "key": "Mordekaiser",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Darkness Rise",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/MordekaiserPassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Obliterate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MordekaiserQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Indestructible",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MordekaiserW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Death's Grasp",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MordekaiserE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Realm of Death",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MordekaiserR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Morgana",
+ "key": "Morgana",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Soul Siphon",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/FallenAngel_Empathize.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Dark Binding",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MorganaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Tormented Shadow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MorganaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Black Shield",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MorganaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Soul Shackles",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MorganaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Naafiri",
+ "key": "Naafiri",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "We Are More",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Icons_Naafiri_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Darkin Daggers",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NaafiriQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "The Call of the Pack",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NaafiriR.png"
+ },
+ {
+ "slot": "E",
+ "name": "Eviscerate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NaafiriE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Hounds' Pursuit",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NaafiriW.png"
+ }
+ ]
+ },
+ {
+ "championName": "Nami",
+ "key": "Nami",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Surging Tides",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/NamiPassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Aqua Prison",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NamiQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Ebb and Flow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NamiW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Tidecaller's Blessing",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NamiE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Tidal Wave",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NamiR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Nasus",
+ "key": "Nasus",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Soul Eater",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Nasus_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Siphoning Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NasusQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Wither",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NasusW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Spirit Fire",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NasusE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Fury of the Sands",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NasusR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Nautilus",
+ "key": "Nautilus",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Staggering Blow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Nautilus_StaggeringBlow.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Dredge Line",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NautilusAnchorDrag.png"
+ },
+ {
+ "slot": "W",
+ "name": "Titan's Wrath",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NautilusPiercingGaze.png"
+ },
+ {
+ "slot": "E",
+ "name": "Riptide",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NautilusSplashZone.png"
+ },
+ {
+ "slot": "R",
+ "name": "Depth Charge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NautilusGrandLine.png"
+ }
+ ]
+ },
+ {
+ "championName": "Neeko",
+ "key": "Neeko",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Inherent Glamour",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Neeko_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Blooming Burst",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NeekoQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Shapesplitter",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NeekoW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Tangle-Barbs",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NeekoE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Pop Blossom",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NeekoR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Nidalee",
+ "key": "Nidalee",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Prowl",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Nidalee_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Javelin Toss / Takedown",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JavelinToss.png"
+ },
+ {
+ "slot": "W",
+ "name": "Bushwhack / Pounce",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Bushwhack.png"
+ },
+ {
+ "slot": "E",
+ "name": "Primal Surge / Swipe",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PrimalSurge.png"
+ },
+ {
+ "slot": "R",
+ "name": "Aspect Of The Cougar",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/AspectOfTheCougar.png"
+ }
+ ]
+ },
+ {
+ "championName": "Nilah",
+ "key": "Nilah",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Joy Unending",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/NIlahP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Formless Blade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NilahQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Jubilant Veil",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NilahW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Slipstream",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NilahE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Apotheosis",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NilahR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Nocturne",
+ "key": "Nocturne",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Umbra Blades",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Nocturne_UmbraBlades.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Duskbringer",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NocturneDuskbringer.png"
+ },
+ {
+ "slot": "W",
+ "name": "Shroud of Darkness",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NocturneShroudofDarkness.png"
+ },
+ {
+ "slot": "E",
+ "name": "Unspeakable Horror",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NocturneUnspeakableHorror.png"
+ },
+ {
+ "slot": "R",
+ "name": "Paranoia",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NocturneParanoia.png"
+ }
+ ]
+ },
+ {
+ "championName": "Nunu & Willump",
+ "key": "Nunu",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Call of the Freljord",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/NunuPassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Consume",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NunuQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Biggest Snowball Ever!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NunuW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Snowball Barrage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NunuE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Absolute Zero",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/NunuR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Olaf",
+ "key": "Olaf",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Berserker Rage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Olaf_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Undertow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OlafAxeThrowCast.png"
+ },
+ {
+ "slot": "W",
+ "name": "Tough It Out",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OlafFrenziedStrikes.png"
+ },
+ {
+ "slot": "E",
+ "name": "Reckless Swing",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OlafRecklessStrike.png"
+ },
+ {
+ "slot": "R",
+ "name": "Ragnarok",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OlafRagnarok.png"
+ }
+ ]
+ },
+ {
+ "championName": "Orianna",
+ "key": "Orianna",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Clockwork Windup",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/OriannaPassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Command: Attack",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OrianaIzunaCommand.png"
+ },
+ {
+ "slot": "W",
+ "name": "Command: Dissonance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OrianaDissonanceCommand.png"
+ },
+ {
+ "slot": "E",
+ "name": "Command: Protect",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OrianaRedactCommand.png"
+ },
+ {
+ "slot": "R",
+ "name": "Command: Shockwave",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OrianaDetonateCommand.png"
+ }
+ ]
+ },
+ {
+ "championName": "Ornn",
+ "key": "Ornn",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Living Forge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/OrnnP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Volcanic Rupture",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OrnnQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Bellows Breath",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OrnnW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Searing Charge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OrnnE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Call of the Forge God",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/OrnnR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Pantheon",
+ "key": "Pantheon",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Mortal Will",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Pantheon_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Comet Spear",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PantheonQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Shield Vault",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PantheonW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Aegis Assault",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PantheonE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Grand Starfall",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PantheonR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Poppy",
+ "key": "Poppy",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Iron Ambassador",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Poppy_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Hammer Shock",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PoppyQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Steadfast Presence",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PoppyW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Heroic Charge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PoppyE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Keeper's Verdict",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PoppyR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Pyke",
+ "key": "Pyke",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Gift of the Drowned Ones",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/PykePassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Bone Skewer",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PykeQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Ghostwater Dive",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PykeW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Phantom Undertow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PykeE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Death From Below",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PykeR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Qiyana",
+ "key": "Qiyana",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Royal Privilege",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Qiyana_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Elemental Wrath / Edge of Ixtal",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/QiyanaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Terrashape",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/QiyanaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Audacity",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/QiyanaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Supreme Display of Talent",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/QiyanaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Quinn",
+ "key": "Quinn",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Harrier",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Quinn_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Blinding Assault",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/QuinnQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Heightened Senses",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/QuinnW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Vault",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/QuinnE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Behind Enemy Lines",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/QuinnR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Rakan",
+ "key": "Rakan",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Fey Feathers",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Rakan_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Gleaming Quill",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RakanQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Grand Entrance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RakanW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Battle Dance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RakanE.png"
+ },
+ {
+ "slot": "R",
+ "name": "The Quickness",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RakanR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Rammus",
+ "key": "Rammus",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Spiked Shell",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Armordillo_ScavengeArmor.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Powerball",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PowerBall.png"
+ },
+ {
+ "slot": "W",
+ "name": "Defensive Ball Curl",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/DefensiveBallCurl.png"
+ },
+ {
+ "slot": "E",
+ "name": "Frenzying Taunt",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PuncturingTaunt.png"
+ },
+ {
+ "slot": "R",
+ "name": "Soaring Slam",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Tremors2.png"
+ }
+ ]
+ },
+ {
+ "championName": "Rek'Sai",
+ "key": "RekSai",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Fury of the Xer'Sai",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/RekSai_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Queen's Wrath / Prey Seeker",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RekSaiQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Burrow / Un-burrow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RekSaiW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Furious Bite / Tunnel",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RekSaiE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Void Rush",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RekSaiR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Rell",
+ "key": "Rell",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Break the Mold",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/RellP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Shattering Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RellQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Ferromancy: Crash Down",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RellW_Dismount.png"
+ },
+ {
+ "slot": "E",
+ "name": "Full Tilt",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RellE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Magnet Storm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RellR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Renata Glasc",
+ "key": "Renata",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Leverage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Renata_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Handshake",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RenataQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Bailout",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RenataW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Loyalty Program",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RenataE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Hostile Takeover",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RenataR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Renekton",
+ "key": "Renekton",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Reign of Anger",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Renekton_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Cull the Meek",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RenektonCleave.png"
+ },
+ {
+ "slot": "W",
+ "name": "Ruthless Predator",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RenektonPreExecute.png"
+ },
+ {
+ "slot": "E",
+ "name": "Slice and Dice",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RenektonSliceAndDice.png"
+ },
+ {
+ "slot": "R",
+ "name": "Dominus",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RenektonReignOfTheTyrant.png"
+ }
+ ]
+ },
+ {
+ "championName": "Rengar",
+ "key": "Rengar",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Unseen Predator",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Rengar_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Savagery",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RengarQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Battle Roar",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RengarW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Bola Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RengarE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Thrill of the Hunt",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RengarR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Riven",
+ "key": "Riven",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Runic Blade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/RivenRunicBlades.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Broken Wings",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RivenTriCleave.png"
+ },
+ {
+ "slot": "W",
+ "name": "Ki Burst",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RivenMartyr.png"
+ },
+ {
+ "slot": "E",
+ "name": "Valor",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RivenFeint.png"
+ },
+ {
+ "slot": "R",
+ "name": "Blade of the Exile",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RivenFengShuiEngine.png"
+ }
+ ]
+ },
+ {
+ "championName": "Rumble",
+ "key": "Rumble",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Junkyard Titan",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Rumble_JunkyardTitan1.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Flamespitter",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RumbleFlameThrower.png"
+ },
+ {
+ "slot": "W",
+ "name": "Scrap Shield",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RumbleShield.png"
+ },
+ {
+ "slot": "E",
+ "name": "Electro Harpoon",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RumbleGrenade.png"
+ },
+ {
+ "slot": "R",
+ "name": "The Equalizer",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RumbleCarpetBomb.png"
+ }
+ ]
+ },
+ {
+ "championName": "Ryze",
+ "key": "Ryze",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Arcane Mastery",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Ryze_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Overload",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RyzeQWrapper.png"
+ },
+ {
+ "slot": "W",
+ "name": "Rune Prison",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RyzeW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Spell Flux",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RyzeE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Realm Warp",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/RyzeR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Samira",
+ "key": "Samira",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Daredevil Impulse",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/SamiraP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Flair",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SamiraQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Blade Whirl",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SamiraW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Wild Rush",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SamiraE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Inferno Trigger",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SamiraR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Sejuani",
+ "key": "Sejuani",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Fury of the North",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Sejuani_passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Arctic Assault",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SejuaniQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Winter's Wrath",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SejuaniW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Permafrost",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SejuaniE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Glacial Prison",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SejuaniR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Senna",
+ "key": "Senna",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Absolution",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Senna_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Piercing Darkness",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SennaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Last Embrace",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SennaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Curse of the Black Mist",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SennaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Dawning Shadow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SennaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Seraphine",
+ "key": "Seraphine",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Stage Presence",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Seraphine_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "High Note",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SeraphineQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Surround Sound",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SeraphineW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Beat Drop",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SeraphineE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Encore",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SeraphineR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Sett",
+ "key": "Sett",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Pit Grit",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Sett_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Knuckle Down",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SettQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Haymaker",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SettW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Facebreaker",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SettE.png"
+ },
+ {
+ "slot": "R",
+ "name": "The Show Stopper",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SettR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Shaco",
+ "key": "Shaco",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Backstab",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Jester_CarefulStrikes.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Deceive",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Deceive.png"
+ },
+ {
+ "slot": "W",
+ "name": "Jack In The Box",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/JackInTheBox.png"
+ },
+ {
+ "slot": "E",
+ "name": "Two-Shiv Poison",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TwoShivPoison.png"
+ },
+ {
+ "slot": "R",
+ "name": "Hallucinate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/HallucinateFull.png"
+ }
+ ]
+ },
+ {
+ "championName": "Shen",
+ "key": "Shen",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Ki Barrier",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Shen_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Twilight Assault",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ShenQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Spirit's Refuge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ShenW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Shadow Dash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ShenE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Stand United",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ShenR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Shyvana",
+ "key": "Shyvana",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Scalemail",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Shyvana_Passive.Shyvana_Rework.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Emberstrike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ShyvanaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Inferno Aegis",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ShyvanaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Molten Burst",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ShyvanaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Dragon's Descent",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ShyvanaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Singed",
+ "key": "Singed",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Noxious Slipstream",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Singed_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Poison Trail",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PoisonTrail.png"
+ },
+ {
+ "slot": "W",
+ "name": "Mega Adhesive",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MegaAdhesive.png"
+ },
+ {
+ "slot": "E",
+ "name": "Fling",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Fling.png"
+ },
+ {
+ "slot": "R",
+ "name": "Insanity Potion",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/InsanityPotion.png"
+ }
+ ]
+ },
+ {
+ "championName": "Sion",
+ "key": "Sion",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Glory in Death",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Sion_Passive1.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Decimating Smash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SionQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Soul Furnace",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SionW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Roar of the Slayer",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SionE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Unstoppable Onslaught",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SionR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Sivir",
+ "key": "Sivir",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Fleet of Foot",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Sivir_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Boomerang Blade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SivirQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Ricochet",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SivirW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Spell Shield",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SivirE.png"
+ },
+ {
+ "slot": "R",
+ "name": "On The Hunt",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SivirR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Skarner",
+ "key": "Skarner",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Threads of Vibration",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Skarner_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Shattered Earth / Upheaval",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SkarnerQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Seismic Bastion",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SkarnerW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Ixtal's Impact",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SkarnerE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Impale",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SkarnerR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Smolder",
+ "key": "Smolder",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Dragon Practice",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Icons_Smolder_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Super Scorcher Breath",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SmolderQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Achooo!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SmolderW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Flap, Flap, Flap",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SmolderE.png"
+ },
+ {
+ "slot": "R",
+ "name": "MMOOOMMMM!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SmolderR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Sona",
+ "key": "Sona",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Power Chord",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Sona_Passive_Charged.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Hymn of Valor",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SonaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Aria of Perseverance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SonaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Song of Celerity",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SonaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Crescendo",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SonaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Soraka",
+ "key": "Soraka",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Salvation",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Soraka_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Starcall",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SorakaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Astral Infusion",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SorakaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Equinox",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SorakaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Wish",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SorakaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Swain",
+ "key": "Swain",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Ravenous Flock",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Swain_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Death's Hand",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SwainQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Vision of Empire",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SwainW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Nevermove",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SwainE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Demonic Ascension",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SwainR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Sylas",
+ "key": "Sylas",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Petricite Burst",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/SylasP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Chain Lash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SylasQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Kingslayer",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SylasW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Abscond / Abduct",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SylasE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Hijack",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SylasR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Syndra",
+ "key": "Syndra",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Transcendent",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/SyndraPassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Dark Sphere",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SyndraQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Force of Will",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SyndraW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Scatter the Weak",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SyndraE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Unleashed Power",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/SyndraR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Tahm Kench",
+ "key": "TahmKench",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "An Acquired Taste",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/TahmKenchP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Tongue Lash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TahmKenchQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Abyssal Dive",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TahmKenchW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Thick Skin",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TahmKenchE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Devour",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TahmKenchRWrapper.png"
+ }
+ ]
+ },
+ {
+ "championName": "Taliyah",
+ "key": "Taliyah",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Rock Surfing",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Taliyah_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Threaded Volley",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TaliyahQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Seismic Shove",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TaliyahWVC.png"
+ },
+ {
+ "slot": "E",
+ "name": "Unraveled Earth",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TaliyahE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Weaver's Wall",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TaliyahR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Talon",
+ "key": "Talon",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Blade's End",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/TalonP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Noxian Diplomacy",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TalonQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Rake",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TalonW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Assassin's Path",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TalonE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Shadow Assault",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TalonR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Taric",
+ "key": "Taric",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Bravado",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Taric_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Starlight's Touch",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TaricQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Bastion",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TaricW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Dazzle",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TaricE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Cosmic Radiance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TaricR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Teemo",
+ "key": "Teemo",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Guerrilla Warfare",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/TeemoPassive.ASU_Teemo.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Blinding Dart",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TeemoQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Move Quick",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TeemoW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Toxic Shot",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TeemoE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Noxious Trap",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TeemoR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Thresh",
+ "key": "Thresh",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Damnation",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Thresh_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Death Sentence",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ThreshQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Dark Passage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ThreshW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Flay",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ThreshE.png"
+ },
+ {
+ "slot": "R",
+ "name": "The Box",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ThreshRPenta.png"
+ }
+ ]
+ },
+ {
+ "championName": "Tristana",
+ "key": "Tristana",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Draw a Bead",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Tristana_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Rapid Fire",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TristanaQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Rocket Jump",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TristanaW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Explosive Charge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TristanaE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Buster Shot",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TristanaR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Trundle",
+ "key": "Trundle",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "King's Tribute",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Trundle_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Chomp",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TrundleTrollSmash.png"
+ },
+ {
+ "slot": "W",
+ "name": "Frozen Domain",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/trundledesecrate.png"
+ },
+ {
+ "slot": "E",
+ "name": "Pillar of Ice",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TrundleCircle.png"
+ },
+ {
+ "slot": "R",
+ "name": "Subjugate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TrundlePain.png"
+ }
+ ]
+ },
+ {
+ "championName": "Tryndamere",
+ "key": "Tryndamere",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Battle Fury",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Tryndamere_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Bloodlust",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TryndamereQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Mocking Shout",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TryndamereW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Spinning Slash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TryndamereE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Undying Rage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/UndyingRage.png"
+ }
+ ]
+ },
+ {
+ "championName": "Twisted Fate",
+ "key": "TwistedFate",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Loaded Dice",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Cardmaster_SealFate.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Wild Cards",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/WildCards.png"
+ },
+ {
+ "slot": "W",
+ "name": "Pick a Card",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/PickACard.png"
+ },
+ {
+ "slot": "E",
+ "name": "Stacked Deck",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/CardmasterStack.png"
+ },
+ {
+ "slot": "R",
+ "name": "Destiny",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/Destiny.png"
+ }
+ ]
+ },
+ {
+ "championName": "Twitch",
+ "key": "Twitch",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Deadly Venom",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Twitch_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Ambush",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TwitchHideInShadows.png"
+ },
+ {
+ "slot": "W",
+ "name": "Venom Cask",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TwitchVenomCask.png"
+ },
+ {
+ "slot": "E",
+ "name": "Contaminate",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TwitchExpunge.png"
+ },
+ {
+ "slot": "R",
+ "name": "Spray and Pray",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TwitchFullAutomatic.png"
+ }
+ ]
+ },
+ {
+ "championName": "Udyr",
+ "key": "Udyr",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Bridge Between",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Udyr_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Wilding Claw",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/UdyrQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Iron Mantle",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/UdyrW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Blazing Stampede",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/UdyrE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Wingborne Storm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/UdyrR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Urgot",
+ "key": "Urgot",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Echoing Flames",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Urgot_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Corrosive Charge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/UrgotQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Purge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/UrgotW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Disdain",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/UrgotE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Fear Beyond Death",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/UrgotR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Varus",
+ "key": "Varus",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Living Vengeance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/VarusPassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Piercing Arrow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VarusQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Blighted Quiver",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VarusW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Hail of Arrows",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VarusE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Chain of Corruption",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VarusR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Vayne",
+ "key": "Vayne",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Night Hunter",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Vayne_NightHunter.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Tumble",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VayneTumble.png"
+ },
+ {
+ "slot": "W",
+ "name": "Silver Bolts",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VayneSilveredBolts.png"
+ },
+ {
+ "slot": "E",
+ "name": "Condemn",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VayneCondemn.png"
+ },
+ {
+ "slot": "R",
+ "name": "Final Hour",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VayneInquisition.png"
+ }
+ ]
+ },
+ {
+ "championName": "Veigar",
+ "key": "Veigar",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Phenomenal Evil Power",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/VeigarEntropy.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Baleful Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VeigarBalefulStrike.png"
+ },
+ {
+ "slot": "W",
+ "name": "Dark Matter",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VeigarDarkMatter.png"
+ },
+ {
+ "slot": "E",
+ "name": "Event Horizon",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VeigarEventHorizon.png"
+ },
+ {
+ "slot": "R",
+ "name": "Primordial Burst",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VeigarR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Vel'Koz",
+ "key": "Velkoz",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Organic Deconstruction",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/VelKoz_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Plasma Fission",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VelkozQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Void Rift",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VelkozW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Tectonic Disruption",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VelkozE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Life Form Disintegration Ray",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VelkozR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Vex",
+ "key": "Vex",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Doom 'n Gloom",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Icons_Vex_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Mistral Bolt",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VexQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Personal Space",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VexW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Looming Darkness",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VexE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Shadow Surge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VexR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Vi",
+ "key": "Vi",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Blast Shield",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/ViPassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Vault Breaker",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Denting Blows",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Relentless Force",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Cease and Desist",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Viego",
+ "key": "Viego",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Sovereign's Domination",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Viego_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Blade of the Ruined King",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViegoQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Spectral Maw",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViegoW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Harrowed Path",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViegoE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Heartbreaker",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViegoR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Viktor",
+ "key": "Viktor",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Glorious Evolution",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Viktor_Passive.ViktorVGU.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Siphon Power",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViktorQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Gravity Field",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViktorW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Hextech Ray",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViktorE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Arcane Storm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ViktorR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Vladimir",
+ "key": "Vladimir",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Crimson Pact",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/VladimirP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Transfusion",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VladimirQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Sanguine Pool",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VladimirSanguinePool.png"
+ },
+ {
+ "slot": "E",
+ "name": "Tides of Blood",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VladimirE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Hemoplague",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VladimirHemoplague.png"
+ }
+ ]
+ },
+ {
+ "championName": "Volibear",
+ "key": "Volibear",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "The Relentless Storm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Volibear_Icon_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Thundering Smash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VolibearQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Frenzied Maul",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VolibearW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Sky Splitter",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VolibearE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Stormbringer",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/VolibearR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Warwick",
+ "key": "Warwick",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Eternal Hunger",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/WarwickP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Jaws of the Beast",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/WarwickQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Blood Hunt",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/WarwickW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Primal Howl",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/WarwickE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Infinite Duress",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/WarwickR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Wukong",
+ "key": "MonkeyKing",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Stone Skin",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/MonkeyKingStoneSkin.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Crushing Blow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MonkeyKingDoubleAttack.png"
+ },
+ {
+ "slot": "W",
+ "name": "Warrior Trickster",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MonkeyKingDecoy.png"
+ },
+ {
+ "slot": "E",
+ "name": "Nimbus Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MonkeyKingNimbus.png"
+ },
+ {
+ "slot": "R",
+ "name": "Cyclone",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/MonkeyKingSpinToWin.png"
+ }
+ ]
+ },
+ {
+ "championName": "Xayah",
+ "key": "Xayah",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Clean Cuts",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/XayahPassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Double Daggers",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XayahQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Deadly Plumage",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XayahW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Bladecaller",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XayahE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Featherstorm",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XayahR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Xerath",
+ "key": "Xerath",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Mana Surge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Xerath_Passive1.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Arcanopulse",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XerathArcanopulseChargeUp.png"
+ },
+ {
+ "slot": "W",
+ "name": "Eye of Destruction",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XerathArcaneBarrage2.png"
+ },
+ {
+ "slot": "E",
+ "name": "Shocking Orb",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XerathMageSpear.png"
+ },
+ {
+ "slot": "R",
+ "name": "Rite of the Arcane",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XerathLocusOfPower2.png"
+ }
+ ]
+ },
+ {
+ "championName": "Xin Zhao",
+ "key": "XinZhao",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Determination",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/XinZhaoReworkP.XinZhaoRework.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Three Talon Strike",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XinZhaoQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Wind Becomes Lightning",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XinZhaoW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Audacious Charge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XinZhaoE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Crescent Guard",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/XinZhaoR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Yasuo",
+ "key": "Yasuo",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Way of the Wanderer",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Yasuo_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Steel Tempest",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YasuoQ1Wrapper.png"
+ },
+ {
+ "slot": "W",
+ "name": "Wind Wall",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YasuoW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Sweeping Blade",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YasuoE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Last Breath",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YasuoR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Yone",
+ "key": "Yone",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Way of the Hunter",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/YonePassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Mortal Steel",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YoneQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Spirit Cleave",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YoneW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Soul Unbound",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YoneE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Fate Sealed",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YoneR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Yorick",
+ "key": "Yorick",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Shepherd of Souls",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Yorick_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Last Rites",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YorickQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Dark Procession",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YorickW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Mourning Mist",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YorickE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Eulogy of the Isles",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YorickR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Yunara",
+ "key": "Yunara",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Vow of the First Lands",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Yunara_Passive.Yunara.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Cultivation of Spirit",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YunaraQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Arc of Judgment | Arc of Ruin",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YunaraW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Kanmei's Steps | Untouchable Shadow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YunaraE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Transcend One's Self",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YunaraR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Yuumi",
+ "key": "Yuumi",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Feline Friendship",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/YuumiP2.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Prowling Projectile",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YuumiQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "You and Me!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YuumiW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Zoomies",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YuumiE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Final Chapter",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/YuumiR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Zaahen",
+ "key": "Zaahen",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Cultivation of War",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/ZaahenP.Zaahen.png"
+ },
+ {
+ "slot": "Q",
+ "name": "The Darkin Glaive",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZaahenQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Dreaded Return",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZaahenW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Aureate Rush",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZaahenE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Grim Deliverance",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZaahenR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Zac",
+ "key": "Zac",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Cell Division",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/ZacPassive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Stretching Strikes",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZacQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Unstable Matter",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZacW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Elastic Slingshot",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZacE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Let's Bounce!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZacR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Zed",
+ "key": "Zed",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Contempt for the Weak",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/ZedP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Razor Shuriken",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZedQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Living Shadow",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZedW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Shadow Slash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZedE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Death Mark",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZedR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Zeri",
+ "key": "Zeri",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Living Battery",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/ZeriP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Burst Fire",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZeriQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Ultrashock Laser",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZeriW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Spark Surge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZeriE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Lightning Crash",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZeriR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Ziggs",
+ "key": "Ziggs",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Short Fuse",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/ZiggsPassiveReady.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Bouncing Bomb",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZiggsQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Satchel Charge",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZiggsW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Hexplosive Minefield",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZiggsE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Mega Inferno Bomb",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZiggsR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Zilean",
+ "key": "Zilean",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Time In A Bottle",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Zilean_Passive.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Time Bomb",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZileanQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Rewind",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZileanW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Time Warp",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/TimeWarp.png"
+ },
+ {
+ "slot": "R",
+ "name": "Chronoshift",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ChronoShift.png"
+ }
+ ]
+ },
+ {
+ "championName": "Zoe",
+ "key": "Zoe",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "More Sparkles!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/Zoe_P.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Paddle Star!",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZoeQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Spell Thief",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZoeW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Sleepy Trouble Bubble",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZoeE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Portal Jump",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZoeR.png"
+ }
+ ]
+ },
+ {
+ "championName": "Zyra",
+ "key": "Zyra",
+ "abilities": [
+ {
+ "slot": "P",
+ "name": "Garden of Thorns",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/passive/ZyraP.png"
+ },
+ {
+ "slot": "Q",
+ "name": "Deadly Spines",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZyraQ.png"
+ },
+ {
+ "slot": "W",
+ "name": "Rampant Growth",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZyraW.png"
+ },
+ {
+ "slot": "E",
+ "name": "Grasping Roots",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZyraE.png"
+ },
+ {
+ "slot": "R",
+ "name": "Stranglethorns",
+ "icon": "https://ddragon.leagueoflegends.com/cdn/16.8.1/img/spell/ZyraR.png"
+ }
+ ]
+ }
+]
diff --git a/internal/modules/loldleability/handlers.go b/internal/modules/loldleability/handlers.go
new file mode 100644
index 0000000..ac2c5d5
--- /dev/null
+++ b/internal/modules/loldleability/handlers.go
@@ -0,0 +1,256 @@
+package loldleability
+
+import (
+ "context"
+ "fmt"
+ "html"
+ "math/rand"
+ "strconv"
+
+ "github.com/go-telegram/bot"
+ "github.com/go-telegram/bot/models"
+
+ "github.com/tiennm99/miti99bot-go/internal/champname"
+ "github.com/tiennm99/miti99bot-go/internal/keylock"
+ "github.com/tiennm99/miti99bot-go/internal/modules/util/chathelper"
+ "github.com/tiennm99/miti99bot-go/internal/storage"
+)
+
+const newRoundHint = "🆕 Send /loldle_ability or /loldle_ability <champion> to start a new round."
+
+// state captures everything a loldle-ability handler needs at runtime.
+// Built once per Factory call and shared across the four command closures.
+type state struct {
+ kv storage.KVStore
+ pool []AbilityChampion
+ locks keylock.Map // serialises Get→mutate→Put per subject
+}
+
+// championName extracts the comparable name field for champname helpers.
+func championName(c *AbilityChampion) string { return c.ChampionName }
+
+func (s *state) pickRandomChampion() *AbilityChampion {
+ return &s.pool[rand.Intn(len(s.pool))]
+}
+
+func pickRandomAbility(c *AbilityChampion) *Ability {
+ return &c.Abilities[rand.Intn(len(c.Abilities))]
+}
+
+func (s *state) startFreshGame(ctx context.Context, subject string) (*gameState, error) {
+ target := s.pickRandomChampion()
+ ability := pickRandomAbility(target)
+ g := &gameState{
+ Target: target.ChampionName,
+ Slot: ability.Slot,
+ Guesses: []string{},
+ StartedAt: nil,
+ }
+ if err := saveGame(ctx, s.kv, subject, g); err != nil {
+ return nil, err
+ }
+ return g, nil
+}
+
+func (s *state) getOrInitGame(ctx context.Context, subject string, maxGuesses int) (*gameState, error) {
+ existing, err := loadGame(ctx, s.kv, subject)
+ if err != nil {
+ return nil, err
+ }
+ if existing != nil && len(existing.Guesses) < maxGuesses {
+ return existing, nil
+ }
+ return s.startFreshGame(ctx, subject)
+}
+
+// caption is the photo caption shown above each round-in-progress icon.
+func caption(guesses, maxGuesses int) string {
+ return fmt.Sprintf("🔮 Guess the champion from this ability. %d/%d guesses so far.", guesses, maxGuesses)
+}
+
+// sendAbilityIcon dispatches a sendPhoto with the ability icon URL. Returns
+// the bot library's error verbatim — caller decides whether to log/ignore.
+func sendAbilityIcon(ctx context.Context, b *bot.Bot, chatID int64, ability *Ability, captionText string) error {
+ _, err := b.SendPhoto(ctx, &bot.SendPhotoParams{
+ ChatID: chatID,
+ Photo: &models.InputFileString{Data: ability.Icon},
+ Caption: captionText,
+ })
+ return err
+}
+
+// handleAbility is /loldle_ability [champion] — show icon if no arg, else guess.
+func (s *state) handleAbility(ctx context.Context, b *bot.Bot, update *models.Update) error {
+ msg := update.Message
+ if msg == nil {
+ return nil
+ }
+ subject := chathelper.SubjectFor(msg)
+ if subject == "" {
+ return chathelper.Reply(ctx, b, msg.Chat.ID, "Cannot identify chat.")
+ }
+ defer s.locks.Acquire(subject)()
+ arg := chathelper.ArgAfterCommand(msg.Text)
+
+ maxGuesses, err := getMaxGuesses(ctx, s.kv, subject)
+ if err != nil {
+ return err
+ }
+ game, err := s.getOrInitGame(ctx, subject, maxGuesses)
+ if err != nil {
+ return err
+ }
+ target := champname.FindByExactName(s.pool, game.Target, championName)
+ var ability *Ability
+ if target != nil {
+ ability = abilityBySlot(target, game.Slot)
+ }
+ if target == nil || ability == nil {
+ // Pool was refreshed mid-round and the slot is gone — drop the round.
+ if err := clearGame(ctx, s.kv, subject); err != nil {
+ return err
+ }
+ return chathelper.ReplyHTML(ctx, b, msg.Chat.ID,
+ "Ability data was updated since this round started. "+newRoundHint)
+ }
+
+ if arg == "" {
+ return sendAbilityIcon(ctx, b, msg.Chat.ID, ability, caption(len(game.Guesses), maxGuesses))
+ }
+
+ guess := champname.Find(s.pool, arg, championName)
+ if guess == nil {
+ return chathelper.Reply(ctx, b, msg.Chat.ID, fmt.Sprintf("Champion not found: %q.", arg))
+ }
+
+ for _, prior := range game.Guesses {
+ if prior == guess.ChampionName {
+ return chathelper.ReplyHTML(ctx, b, msg.Chat.ID, fmt.Sprintf(
+ "🔁 %s was already guessed this round — try another champion.",
+ html.EscapeString(guess.ChampionName)))
+ }
+ }
+
+ if game.StartedAt == nil {
+ now := chathelper.NowMillis()
+ game.StartedAt = &now
+ }
+ game.Guesses = append(game.Guesses, guess.ChampionName)
+ won := guess.ChampionName == target.ChampionName
+ answer := html.EscapeString(target.ChampionName)
+ abilityLabel := fmt.Sprintf("%s (%s)", html.EscapeString(ability.Name), ability.Slot)
+
+ switch {
+ case won:
+ st, err := recordResult(ctx, s.kv, subject, true)
+ if err != nil {
+ return err
+ }
+ if err := clearGame(ctx, s.kv, subject); err != nil {
+ return err
+ }
+ return chathelper.ReplyHTML(ctx, b, msg.Chat.ID, fmt.Sprintf(
+ "🎉 Got it! That was %s — %s. Solved in %d/%d\n🔥 Streak: %d\n%s",
+ answer, abilityLabel, len(game.Guesses), maxGuesses, st.Streak, newRoundHint))
+
+ case len(game.Guesses) >= maxGuesses:
+ if _, err := recordResult(ctx, s.kv, subject, false); err != nil {
+ return err
+ }
+ if err := clearGame(ctx, s.kv, subject); err != nil {
+ return err
+ }
+ return chathelper.ReplyHTML(ctx, b, msg.Chat.ID, fmt.Sprintf(
+ "❌ Out of guesses. Answer was %s — %s.\n%s",
+ answer, abilityLabel, newRoundHint))
+
+ default:
+ if err := saveGame(ctx, s.kv, subject, game); err != nil {
+ return err
+ }
+ return chathelper.ReplyHTML(ctx, b, msg.Chat.ID, fmt.Sprintf(
+ "❌ Not %s. Guess %d/%d.",
+ html.EscapeString(guess.ChampionName), len(game.Guesses), maxGuesses))
+ }
+}
+
+// handleGiveup is /loldle_ability_giveup — reveal answer + clear round.
+func (s *state) handleGiveup(ctx context.Context, b *bot.Bot, update *models.Update) error {
+ msg := update.Message
+ if msg == nil {
+ return nil
+ }
+ subject := chathelper.SubjectFor(msg)
+ if subject == "" {
+ return chathelper.Reply(ctx, b, msg.Chat.ID, "Cannot identify chat.")
+ }
+ defer s.locks.Acquire(subject)()
+
+ existing, err := loadGame(ctx, s.kv, subject)
+ if err != nil {
+ return err
+ }
+ if existing == nil {
+ return chathelper.ReplyHTML(ctx, b, msg.Chat.ID, "No active round. "+newRoundHint)
+ }
+ if _, err := recordResult(ctx, s.kv, subject, false); err != nil {
+ return err
+ }
+ target := champname.FindByExactName(s.pool, existing.Target, championName)
+ var label string
+ if target != nil {
+ if a := abilityBySlot(target, existing.Slot); a != nil {
+ label = fmt.Sprintf(" — %s (%s)", html.EscapeString(a.Name), a.Slot)
+ }
+ }
+ if err := clearGame(ctx, s.kv, subject); err != nil {
+ return err
+ }
+ return chathelper.ReplyHTML(ctx, b, msg.Chat.ID, fmt.Sprintf(
+ "🏳️ Answer was %s%s.\n%s",
+ html.EscapeString(existing.Target), label, newRoundHint))
+}
+
+// handleStats is /loldle_ability_stats — lifetime score.
+func (s *state) handleStats(ctx context.Context, b *bot.Bot, update *models.Update) error {
+ msg := update.Message
+ if msg == nil {
+ return nil
+ }
+ subject := chathelper.SubjectFor(msg)
+ if subject == "" {
+ return chathelper.Reply(ctx, b, msg.Chat.ID, "Cannot identify chat.")
+ }
+ st, err := loadStats(ctx, s.kv, subject)
+ if err != nil {
+ return err
+ }
+ scope := "group"
+ if msg.Chat.Type == models.ChatTypePrivate {
+ scope = "your"
+ }
+ return chathelper.Reply(ctx, b, msg.Chat.ID, fmt.Sprintf(
+ "📊 Loldle Ability %s stats\nPlayed: %d\nWins: %d (%d%%)\nCurrent streak: %d\nBest streak: %d",
+ scope, st.Played, st.Wins, chathelper.WinRate(st.Wins, st.Played), st.Streak, st.BestStreak))
+}
+
+// handleSetMax is /loldle_ability_setmax — private; per-subject override.
+func (s *state) handleSetMax(ctx context.Context, b *bot.Bot, update *models.Update) error {
+ msg := update.Message
+ if msg == nil {
+ return nil
+ }
+ subject := chathelper.SubjectFor(msg)
+ if subject == "" {
+ return chathelper.Reply(ctx, b, msg.Chat.ID, "Cannot identify chat.")
+ }
+ arg := chathelper.ArgAfterCommand(msg.Text)
+ n, err := strconv.Atoi(arg)
+ if err != nil || n < 1 || n > MaxGuessesCap {
+ return chathelper.Reply(ctx, b, msg.Chat.ID, fmt.Sprintf("Usage: /loldle_ability_setmax <1-%d>", MaxGuessesCap))
+ }
+ if err := setMaxGuesses(ctx, s.kv, subject, n); err != nil {
+ return err
+ }
+ return chathelper.Reply(ctx, b, msg.Chat.ID, fmt.Sprintf("✅ Loldle ability max guesses set to %d (applies to the next round).", n))
+}
diff --git a/internal/modules/loldleability/handlers_test.go b/internal/modules/loldleability/handlers_test.go
new file mode 100644
index 0000000..717931c
--- /dev/null
+++ b/internal/modules/loldleability/handlers_test.go
@@ -0,0 +1,152 @@
+package loldleability
+
+import (
+ "context"
+ "strings"
+ "testing"
+
+ "github.com/tiennm99/miti99bot-go/internal/modules"
+ "github.com/tiennm99/miti99bot-go/internal/storage"
+ "github.com/tiennm99/miti99bot-go/internal/testutil"
+)
+
+// installAbility wires the loldle-ability module + auth (owner gates
+// /loldle_ability_setmax). seedTarget + seedSlot pre-seed a game so guess
+// outcomes are deterministic without hooking math/rand.
+func installAbility(t *testing.T, ownerID int64, seedSubject, seedTarget, seedSlot string) (*testutil.RecordingBot, storage.KVStore) {
+ t.Helper()
+ rb := testutil.NewRecordingBot(t)
+ provider := storage.NewMemoryProvider()
+ kv := provider.For("loldle-ability")
+ mod := New(modules.Deps{KV: kv})
+ reg := &modules.Registry{
+ Modules: []modules.Module{{Name: "loldle-ability", Commands: mod.Commands}},
+ AllCommands: map[string]modules.Command{},
+ }
+ for _, c := range mod.Commands {
+ reg.AllCommands[c.Name] = c
+ }
+ modules.Install(rb.Bot, reg, modules.Auth{BotOwnerID: ownerID})
+
+ if seedTarget != "" {
+ g := &gameState{Target: seedTarget, Slot: seedSlot, Guesses: []string{}}
+ if err := saveGame(context.Background(), kv, seedSubject, g); err != nil {
+ t.Fatalf("seed game: %v", err)
+ }
+ }
+ return rb, kv
+}
+
+// /loldle_ability with no arg sends a photo, not a text message.
+func TestAbility_NoArgSendsPhoto(t *testing.T) {
+ rb, _ := installAbility(t, 0, "1", "Aatrox", "Q")
+ rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(1, "/loldle_ability"))
+
+ calls := rb.Sent()
+ if len(calls) == 0 {
+ t.Fatal("/loldle_ability produced no reply")
+ }
+ last := calls[len(calls)-1]
+ if last.Method != "sendPhoto" {
+ t.Errorf("method = %q, want sendPhoto", last.Method)
+ }
+ // Aatrox Q icon — DDragon URL pattern.
+ photo := last.Form["photo"]
+ if !strings.Contains(photo, "AatroxQ") || !strings.Contains(photo, "ddragon.leagueoflegends.com") {
+ t.Errorf("photo = %q, want Aatrox Q DDragon URL", photo)
+ }
+ caption := last.Form["caption"]
+ if !strings.Contains(caption, "Guess the champion") {
+ t.Errorf("caption missing prompt: %q", caption)
+ }
+}
+
+func TestAbility_Win(t *testing.T) {
+ rb, _ := installAbility(t, 0, "1", "Aatrox", "Q")
+ rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(1, "/loldle_ability aatrox"))
+
+ got := rb.LastSent().Text()
+ if !strings.Contains(got, "Got it") {
+ t.Errorf("win reply missing 'Got it': %q", got)
+ }
+ if !strings.Contains(got, "Aatrox") {
+ t.Errorf("win reply missing 'Aatrox': %q", got)
+ }
+ // Ability label format: Name (Slot) — the slot must surface so the
+ // player sees which ability the bot was thinking of.
+ if !strings.Contains(got, "(Q)") {
+ t.Errorf("win reply missing slot tag (Q): %q", got)
+ }
+}
+
+func TestAbility_UnknownChampion(t *testing.T) {
+ rb, _ := installAbility(t, 0, "1", "Aatrox", "Q")
+ rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(1, "/loldle_ability ZilbeanZ"))
+
+ got := rb.LastSent().Text()
+ if !strings.Contains(got, "Champion not found") {
+ t.Errorf("unknown champion reject: %q", got)
+ }
+}
+
+func TestAbility_DuplicateGuessRejected(t *testing.T) {
+ rb, _ := installAbility(t, 0, "1", "Aatrox", "Q")
+ rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(1, "/loldle_ability ahri"))
+ rb.Reset()
+ rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(1, "/loldle_ability ahri"))
+
+ got := rb.LastSent().Text()
+ if !strings.Contains(got, "already guessed") {
+ t.Errorf("duplicate-guess reply: %q", got)
+ }
+}
+
+func TestAbilityGiveup_RevealsAnswerAndAbility(t *testing.T) {
+ rb, _ := installAbility(t, 0, "1", "Aatrox", "Q")
+ rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(1, "/loldle_ability_giveup"))
+
+ got := rb.LastSent().Text()
+ if !strings.Contains(got, "Aatrox") {
+ t.Errorf("/loldle_ability_giveup should reveal Aatrox: %q", got)
+ }
+ if !strings.Contains(got, "(Q)") {
+ t.Errorf("/loldle_ability_giveup should include slot label: %q", got)
+ }
+}
+
+func TestAbilityStats_Empty(t *testing.T) {
+ rb, _ := installAbility(t, 0, "", "", "")
+ rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(1, "/loldle_ability_stats"))
+
+ got := rb.LastSent().Text()
+ for _, want := range []string{"Played: 0", "Wins: 0 (0%)"} {
+ if !strings.Contains(got, want) {
+ t.Errorf("/loldle_ability_stats empty missing %q; got %q", want, got)
+ }
+ }
+}
+
+func TestAbilitySetMax_OwnerSucceeds(t *testing.T) {
+ rb, kv := installAbility(t, 999, "", "", "")
+ rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(999, "/loldle_ability_setmax 3"))
+
+ got := rb.LastSent().Text()
+ if !strings.Contains(got, "max guesses set to 3") {
+ t.Errorf("/loldle_ability_setmax reply: %q", got)
+ }
+ var cfg roundConfig
+ if err := kv.GetJSON(context.Background(), configKey("999"), &cfg); err != nil {
+ t.Fatalf("expected config persisted: %v", err)
+ }
+ if cfg.MaxGuesses != 3 {
+ t.Errorf("MaxGuesses persisted = %d, want 3", cfg.MaxGuesses)
+ }
+}
+
+func TestAbilitySetMax_DeniedToNonOwner(t *testing.T) {
+ rb, _ := installAbility(t, 999, "", "", "")
+ rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, "/loldle_ability_setmax 5"))
+ if calls := rb.Sent(); len(calls) != 0 {
+ t.Errorf("non-owner /loldle_ability_setmax replied: %+v", calls)
+ }
+}
diff --git a/internal/modules/loldleability/loldleability.go b/internal/modules/loldleability/loldleability.go
new file mode 100644
index 0000000..379fa49
--- /dev/null
+++ b/internal/modules/loldleability/loldleability.go
@@ -0,0 +1,39 @@
+package loldleability
+
+import (
+ "github.com/tiennm99/miti99bot-go/internal/modules"
+)
+
+// New is the loldle-ability module Factory. Loads the embedded pool once
+// and shares it (plus the per-subject lock map) across all handlers.
+func New(deps modules.Deps) modules.Module {
+ s := &state{kv: deps.KV, pool: loadPool()}
+ return modules.Module{
+ Commands: []modules.Command{
+ {
+ Name: "loldle_ability",
+ Visibility: modules.VisibilityPublic,
+ Description: "Ability loldle — guess the champion from an ability icon",
+ Handler: s.handleAbility,
+ },
+ {
+ Name: "loldle_ability_giveup",
+ Visibility: modules.VisibilityPublic,
+ Description: "Reveal the current ability loldle answer",
+ Handler: s.handleGiveup,
+ },
+ {
+ Name: "loldle_ability_stats",
+ Visibility: modules.VisibilityPublic,
+ Description: "Show your ability loldle stats (wins, streak)",
+ Handler: s.handleStats,
+ },
+ {
+ Name: "loldle_ability_setmax",
+ Visibility: modules.VisibilityPrivate,
+ Description: "Override ability loldle max guesses per round (1-10)",
+ Handler: s.handleSetMax,
+ },
+ },
+ }
+}
diff --git a/internal/modules/loldleability/lookup_test.go b/internal/modules/loldleability/lookup_test.go
new file mode 100644
index 0000000..9cbac2b
--- /dev/null
+++ b/internal/modules/loldleability/lookup_test.go
@@ -0,0 +1,55 @@
+package loldleability
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/tiennm99/miti99bot-go/internal/champname"
+)
+
+func TestLoadPool_AbilitiesNonEmpty(t *testing.T) {
+ pool := loadPool()
+ if n := len(pool); n < 150 || n > 200 {
+ t.Errorf("pool size = %d, want ~172", n)
+ }
+ for _, c := range pool {
+ if len(c.Abilities) == 0 {
+ t.Errorf("empty abilities record leaked through filter: %s", c.ChampionName)
+ }
+ }
+ got := champname.FindByExactName(pool, "Aatrox", championName)
+ if got == nil {
+ t.Fatal("expected Aatrox in pool")
+ }
+ // Aatrox should have all 5 standard ability slots present.
+ slots := map[string]bool{}
+ for _, a := range got.Abilities {
+ slots[a.Slot] = true
+ if !strings.HasPrefix(a.Icon, "https://ddragon.leagueoflegends.com/cdn/") {
+ t.Errorf("Aatrox ability %s icon is not a DDragon URL: %q", a.Slot, a.Icon)
+ }
+ }
+ for _, want := range []string{"P", "Q", "W", "E", "R"} {
+ if !slots[want] {
+ t.Errorf("Aatrox missing slot %q", want)
+ }
+ }
+}
+
+func TestAbilityBySlot(t *testing.T) {
+ c := &AbilityChampion{
+ ChampionName: "Test",
+ Abilities: []Ability{
+ {Slot: "P", Name: "Passive"},
+ {Slot: "Q", Name: "Q ability"},
+ {Slot: "R", Name: "R ability"},
+ },
+ }
+ if got := abilityBySlot(c, "Q"); got == nil || got.Name != "Q ability" {
+ t.Errorf("abilityBySlot(Q) = %v, want 'Q ability'", got)
+ }
+ // Unknown slot → nil (caller treats as refresh signal).
+ if got := abilityBySlot(c, "W"); got != nil {
+ t.Errorf("abilityBySlot(W) = %v, want nil (slot not present)", got)
+ }
+}
diff --git a/internal/modules/loldleability/state.go b/internal/modules/loldleability/state.go
new file mode 100644
index 0000000..15647f5
--- /dev/null
+++ b/internal/modules/loldleability/state.go
@@ -0,0 +1,127 @@
+package loldleability
+
+import (
+ "context"
+ "errors"
+ "fmt"
+
+ "github.com/tiennm99/miti99bot-go/internal/storage"
+)
+
+// Round-length defaults. Mirror JS: 5 default, capped at 10 via
+// /loldle_ability_setmax.
+const (
+ MaxGuesses = 5
+ MaxGuessesCap = 10
+)
+
+// gameState differs from emoji/quote: it locks the chosen ability slot at
+// round start so the SAME icon shows across every turn until the round ends.
+// Field tags match JS.
+type gameState struct {
+ Target string `json:"target"`
+ Slot string `json:"slot"` // ability slot — P, Q, W, E, R
+ Guesses []string `json:"guesses"`
+ StartedAt *int64 `json:"startedAt"`
+}
+
+type stats struct {
+ Played int `json:"played"`
+ Wins int `json:"wins"`
+ Streak int `json:"streak"`
+ BestStreak int `json:"bestStreak"`
+}
+
+type roundConfig struct {
+ MaxGuesses int `json:"maxGuesses"`
+}
+
+func gameKey(subject string) string { return "game:" + subject }
+func statsKey(subject string) string { return "stats:" + subject }
+func configKey(subject string) string { return "config:" + subject }
+
+func loadGame(ctx context.Context, kv storage.KVStore, subject string) (*gameState, error) {
+ var g gameState
+ err := kv.GetJSON(ctx, gameKey(subject), &g)
+ switch {
+ case err == nil:
+ return &g, nil
+ case errors.Is(err, storage.ErrNotFound):
+ return nil, nil
+ default:
+ return nil, fmt.Errorf("loldleability loadGame: %w", err)
+ }
+}
+
+func saveGame(ctx context.Context, kv storage.KVStore, subject string, g *gameState) error {
+ if err := kv.PutJSON(ctx, gameKey(subject), g); err != nil {
+ return fmt.Errorf("loldleability saveGame: %w", err)
+ }
+ return nil
+}
+
+func clearGame(ctx context.Context, kv storage.KVStore, subject string) error {
+ if err := kv.Delete(ctx, gameKey(subject)); err != nil {
+ return fmt.Errorf("loldleability clearGame: %w", err)
+ }
+ return nil
+}
+
+func loadStats(ctx context.Context, kv storage.KVStore, subject string) (*stats, error) {
+ var s stats
+ err := kv.GetJSON(ctx, statsKey(subject), &s)
+ switch {
+ case err == nil:
+ return &s, nil
+ case errors.Is(err, storage.ErrNotFound):
+ return &stats{}, nil
+ default:
+ return nil, fmt.Errorf("loldleability loadStats: %w", err)
+ }
+}
+
+func recordResult(ctx context.Context, kv storage.KVStore, subject string, won bool) (*stats, error) {
+ s, err := loadStats(ctx, kv, subject)
+ if err != nil {
+ return nil, err
+ }
+ s.Played++
+ if won {
+ s.Wins++
+ s.Streak++
+ if s.Streak > s.BestStreak {
+ s.BestStreak = s.Streak
+ }
+ } else {
+ s.Streak = 0
+ }
+ if err := kv.PutJSON(ctx, statsKey(subject), s); err != nil {
+ return nil, fmt.Errorf("loldleability recordResult: %w", err)
+ }
+ return s, nil
+}
+
+func getMaxGuesses(ctx context.Context, kv storage.KVStore, subject string) (int, error) {
+ var cfg roundConfig
+ err := kv.GetJSON(ctx, configKey(subject), &cfg)
+ if err != nil {
+ if errors.Is(err, storage.ErrNotFound) {
+ return MaxGuesses, nil
+ }
+ return 0, fmt.Errorf("loldleability getMaxGuesses: %w", err)
+ }
+ if cfg.MaxGuesses < 1 || cfg.MaxGuesses > MaxGuessesCap {
+ return MaxGuesses, nil
+ }
+ return cfg.MaxGuesses, nil
+}
+
+func setMaxGuesses(ctx context.Context, kv storage.KVStore, subject string, n int) error {
+ if n < 1 || n > MaxGuessesCap {
+ return fmt.Errorf("loldleability: maxGuesses must be in [1, %d], got %d", MaxGuessesCap, n)
+ }
+ if err := kv.PutJSON(ctx, configKey(subject), roundConfig{MaxGuesses: n}); err != nil {
+ return fmt.Errorf("loldleability setMaxGuesses: %w", err)
+ }
+ return nil
+}
diff --git a/internal/modules/loldleability/state_test.go b/internal/modules/loldleability/state_test.go
new file mode 100644
index 0000000..cb364f3
--- /dev/null
+++ b/internal/modules/loldleability/state_test.go
@@ -0,0 +1,81 @@
+package loldleability
+
+import (
+ "context"
+ "encoding/json"
+ "testing"
+
+ "github.com/tiennm99/miti99bot-go/internal/storage"
+)
+
+// gameState gains a `slot` field vs emoji/quote — locks the chosen ability
+// at round start. JSON wire format must include `slot`.
+func TestGameState_IncludesSlotField(t *testing.T) {
+ g := gameState{Target: "Aatrox", Slot: "Q", Guesses: []string{}}
+ b, err := json.Marshal(g)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := `{"target":"Aatrox","slot":"Q","guesses":[],"startedAt":null}`
+ if string(b) != want {
+ t.Errorf("marshal:\ngot %s\nwant %s", b, want)
+ }
+}
+
+// JS-wire-format decode parity: a record written by the JS bot must decode
+// directly. Locks the slot field name + null-startedAt round-trip.
+func TestGameState_DecodeFromJSWire(t *testing.T) {
+ var g gameState
+ raw := []byte(`{"target":"Ahri","slot":"E","guesses":["Akali"],"startedAt":1700000000000}`)
+ if err := json.Unmarshal(raw, &g); err != nil {
+ t.Fatalf("unmarshal: %v", err)
+ }
+ if g.Target != "Ahri" || g.Slot != "E" || len(g.Guesses) != 1 || g.StartedAt == nil || *g.StartedAt != 1700000000000 {
+ t.Errorf("decoded: %+v", g)
+ }
+}
+
+func TestGetMaxGuesses_DefaultsToFive(t *testing.T) {
+ ctx := context.Background()
+ kv := storage.NewMemoryKVStore()
+ if n, _ := getMaxGuesses(ctx, kv, "u1"); n != MaxGuesses {
+ t.Errorf("default = %d, want %d", n, MaxGuesses)
+ }
+ if MaxGuesses != 5 {
+ t.Errorf("MaxGuesses = %d, want 5 (parity with JS)", MaxGuesses)
+ }
+}
+
+func TestRecordResult_StreakSequence(t *testing.T) {
+ ctx := context.Background()
+ kv := storage.NewMemoryKVStore()
+ s, _ := recordResult(ctx, kv, "u1", true)
+ if s.Streak != 1 || s.Wins != 1 {
+ t.Errorf("first win: %+v", s)
+ }
+ s, _ = recordResult(ctx, kv, "u1", false)
+ if s.Streak != 0 || s.BestStreak != 1 {
+ t.Errorf("loss after streak=1: %+v", s)
+ }
+}
+
+func TestSaveLoadClear_RoundTrip(t *testing.T) {
+ ctx := context.Background()
+ kv := storage.NewMemoryKVStore()
+ at := int64(42)
+ want := &gameState{Target: "Aatrox", Slot: "R", Guesses: []string{"Ahri"}, StartedAt: &at}
+ if err := saveGame(ctx, kv, "u1", want); err != nil {
+ t.Fatal(err)
+ }
+ got, _ := loadGame(ctx, kv, "u1")
+ if got == nil || got.Slot != "R" {
+ t.Errorf("round-trip lost slot: %+v", got)
+ }
+ if err := clearGame(ctx, kv, "u1"); err != nil {
+ t.Fatal(err)
+ }
+ got, _ = loadGame(ctx, kv, "u1")
+ if got != nil {
+ t.Errorf("after clear, got %+v, want nil", got)
+ }
+}
diff --git a/plans/260508-2222-go-port-cloud-run/phase-06-port-loldle-variants.md b/plans/260508-2222-go-port-cloud-run/phase-06-port-loldle-variants.md
index e21b897..a4e7f72 100644
--- a/plans/260508-2222-go-port-cloud-run/phase-06-port-loldle-variants.md
+++ b/plans/260508-2222-go-port-cloud-run/phase-06-port-loldle-variants.md
@@ -69,6 +69,7 @@ A small shared package would help, but keep modules independent (KISS) until dup
This phase ships in five sub-cooks (one per module — each is large enough to risk context exhaustion):
- **6a:** loldle-emoji — 172-record emoji clue dict, binary scoring, simplest variant. ✅
- **6b:** loldle-quote — quote-pool variant, default 6 guesses. ✅ (consumes the shared `chathelper` + `champname` packages extracted in fix-all-review-findings Phase 03)
+- **6c:** loldle-ability — DDragon ability-icon URL builder, sendPhoto reply, gameState gains a `slot` field so the same icon shows across guesses. ✅
- **6c (next):** loldle-ability — DDragon ability-icon URL builder, sendPhoto.
- **6d (next):** loldle-splash — DDragon splash URL builder, sendPhoto.
- **6e (next):** lolschedule — HTTP client to lolesports/leaguepedia API; no game state, different shape entirely.
@@ -76,7 +77,8 @@ This phase ships in five sub-cooks (one per module — each is large enough to r
## Success Criteria
- [x] loldle-emoji responds to `/loldle_emoji`, `/loldle_emoji_giveup`, `/loldle_emoji_stats`, `/loldle_emoji_setmax`
- [x] loldle-quote responds to `/loldle_quote`, `/loldle_quote_giveup`, `/loldle_quote_stats`, `/loldle_quote_setmax`
-- [ ] Ability + splash images render in Telegram (no broken-image markers) — deferred to 6c/6d
+- [x] loldle-ability responds to `/loldle_ability`, `/loldle_ability_giveup`, `/loldle_ability_stats`, `/loldle_ability_setmax`; sendPhoto path uses the DDragon icon URL directly
+- [ ] Splash images render in Telegram (no broken-image markers) — deferred to 6d
- [ ] `/lolschedule today` matches JS behavior — deferred to 6e
- [x] All variants share consistent guess-count limits matching JS (emoji 5, quote 6 — JS parity)
- [x] Ported tests pass for loldle-emoji + loldle-quote (lookup, state, render, JS-wire-format decode, handler integration)