Skip to content
This repository has been archived by the owner on Jun 9, 2022. It is now read-only.

Commit

Permalink
ADD - Ability parsing prototype
Browse files Browse the repository at this point in the history
Signed-off-by: RaenonX <[email protected]>
  • Loading branch information
RaenonX committed Dec 18, 2020
1 parent a7f9cc3 commit 754b562
Show file tree
Hide file tree
Showing 25 changed files with 549 additions and 127 deletions.
2 changes: 1 addition & 1 deletion .data/media
Submodule media updated from a015de to 5b0988
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ View the data of all given hit attributes.
### Datamining and data deploying pipeline
- \[SimCord\] qwewqa
- \[SimCord\] qwewqa / Mustard Yellow
- \[SimCord\] eave
- **\[OM\] [Ryo][GH-ryo]**
Expand Down
3 changes: 3 additions & 0 deletions dlparse/enums/ability_variant.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ class AbilityVariantType(Enum):
CHANGE_STATE = 14
"""Calls the hit attribute (at str field) or the action condition (ID at ID-A field) if the condition holds."""

SP_CHARGE = 17
"""Charge the SP gauges."""

GAUGE_STATUS = 40
"""Grants different effects according to the user's gauge status."""

Expand Down
24 changes: 15 additions & 9 deletions dlparse/enums/buff_parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,31 @@ class BuffParameter(Enum):
"""Rate of SP gain. A value of 0.12 means SP +12%."""
SP_GAIN = 202
"""Immediate SP gain. A value of 100 means get SP 100."""
SP_CHARGE_PCT = 203
"""
Immediately charges the SP by certain % of **ALL** skills.
A value of 0.15 means to refill 15% SP of all skills.
"""
SP_CHARGE_PCT_S1 = 204
SP_CHARGE_PCT_S1 = 211
"""
Immediately charges the SP of **S1**.
A value of 0.15 means to refill 15% SP of S1.
"""
SP_CHARGE_PCT_S2 = 205
SP_CHARGE_PCT_S2 = 212
"""
Immediately charges the SP of **S2**.
A value of 0.15 means to refill 15% SP of S2.
"""
SP_CHARGE_PCT_USED = 206
SP_CHARGE_PCT_S3 = 213
"""
Immediately charges the SP of **S3**.
A value of 0.15 means to refill 15% SP of S3.
"""
SP_CHARGE_PCT_S4 = 214
"""
Immediately charges the SP of **S4**.
A value of 0.15 means to refill 15% SP of S4.
"""
SP_CHARGE_PCT_USED = 215
"""
Immediately charges the SP of the skill that was just used.
Expand Down
21 changes: 17 additions & 4 deletions dlparse/enums/skill_condition/category.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from dlparse.errors import EnumConversionError
from .items import SkillCondition
from ..ability_condition import AbilityCondition
from ..condition_base import ConditionCheckResultMixin
from ..element import Element
from ..status import Status
Expand Down Expand Up @@ -31,6 +32,7 @@ class SkillConditionCheckResult(ConditionCheckResultMixin, Enum):
MULTIPLE_ACTION_CONDITION = auto()
MULTIPLE_GAUGE_FILLED = auto()
MULTIPLE_LAPIS_CARD = auto()
MULTIPLE_MISC = auto()

INTERNAL_NOT_AFFLICTION_ONLY = auto()
INTERNAL_NOT_TARGET_ELEMENTAL = auto()
Expand Down Expand Up @@ -184,7 +186,7 @@ def get_members_lte(self, threshold: float) -> list[SkillCondition]:
class SkillConditionCategories:
"""Categories for skill conditions (:class:`SkillCondition`)."""

# region Target
# region 1xx - Target
target_status = SkillConditionCategory[Status](
{
# Abnormal statuses
Expand Down Expand Up @@ -227,7 +229,7 @@ class SkillConditionCategories:
)
# endregion

# region Self status (general)
# region 2xx - Self status (general)
self_hp_status = SkillConditionCategoryTargetNumber(
{
SkillCondition.SELF_HP_1: 0,
Expand Down Expand Up @@ -319,7 +321,7 @@ class SkillConditionCategories:
)
# endregion

# region Skill animation/effect
# region 3xx - Skill animation/effect
skill_bullet_hit = SkillConditionCategoryTargetNumber(
{
SkillCondition.BULLET_HIT_1: 1,
Expand Down Expand Up @@ -389,7 +391,7 @@ class SkillConditionCategories:
)
# endregion

# region Self status (special)
# region 4xx - Self status (special)
action_condition = SkillConditionCategoryTargetNumber(
{
# Value is the corresponding Action Condition ID (not necessary means that it needs to exist)
Expand Down Expand Up @@ -427,6 +429,17 @@ class SkillConditionCategories:
)
# endregion

# region 9xx - Miscellaneous
misc = SkillConditionCategory[AbilityCondition](
{
SkillCondition.QUEST_START: AbilityCondition.QUEST_START,
},
SkillConditionMaxCount.SINGLE,
"Miscellaneous",
SkillConditionCheckResult.MULTIPLE_MISC
)
# endregion

_action_cond_cat: dict[int, SkillConditionCategory] = {
1319: self_lapis_card
}
Expand Down
6 changes: 5 additions & 1 deletion dlparse/enums/skill_condition/composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ class SkillConditionComposite(ConditionCompositeBase[SkillCondition]):
SkillCondition.TARGET_OD_STATE,
SkillCondition.TARGET_BK_STATE,
SkillCondition.MARK_EXPLODES,
SkillCondition.SELF_ENERGIZED
SkillCondition.SELF_ENERGIZED,
SkillCondition.SKILL_USED_S1,
SkillCondition.SKILL_USED_S2,
SkillCondition.SKILL_USED_ALL,
SkillCondition.QUEST_START
}

# region Target
Expand Down
20 changes: 15 additions & 5 deletions dlparse/enums/skill_condition/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class SkillCondition(Enum):

NONE = 0

# region Target
# region 1xx - Target
# region Afflicted
TARGET_POISONED = 101
TARGET_BURNED = 102
Expand Down Expand Up @@ -54,7 +54,7 @@ class SkillCondition(Enum):
# endregion
# endregion

# region Self status (general)
# region 2xx - Self status (general)
# region HP
SELF_HP_1 = 200
"""User's HP = 1."""
Expand Down Expand Up @@ -139,7 +139,7 @@ class SkillCondition(Enum):
# endregion
# endregion

# region Skill animation/effect
# region 3xx - Skill animation/effect
# region Bullet hit count
BULLET_HIT_1 = 301
BULLET_HIT_2 = 302
Expand Down Expand Up @@ -194,7 +194,7 @@ class SkillCondition(Enum):
# endregion
# endregion

# region Self status (special)
# region 4xx - Self status (special)
# region Action condition (Sigil released, lapis cards, etc.)
SELF_SIGIL_LOCKED = 400 # ACID: 1152
SELF_SIGIL_RELEASED = 401
Expand All @@ -210,12 +210,22 @@ class SkillCondition(Enum):
SELF_GAUGE_FILLED_2 = 452
# endregion

# region Skill usage
SKILL_USED_S1 = 481
SKILL_USED_S2 = 482
SKILL_USED_ALL = 489
# endregion

# region Special (Energized, inspired)
SELF_ENERGIZED = 490

# endregion
# endregion

# region 9xx - Miscellaneous (e.g. quest start)
QUEST_START = 901

# endregion

def __bool__(self):
return self != SkillCondition.NONE

Expand Down
26 changes: 25 additions & 1 deletion dlparse/errors/mono_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from .base import AppValueError, EntryNotFoundError

__all__ = ("SkillDataNotFoundError", "ActionDataNotFoundError", "TextLabelNotFoundError",
"AbilityConditionUnconvertibleError", "BulletMaxCountUnavailableError")
"AbilityLimitDataNotFoundError", "AbilityOnSkillUnconvertibleError",
"AbilityConditionUnconvertibleError", "BulletMaxCountUnavailableError", "AbilityVariantUnconvertibleError")


class SkillDataNotFoundError(EntryNotFoundError):
Expand Down Expand Up @@ -35,6 +36,21 @@ def __init__(self, label: str):
super().__init__(f"Text of label {label} not found")


class AbilityLimitDataNotFoundError(EntryNotFoundError):
"""Error to be raised if the ability limit data is not found."""

def __init__(self, data_id: int):
super().__init__(f"Ability limit data of ID {data_id} not found")


class AbilityVariantUnconvertibleError(AppValueError):
"""Error to be raised if the ability variant cannot be converted to ability variant effect unit."""

def __init__(self, ability_id: int, variant_type: int):
super().__init__(f"Unable to convert ability variant to effect units "
f"(ability ID: {ability_id} / variant type ID {variant_type})")


class AbilityConditionUnconvertibleError(AppValueError):
"""Error to be raised if the ability condition cannot be converted to skill condition."""

Expand All @@ -43,5 +59,13 @@ def __init__(self, ability_condition: int, val_1: float, val_2: float):
f"(ability condition code: {ability_condition} / val 1: {val_1} / val 2: {val_2})")


class AbilityOnSkillUnconvertibleError(AppValueError):
"""Error to be raised if the on skill field of the ability cannot be converted to skill condition."""

def __init__(self, ability_id: int, on_skill: int):
super().__init__(f"Unable to convert ability on skill condition to skill condition "
f"(ability ID: {ability_id} / on skill: {on_skill}")


class BulletMaxCountUnavailableError(AppValueError):
"""Error to be raised if the bullet max count cannot be obtained solely from its action component."""
2 changes: 2 additions & 0 deletions dlparse/model/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""Various custom data models."""
from .ability import AbilityData
from .buff_boost import BuffCountBoostData, BuffZoneBoostData
from .effect_ability import AbilityVariantEffectUnit
from .effect_action_cond import ActionConditionEffectUnit, AfflictionEffectUnit
from .effect_base import EffectUnitBase
from .hit_base import HitData
from .hit_buff import BuffingHitData
from .hit_dmg import DamagingHitData
Expand Down
44 changes: 40 additions & 4 deletions dlparse/model/ability.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,51 @@
"""Models for ability data."""
from dataclasses import dataclass
from typing import TYPE_CHECKING
from dataclasses import InitVar, dataclass, field
from typing import TYPE_CHECKING, TypeVar

from .effect_base import EffectUnitBase

if TYPE_CHECKING:
from dlparse.mono.asset import AbilityEntry
from dlparse.mono.asset import AbilityEntry, AbilityLimitGroupAsset

__all__ = ("AbilityData",)

T = TypeVar("T", bound=EffectUnitBase)


@dataclass
class AbilityData:
"""A transformed ability data."""

ability_data: list["AbilityEntry"]
asset_ability_limit: InitVar["AbilityLimitGroupAsset"] # Used for recording the max possible value

ability_data: dict[int, "AbilityEntry"]

_effect_units: set[T] = field(init=False)

def _init_units(self, asset_ability_limit: "AbilityLimitGroupAsset"):
self._effect_units = set()
for ability_entry in self.ability_data.values():
self._effect_units.update(ability_entry.to_effect_units(asset_ability_limit))

def __post_init__(self, asset_ability_limit: "AbilityLimitGroupAsset"):
self._init_units(asset_ability_limit)

@property
def has_unknown_condition(self):
"""Check if the ability data contains any unknown condition."""
return any(ability_entry.is_unknown_condition for ability_entry in self.ability_data.values())

@property
def has_unknown_variants(self):
"""Check if the ability data contains any unknown variants."""
return any(ability_entry.has_unknown_elements for ability_entry in self.ability_data.values())

@property
def has_unknown_elements(self) -> bool:
"""Check if the ability data contains any unknown variants or condition."""
return self.has_unknown_condition or self.has_unknown_variants

@property
def effect_units(self) -> set[T]:
"""Get all effect units of the ability."""
return self._effect_units
19 changes: 8 additions & 11 deletions dlparse/model/buff_boost.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
"""Buff boosting data model."""
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import TYPE_CHECKING

from dlparse.enums import SkillConditionComposite
from dlparse.mono.asset import ActionConditionAsset, BuffCountAsset, HitAttrEntry
from .hit_dmg import DamagingHitData

if TYPE_CHECKING:
from .hit_dmg import DamagingHitData
from dlparse.mono.asset import ActionConditionAsset, BuffCountAsset, HitAttrEntry

__all__ = ("BuffCountBoostData", "BuffZoneBoostData")

Expand All @@ -17,12 +20,6 @@ class BuffBoostData(ABC):
def __hash__(self):
raise NotImplementedError()

def __eq__(self, other):
if not isinstance(other, self.__class__):
return False

return hash(self) == hash(other)


@dataclass(eq=False)
class BuffCountBoostData(BuffBoostData):
Expand All @@ -45,8 +42,8 @@ class BuffCountBoostData(BuffBoostData):

@staticmethod
def from_hit_attr(
hit_attr: HitAttrEntry, condition_comp: SkillConditionComposite,
asset_action_cond: ActionConditionAsset, asset_buff_count: BuffCountAsset
hit_attr: "HitAttrEntry", condition_comp: SkillConditionComposite,
asset_action_cond: "ActionConditionAsset", asset_buff_count: "BuffCountAsset"
) -> "BuffCountBoostData":
"""Get the buff count boost data of ``hit_attr``."""
if not hit_attr.boost_by_buff_count:
Expand Down Expand Up @@ -100,7 +97,7 @@ def __hash__(self):
return hash((self.rate_by_self * 1E5, self.rate_by_ally * 1E5,))

@staticmethod
def from_hit_units(hit_data_list: list[DamagingHitData]) -> "BuffZoneBoostData":
def from_hit_units(hit_data_list: list["DamagingHitData"]) -> "BuffZoneBoostData":
"""``hit_data_list`` to a buff zone boosting data."""
rate_by_self = sum(hit_data.mod_on_self_buff_zone for hit_data in hit_data_list)
rate_by_ally = sum(hit_data.mod_on_ally_buff_zone for hit_data in hit_data_list)
Expand Down
Loading

0 comments on commit 754b562

Please sign in to comment.