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

Commit

Permalink
ADD - Enemy data loading assets (#12)
Browse files Browse the repository at this point in the history
Signed-off-by: RaenonX <[email protected]>
  • Loading branch information
RaenonX committed Apr 17, 2021
1 parent 2ac2e14 commit bf23878
Show file tree
Hide file tree
Showing 5 changed files with 356 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .data/media
Submodule media updated 6250 files
90 changes: 90 additions & 0 deletions dlparse/mono/asset/master/dungeon_planner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""Classes for handling the dungeon planner asset."""
from dataclasses import dataclass
from typing import Optional, TextIO, Union

from dlparse.mono.asset.base import MasterAssetBase, MasterEntryBase, MasterParserBase

__all__ = ("DungeonPlannerEntry", "DungeonPlannerAsset")

DUNGEON_VARIATION_COUNT_MAX: int = 5


@dataclass
class DungeonPlannerEntry(MasterEntryBase):
"""Single entry of a dungeon planner data."""

bgm_id: str

enemy_param_ids: list[list[int]] # Index = ``variation_idx`` of the quest data

@staticmethod
def get_enemy_param_ids(data: dict[str, Union[str, int]]) -> list[list[int]]:
"""
Get the enemy parameter IDs.
The index of the return corresponds to ``variation_idx`` field of the quest data.
"""
param_ids = []
param_fields = [
[
"_BossCameraEnemy0Param",
"_BossCameraEnemy1Param",
"_BossCameraEnemy2Param",
"_BossCameraEnemy3Param",
"_BossCameraEnemy4Param",
"_BossCameraEnemy5Param",
"_BossCameraEnemy6Param",
"_BossCameraEnemy7Param",
"_BossCameraEnemy8Param",
"_BossCameraEnemy9Param"
],
["_BossCameraEnemy0ParamHard"],
["_BossCameraEnemy0ParamVeryhard"],
["_BossCameraEnemy0ParamExtreme"],
["_BossCameraEnemy0ParamHell"],
]

for variation_fields in param_fields:
param_ids_variation = []

for variation_field in variation_fields:
# REMOVE: not with walrus https://github.com/PyCQA/pylint/issues/3249
# pylint: disable=superfluous-parens
if not (enemy_param_id := data[variation_field]):
continue

param_ids_variation.append(enemy_param_id)

param_ids.append(param_ids_variation)

return param_ids

@staticmethod
def parse_raw(data: dict[str, Union[str, int]]) -> "DungeonPlannerEntry":
return DungeonPlannerEntry(
id=data["_Area"],
bgm_id=data["_Bgm"],
enemy_param_ids=DungeonPlannerEntry.get_enemy_param_ids(data),
)


class DungeonPlannerAsset(MasterAssetBase[DungeonPlannerEntry]):
"""Quest data asset class."""

asset_file_name = "DungeonAreaPlannerData.json"

def __init__(
self, file_location: Optional[str] = None, /,
asset_dir: Optional[str] = None, file_like: Optional[TextIO] = None
):
super().__init__(DungeonPlannerParser, file_location, asset_dir=asset_dir, file_like=file_like)


class DungeonPlannerParser(MasterParserBase[DungeonPlannerEntry]):
"""Class to parse the quest data file."""

@classmethod
def parse_file(cls, file_like: TextIO) -> dict[int, DungeonPlannerEntry]:
entries = cls.get_entries_dict(file_like)

return {key: DungeonPlannerEntry.parse_raw(value) for key, value in entries.items()}
58 changes: 58 additions & 0 deletions dlparse/mono/asset/master/enemy_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""
Classes for handling the enemy data asset.
Note that enemy data and enemy param are different things.
"""
from dataclasses import dataclass
from typing import Optional, TextIO, Union

from dlparse.enums import Element
from dlparse.mono.asset.base import MasterAssetBase, MasterEntryBase, MasterParserBase

__all__ = ("EnemyDataEntry", "EnemyDataAsset")


@dataclass
class EnemyDataEntry(MasterEntryBase):
"""Single entry of an enemy data."""

element: Element

od_atk_rate: float
od_def_rate: float

bk_duration_sec: int
bk_def_rate: float

@staticmethod
def parse_raw(data: dict[str, Union[str, int]]) -> "EnemyDataEntry":
return EnemyDataEntry(
id=data["_Id"],
element=Element(data["_ElementalType"]),
od_atk_rate=data["_ObAtkRate"],
od_def_rate=data["_ObDefRate"],
bk_duration_sec=data["_BreakDuration"],
bk_def_rate=data["_BreakDefRate"],
)


class EnemyDataAsset(MasterAssetBase[EnemyDataEntry]):
"""Enemy data asset class."""

asset_file_name = "EnemyParam.json"

def __init__(
self, file_location: Optional[str] = None, /,
asset_dir: Optional[str] = None, file_like: Optional[TextIO] = None
):
super().__init__(EnemyDataParser, file_location, asset_dir=asset_dir, file_like=file_like)


class EnemyDataParser(MasterParserBase[EnemyDataEntry]):
"""Class to parse the enemy data file."""

@classmethod
def parse_file(cls, file_like: TextIO) -> dict[int, EnemyDataEntry]:
entries = cls.get_entries_dict(file_like)

return {key: EnemyDataEntry.parse_raw(value) for key, value in entries.items()}
144 changes: 144 additions & 0 deletions dlparse/mono/asset/master/enemy_param.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"""
Classes for handling the quest data asset.
Note that enemy data and enemy param are different things.
"""
from dataclasses import dataclass
from typing import Optional, TextIO, Union

from dlparse.enums import Element, Status
from dlparse.mono.asset.base import MasterAssetBase, MasterEntryBase, MasterParserBase

__all__ = ("EnemyParamEntry", "EnemyParamAsset")


@dataclass
class EnemyParamEntry(MasterEntryBase):
"""Single entry of an enemy param data."""

enemy_data_id: int

ai_name: str
action_set_id: int
action_set_id_on_elem: dict[Element, int]

ability_ids: list[int]
ability_berserk_id: int

hp: int
atk: int
defense: int

base_od: int
base_bk: int

affliction_resistance_pct: dict[Status, int]

form_2nd_param_id: int

child_1_param_id: int
child_1_count: int
child_2_param_id: int
child_2_count: int
child_3_param_id: int
child_3_count: int

part_1_param_id: int
part_2_param_id: int
part_3_param_id: int
part_4_param_id: int

appear_voice_id: str

@staticmethod
def get_affliction_resistance_pct(data: dict[str, Union[str, int]]) -> dict[Status, int]:
"""
Get a dictionary which key is the corresponding abnormal status; value is its corresponding resistance.
Note that the value returning is percentage (%). A value of 100 means absolute resist.
"""
ret = {
Status.POISON: data["_RegistAbnormalRate01"],
Status.BURN: data["_RegistAbnormalRate02"],
Status.FREEZE: data["_RegistAbnormalRate03"],
Status.PARALYZE: data["_RegistAbnormalRate04"],
Status.BLIND: data["_RegistAbnormalRate05"],
Status.STUN: data["_RegistAbnormalRate06"],
Status.CURSE: data["_RegistAbnormalRate07"],
Status.BOG: data["_RegistAbnormalRate08"],
Status.SLEEP: data["_RegistAbnormalRate09"],
Status.FROSTBITE: data["_RegistAbnormalRate10"],
Status.FLASHBURN: data["_RegistAbnormalRate11"],
Status.STORMLASH: data["_RegistAbnormalRate12"],
Status.SHADOWBLIGHT: data["_RegistAbnormalRate13"],
Status.SCORCHREND: data["_RegistAbnormalRate14"],
}

return ret

@staticmethod
def parse_raw(data: dict[str, Union[str, int]]) -> "EnemyParamEntry":
action_set_id_elem = {
Element.FLAME: data["_ActionSetFire"],
Element.WATER: data["_ActionSetWater"],
Element.WIND: data["_ActionSetWind"],
Element.LIGHT: data["_ActionSetLight"],
Element.SHADOW: data["_ActionSetDark"],
}

ability_ids = [
data["_Ability01"],
data["_Ability02"],
data["_Ability03"],
data["_Ability04"]
]

return EnemyParamEntry(
id=data["_Id"],
enemy_data_id=data["_DataId"],
ai_name=data["_Ai"],
action_set_id=data["_ActionSet"],
action_set_id_on_elem=action_set_id_elem,
ability_ids=ability_ids,
ability_berserk_id=data["_BerserkAbility"],
hp=data["_HP"],
atk=data["_Atk"],
defense=data["_Def"],
base_od=data["_BaseOD"],
base_bk=data["_BaseBreak"],
affliction_resistance_pct=EnemyParamEntry.get_affliction_resistance_pct(data),
form_2nd_param_id=data["_Form2nd"],
child_1_param_id=data["_Child01Param"],
child_1_count=data["_Child01Num"],
child_2_param_id=data["_Child02Param"],
child_2_count=data["_Child02Num"],
child_3_param_id=data["_Child03Param"],
child_3_count=data["_Child03Num"],
part_1_param_id=data["_PartsA"],
part_2_param_id=data["_PartsB"],
part_3_param_id=data["_PartsC"],
part_4_param_id=data["_PartsD"],
appear_voice_id=data["_BossAppearVoiceId"],
)


class EnemyParamAsset(MasterAssetBase[EnemyParamEntry]):
"""Enemy param asset class."""

asset_file_name = "EnemyParam.json"

def __init__(
self, file_location: Optional[str] = None, /,
asset_dir: Optional[str] = None, file_like: Optional[TextIO] = None
):
super().__init__(EnemyParamParser, file_location, asset_dir=asset_dir, file_like=file_like)


class EnemyParamParser(MasterParserBase[EnemyParamEntry]):
"""Class to parse the enemy param data file."""

@classmethod
def parse_file(cls, file_like: TextIO) -> dict[int, EnemyParamEntry]:
entries = cls.get_entries_dict(file_like)

return {key: EnemyParamEntry.parse_raw(value) for key, value in entries.items()}
63 changes: 63 additions & 0 deletions dlparse/mono/asset/master/quest_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Classes for handling the quest data asset."""
from dataclasses import dataclass
from typing import Optional, TextIO, Union

from dlparse.enums import Element
from dlparse.mono.asset.base import MasterAssetBase, MasterEntryBase, MasterParserBase

__all__ = ("QuestDataEntry", "QuestDataAsset")


@dataclass
class QuestDataEntry(MasterEntryBase):
"""Single entry of a quest data."""

name_view_label: str

element_1: Element
element_1_limit: Element
element_2: Element
element_2_limit: Element

max_time_sec: int
max_revive: int

variation_idx: int
area_1_name: str

@staticmethod
def parse_raw(data: dict[str, Union[str, int]]) -> "QuestDataEntry":
return QuestDataEntry(
id=data["_Id"],
name_view_label=data["_QuestViewName"],
element_1=Element(data["_Elemental"]),
element_1_limit=Element(data["_LimitedElementalType"]),
element_2=Element(data["_Elemental2"]),
element_2_limit=Element(data["_LimitedElementalType2"]),
max_time_sec=data["_FailedTermsTimeElapsed"],
max_revive=data["_RebornLimit"],
variation_idx=data["_VariationType"],
area_1_name=data["_AreaName01"]
)


class QuestDataAsset(MasterAssetBase[QuestDataEntry]):
"""Quest data asset class."""

asset_file_name = "QuestData.json"

def __init__(
self, file_location: Optional[str] = None, /,
asset_dir: Optional[str] = None, file_like: Optional[TextIO] = None
):
super().__init__(QuestDataParser, file_location, asset_dir=asset_dir, file_like=file_like)


class QuestDataParser(MasterParserBase[QuestDataEntry]):
"""Class to parse the quest data file."""

@classmethod
def parse_file(cls, file_like: TextIO) -> dict[int, QuestDataEntry]:
entries = cls.get_entries_dict(file_like)

return {key: QuestDataEntry.parse_raw(value) for key, value in entries.items()}

0 comments on commit bf23878

Please sign in to comment.