PaiGram/plugins/genshin/model/base.py
2024-11-30 22:32:07 +08:00

206 lines
7.9 KiB
Python

from decimal import Decimal
from enum import Enum
from typing import Optional, List, NewType
from pydantic import field_validator, BaseModel, Field, ValidationInfo
# TODO: 考虑自动生成Enum
Character = NewType("Character", str)
Weapon = NewType("Weapon", str)
Set = NewType("Set", str)
class DigitType(Enum):
NUMERIC = "numeric"
PERCENT = "percent"
class Digit(BaseModel):
type: DigitType
value: Decimal
class WeaponType(Enum):
BOW = "bow"
CLAYMORE = "claymore"
CATALYST = "catalyst"
POLEARM = "polearm"
SWORD = "sword"
class ArtifactPosition(Enum):
FLOWER = "flower"
PLUME = "plume"
SANDS = "sands"
GOBLET = "goblet"
CIRCLET = "circlet"
class ArtifactAttributeType(Enum):
HP = "hp"
ATK = "atk"
DEF = "def"
HP_PERCENT = "hp_percent"
ATK_PERCENT = "atk_percent"
DEF_PERCENT = "def_percent"
ELEMENTAL_MASTERY = "elemental_mastery"
ENERGY_RECHARGE = "energy_recharge"
CRIT_RATE = "crit_rate"
CRIT_DMG = "crit_dmg"
HEALING_BONUS = "healing_bonus"
PYRO_DMG_BONUS = "pyro_dmg_bonus"
HYDRO_DMG_BONUS = "hydro_dmg_bonus"
DENDRO_DMG_BONUS = "dendro_dmg_bonus"
ELECTRO_DMG_BONUS = "electro_dmg_bonus"
ANEMO_DMG_BONUS = "anemo_dmg_bonus"
CRYO_DMG_BONUS = "cryo_dmg_bonus"
GEO_DMG_BONUS = "geo_dmg_bonus"
PHYSICAL_DMG_BONUS = "physical_dmg_bonus"
class ArtifactAttribute(BaseModel):
type: ArtifactAttributeType
digit: Digit
class WeaponInfo(BaseModel):
id: int = 0
weapon: Weapon = ""
type: WeaponType
level: int = 0
max_level: int = 0
refinement: int = 0
ascension: int = 0
@field_validator("max_level")
@classmethod
def validate_max_level(cls, v, info: ValidationInfo):
if v == 0:
return info.data["level"]
if v < info.data["level"]:
raise ValueError("max_level must be greater than or equal to level")
return v
@field_validator("refinement")
@classmethod
def validate_refinement(cls, v):
if v < 0 or v > 5:
raise ValueError("refinement must be between 1 and 5")
return v
class Artifact(BaseModel):
id: int = 0
set: Set = ""
position: ArtifactPosition
level: int = 0
rarity: int = 0
main_attribute: ArtifactAttribute
sub_attributes: List[ArtifactAttribute] = []
@field_validator("level")
@classmethod
def validate_level(cls, v):
if v < 0 or v > 20:
raise ValueError("level must be between 0 and 20")
return v
@field_validator("rarity")
@classmethod
def validate_rarity(cls, v):
if v < 0 or v > 5:
raise ValueError("rarity must be between 0 and 5")
return v
@field_validator("sub_attributes")
@classmethod
def validate_sub_attributes(cls, v):
if len(v) > 4:
raise ValueError("sub_attributes must not be greater than 4")
return v
class CharacterStats(BaseModel):
BASE_HP: Digit = Digit(type=DigitType.NUMERIC, value=Decimal(0))
HP: Digit = Field(Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_HP")
HP_PERCENT: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_HP_PERCENT")
BASE_ATTACK: Digit = Field(Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_BASE_ATTACK")
ATTACK: Digit = Field(Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_ATTACK")
ATTACK_PERCENT: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_ATTACK_PERCENT")
BASE_DEFENSE: Digit = Field(Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_BASE_DEFENSE")
DEFENSE: Digit = Field(Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_DEFENSE")
DEFENSE_PERCENT: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_DEFENSE_PERCENT")
ELEMENTAL_MASTERY: Digit = Field(
Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_ELEMENT_MASTERY"
)
CRIT_RATE: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_CRITICAL")
CRIT_DMG: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_CRITICAL_HURT")
HEALING_BONUS: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_HEAL_ADD")
INCOMING_HEALING_BONUS: Digit = Field(
Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_HEALED_ADD"
)
ENERGY_RECHARGE: Digit = Field(
Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_CHARGE_EFFICIENCY"
)
CD_REDUCTION: Digit = Field(
Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_SKILL_CD_MINUS_RATIO"
)
SHIELD_STRENGTH: Digit = Field(
Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_SHIELD_COST_MINUS_RATIO"
)
PYRO_DMG_BONUS: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_FIRE_ADD_HURT")
PYRO_RES: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_FIRE_SUB_HURT")
HYDRO_DMG_BONUS: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_WATER_ADD_HURT")
HYDRO_RES: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_WATER_SUB_HURT")
DENDRO_DMG_BONUS: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_GRASS_ADD_HURT")
DENDRO_RES: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_GRASS_SUB_HURT")
ELECTRO_DMG_BONUS: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_ELEC_ADD_HURT")
ELECTRO_RES: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_ELEC_SUB_HURT")
ANEMO_DMG_BONUS: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_WIND_ADD_HURT")
ANEMO_RES: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_WIND_SUB_HURT")
CRYO_DMG_BONUS: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_ICE_ADD_HURT")
CRYO_RES: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_ICE_SUB_HURT")
GEO_DMG_BONUS: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_ROCK_ADD_HURT")
GEO_RES: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_ROCK_SUB_HURT")
PHYSICAL_DMG_BONUS: Digit = Field(
Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_PHYSICAL_SUB_HURT"
)
PHYSICAL_RES: Digit = Field(Digit(type=DigitType.PERCENT, value=Decimal(0)), alias="FIGHT_PROP_PHYSICAL_ADD_HURT")
CURRENT_HP: Digit = Field(Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_CUR_HP")
MAX_HP: Digit = Field(Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_MAX_HP")
CURRENT_ATTACK: Digit = Field(Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_CUR_ATTACK")
CURRENT_DEFENSE: Digit = Field(Digit(type=DigitType.NUMERIC, value=Decimal(0)), alias="FIGHT_PROP_CUR_DEFENSE")
class CharacterInfo(BaseModel):
id: int = 0
character: Character = ""
weapon_info: Optional[WeaponInfo] = None
artifacts: List[Artifact] = []
level: int = 0
max_level: int = 0
constellation: int = 0
ascension: int = 0
skills: List[int] = []
rarity: int = 0
stats: CharacterStats = CharacterStats()
@field_validator("max_level")
@classmethod
def validate_max_level(cls, v, info: ValidationInfo):
if v == 0:
return info.data["level"]
if v < info.data["level"]:
raise ValueError("max_level must be greater than or equal to level")
return v
@field_validator("skills")
@classmethod
def validate_skills(cls, v):
if len(v) > 3:
raise ValueError("skills must not be greater than 3")
return v