from typing import List, Union, Set
from merakicommons.cache import lazy, lazy_property
from merakicommons.container import searchable, SearchableList
from ...data import Resource, Region, Platform, GameMode
from ..common import (
CoreData,
CoreDataList,
CassiopeiaObject,
CassiopeiaGhost,
CassiopeiaLazyList,
get_latest_version,
ghost_load_on,
)
from .common import ImageData, Image, Sprite
from ...dto.staticdata import summonerspell as dto
##############
# Data Types #
##############
class SummonerSpellListData(CoreDataList):
_dto_type = dto.SummonerSpellListDto
_renamed = {"included_data": "includedData"}
class SpellVarsData(CoreData):
_renamed = {"dyn": "dynamic", "coeff": "coefficients"}
class LevelTipData(CoreData):
_renamed = {"effect": "effects", "label": "keywords"}
class SummonerSpellData(CoreData):
_dto_type = dto.SummonerSpellDto
_renamed = {
"maxrank": "maxRank",
"cooldown": "cooldowns",
"cost": "costs",
"effect": "effects",
"costType": "resource",
"included_data": "includedData",
}
def __call__(self, **kwargs):
if "vars" in kwargs:
self.variables = [SpellVarsData(**v) for v in kwargs.pop("vars")]
if "altimages" in kwargs:
self.alternativeImages = [
ImageData(**alt) for alt in kwargs.pop("altimages")
]
if "image" in kwargs:
self.image = ImageData(**kwargs.pop("image"))
super().__call__(**kwargs)
return self
##############
# Core Types #
##############
[docs]class SummonerSpells(CassiopeiaLazyList):
_data_types = {SummonerSpellListData}
def __init__(
self,
*,
region: Union[Region, str] = None,
version: str = None,
locale: str = None,
included_data: Set[str] = None
):
if included_data is None:
included_data = {"all"}
if locale is None and region is not None:
locale = Region(region).default_locale
kwargs = {"region": region, "included_data": included_data, "locale": locale}
if version:
kwargs["version"] = version
CassiopeiaObject.__init__(self, **kwargs)
@lazy_property
def region(self) -> Region:
return Region(self._data[SummonerSpellListData].region)
@lazy_property
def platform(self) -> Platform:
return self.region.platform
@property
def version(self) -> str:
try:
return self._data[SummonerSpellListData].version
except AttributeError:
version = get_latest_version(region=self.region, endpoint="summoner")
self(version=version)
return self._data[SummonerSpellListData].version
@property
def locale(self) -> str:
"""The locale for this champion."""
return self._data[SummonerSpellListData].locale
@property
def included_data(self) -> Set[str]:
"""A set of tags to return additonal information for this champion when it's loaded."""
return self._data[SummonerSpellListData].includedData
[docs]@searchable({str: ["key"]})
class SpellVars(CassiopeiaObject):
_data_types = {SpellVarsData}
@property
def ranks_with(self) -> str:
"""Well, we don't know what this one is. let us know if you figure it out."""
return self._data[SpellVarsData].ranksWith
@property
def dynamic(self) -> str:
"""Well, we don't know what this one is. let us know if you figure it out."""
return self._data[SpellVarsData].dynamic
@property
def link(self) -> str:
"""Stat this spell scales from."""
return self._data[SpellVarsData].link
@lazy_property
def coefficients(self) -> List[float]:
"""The scaling coefficients for this spell."""
return SearchableList(self._data[SpellVarsData].coefficients)
@property
def key(self) -> str:
"""Well, we don't know what this one is. let us know if you figure it out."""
return self._data[SpellVarsData].key
[docs]@searchable({str: ["name", "key", "keywords"]})
class SummonerSpell(CassiopeiaGhost):
_data_types = {SummonerSpellData}
def __init__(
self,
*,
id: int = None,
name: str = None,
region: Union[Region, str] = None,
version: str = None,
locale: str = None,
included_data: Set[str] = None
):
if included_data is None:
included_data = {"all"}
if locale is None and region is not None:
locale = Region(region).default_locale
kwargs = {"region": region, "included_data": included_data, "locale": locale}
if id is not None:
kwargs["id"] = id
if name is not None:
kwargs["name"] = name
if version is not None:
kwargs["version"] = version
super().__init__(**kwargs)
def __get_query__(self):
query = {
"region": self.region,
"platform": self.platform,
"version": self.version,
"locale": self.locale,
"includedData": self.included_data,
}
if hasattr(self._data[SummonerSpellData], "id"):
query["id"] = self._data[SummonerSpellData].id
if hasattr(self._data[SummonerSpellData], "name"):
query["name"] = self._data[SummonerSpellData].name
return query
def __eq__(self, other: "SummonerSpell"):
if not isinstance(other, SummonerSpell) or self.region != other.region:
return False
s = {}
o = {}
if hasattr(self._data[SummonerSpellData], "id"):
s["id"] = self.id
if hasattr(other._data[SummonerSpellData], "id"):
o["id"] = other.id
if hasattr(self._data[SummonerSpellData], "name"):
s["name"] = self.name
if hasattr(other._data[SummonerSpellData], "name"):
o["name"] = other.name
if any(s.get(key, "s") == o.get(key, "o") for key in s):
return True
else:
return self.id == other.id
def __str__(self):
region = self.region
id_ = "?"
name = "?"
if hasattr(self._data[SummonerSpellData], "id"):
id_ = self.id
if hasattr(self._data[SummonerSpellData], "name"):
name = self.name
return "SummonerSpell(name='{name}', id={id_}, region='{region}')".format(
name=name, id_=id_, region=region.value
)
__hash__ = CassiopeiaGhost.__hash__
@lazy_property
def region(self) -> Region:
"""The region for this summoner spell."""
return Region(self._data[SummonerSpellData].region)
@lazy_property
def platform(self) -> Platform:
"""The platform for this summoner spell."""
return self.region.platform
@property
def version(self) -> str:
"""The version for this summoner spell."""
try:
return self._data[SummonerSpellData].version
except AttributeError:
version = get_latest_version(region=self.region, endpoint="summoner")
self(version=version)
return self._data[SummonerSpellData].version
@property
def locale(self) -> str:
"""The locale for this summoner spell."""
return self._data[SummonerSpellData].locale or self.region.default_locale
@property
def included_data(self) -> Set[str]:
"""The data to included in the query for this summoner spell."""
return self._data[SummonerSpellData].includedData
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
@lazy
def modes(self) -> List[GameMode]:
return SearchableList(
[GameMode(mode) for mode in self._data[SummonerSpellData].modes]
)
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
@lazy
def variables(self) -> List[SpellVars]:
"""Contains spell data."""
return SearchableList(
SpellVars(v) for v in self._data[SummonerSpellData].variables
)
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
@lazy
def resource(self) -> Resource:
"""The resource consumed when using this spell."""
return Resource(self._data[SummonerSpellData].resource)
@lazy_property
def sprite(self) -> Sprite:
return self.image.sprite_info
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
def sanitized_description(self) -> str:
"""The spell's sanitized description."""
return self._data[SummonerSpellData].sanitized_description
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
def sanitized_tooltip(self) -> str:
"""The spell's sanitized tooltip."""
return self._data[SummonerSpellData].sanitizedTooltip
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
@lazy
def effects(self) -> List[List[float]]:
"""The level-by-level replacements for {{ e# }} tags in other values."""
return SearchableList(self._data[SummonerSpellData].effects)
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
def tooltip(self) -> str:
"""The spell's tooltip."""
return self._data[SummonerSpellData].tooltip
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
def max_rank(self) -> int:
"""The maximum rank this spell can attain."""
return self._data[SummonerSpellData].maxRank
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
@lazy
def range(self) -> List[Union[int, str]]:
"""The maximum range of this spell. `self` if it has no range."""
return SearchableList(self._data[SummonerSpellData].range)
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
@lazy
def cooldowns(self) -> List[float]:
"""The cooldowns of this spell (per level)."""
return SearchableList(self._data[SummonerSpellData].cooldowns)
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
@lazy
def costs(self) -> List[int]:
"""The resource costs of this spell (per level)."""
return SearchableList(self._data[SummonerSpellData].costs)
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
def key(self) -> str:
"""The spell's key."""
return self._data[SummonerSpellData].key
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
def description(self) -> str:
"""The spell's description."""
return self._data[SummonerSpellData].description
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
@lazy
def alternative_images(self) -> List[Image]:
"""The alternative images for this spell. These won't exist after patch NN, when Riot standardized all images."""
return SearchableList(
Image.from_data(alt)
for alt in self._data[SummonerSpellData].alternativeImages
)
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
def id(self) -> int:
"""The spell's id."""
return self._data[SummonerSpellData].id
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
def name(self) -> str:
"""The spell's name."""
return self._data[SummonerSpellData].name
@CassiopeiaGhost.property(SummonerSpellData)
@ghost_load_on
@lazy
def image(self) -> Image:
image = Image.from_data(self._data[SummonerSpellData].image)
image(version=self.version)
return image
@lazy_property
def sprite(self) -> Sprite:
return self.image.spriteInfo