def __post_init__(self, asset_manager: "AssetManager"): # Quest basic properties self.quest_mode = self.quest_data.quest_mode self.elements = [ Element(elem) for elem in (self.quest_data.element_1, self.quest_data.element_2) if elem.is_valid ] self.elements_limit = [ Element(elem) for elem in (self.quest_data.element_1_limit, self.quest_data.element_2_limit) if elem.is_valid ] self.max_clear_time_sec = self.quest_data.max_time_sec self.max_revive_allowed = self.quest_data.max_revive # Quest dungeon area self.area_1_name = self.quest_data.area_1_name dungeon_plan = asset_manager.asset_dungeon_planner.get_data_by_id( self.area_1_name) # --- ``variation_idx`` is 1-based index self.spawn_enemy_param_ids = dungeon_plan.enemy_param_ids[ self.quest_data.variation_idx - 1] if not self.spawn_enemy_param_ids: # In Legend Ciella quest, variation type is 4 while the only enemy parameter related is located at 0 # This will attempt to take the data at variation 0 self.spawn_enemy_param_ids = dungeon_plan.enemy_param_ids[0]
def parse_raw(data: dict[str, Union[str, int]]) -> "QuestDataEntry": return QuestDataEntry( id=data["_Id"], quest_mode=QuestMode(data["_QuestPlayModeType"]), 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"])
def parse_raw(cls, data: dict[str, Union[str, int]]) -> "DragonDataEntry": return DragonDataEntry( id=data["_Id"], emblem_id=data["_EmblemId"], element=Element(data["_ElementalType"]), rarity=data["_Rarity"], name_label=data["_Name"], name_label_2=data["_SecondName"], base_id=data["_BaseId"], variation_id=data["_VariationId"], skill_1_id=data["_Skill1"], skill_2_id=data["_Skill2"], ability_id_1_lv1=data["_Abilities11"], ability_id_1_lv2=data["_Abilities12"], ability_id_1_lv3=data["_Abilities13"], ability_id_1_lv4=data["_Abilities14"], ability_id_1_lv5=data["_Abilities15"], ability_id_2_lv1=data["_Abilities21"], ability_id_2_lv2=data["_Abilities22"], ability_id_2_lv3=data["_Abilities23"], ability_id_2_lv4=data["_Abilities24"], ability_id_2_lv5=data["_Abilities25"], normal_attack_action_id=data["_DefaultSkill"], cv_en_label=data["_CvInfoEn"], cv_jp_label=data["_CvInfo"], release_date=cls.parse_datetime(data["_ReleaseStartDate"]), is_playable=bool(data["_IsPlayable"]), ss_skill_id=0, ss_skill_num=SkillNumber.NA, ss_skill_cost=0, unique_dragon_id=0, )
def _from_elem_resist_up( self, asset_manager: "AssetManager", payload: AbilityVariantEffectPayload ) -> set[AbilityVariantEffectUnit]: return self._direct_buff_unit( Element(self.variant.id_a).to_elem_res_up_passive(), asset_manager, payload)
def parse_raw(data: dict[str, Union[str, int]]) -> "EnemyDataEntry": return EnemyDataEntry( id=data["_Id"], initial_element=Element(data["_ElementalType"]), od_atk_rate=data["_ObAtkRate"], od_def_rate=data["_ObDefRate"], bk_duration_sec=data["_BreakDuration"], bk_def_rate=data["_BreakDefRate"], )
def conditions(self) -> list[Condition]: """ Get the conditions for this action condition to be effective. If no conditions are required, return an empty list. If any of the conditions returned matches, then the action condition is considered effective. """ if not self.target_limited_by_element: # Not limited to certain element, no condition return [] return [ ConditionCategories.target_element.convert_reversed(element) for element in Element.from_flag(self.elemental_target) ]
def parse_raw(data: dict[str, Union[str, int]]) -> "AbilityEntry": return AbilityEntry( id=data["_Id"], name_label=data["_Name"], description_label=data["_Details"], ability_icon_name=data["_AbilityIconName"], condition=AbilityConditionEntry( unit_type=UnitType(data["_UnitType"]), elemental_restriction=Element(data["_ElementalType"]), weapon_restriction=Weapon(data["_WeaponType"]), condition_code=data["_ConditionType"], val_1=data["_ConditionValue"], val_2=data["_ConditionValue2"], probability=data["_Probability"], cooldown_sec=data["_CoolTime"], max_occurrences=data["_OccurenceNum"], target_action=AbilityTargetAction(data["_TargetAction"]), ), on_skill=data["_OnSkill"], variant_1=AbilityVariantEntry( type_id=data["_AbilityType1"], id_a=data["_VariousId1a"], id_b=data["_VariousId1b"], id_c=data["_VariousId1c"], id_str=data["_VariousId1str"], limited_group_id=data["_AbilityLimitedGroupId1"], target_action_id=data["_TargetAction1"], up_value=data["_AbilityType1UpValue"]), variant_2=AbilityVariantEntry( type_id=data["_AbilityType2"], id_a=data["_VariousId2a"], id_b=data["_VariousId2b"], id_c=data["_VariousId2c"], id_str=data["_VariousId2str"], limited_group_id=data["_AbilityLimitedGroupId2"], target_action_id=data["_TargetAction2"], up_value=data["_AbilityType2UpValue"]), variant_3=AbilityVariantEntry( type_id=data["_AbilityType3"], id_a=data["_VariousId3a"], id_b=data["_VariousId3b"], id_c=data["_VariousId3c"], id_str=data["_VariousId3str"], limited_group_id=data["_AbilityLimitedGroupId3"], target_action_id=data["_TargetAction3"], up_value=data["_AbilityType3UpValue"]))
def _init_elemental_buffs(self, action_condition_asset: ActionConditionAsset): self.buffs_elemental: list[dict[Element, set[HitActionConditionEffectUnit]]] = [] for hit_data_lv in self.skill_hit_data.hit_data: buff_lv: dict[Element, set[HitActionConditionEffectUnit]] = { elem: set() for elem in Element.get_all_valid_elements() } for hit_data in hit_data_lv: if not hit_data.hit_attr.has_action_condition: continue # No action condition assigned action_condition = action_condition_asset.get_data_by_id(hit_data.action_condition_id) if not action_condition.target_limited_by_element: continue # Action condition not limited by element for elem in action_condition.elemental_target.elements: buff_lv[elem].update(hit_data.to_buffing_units(action_condition_asset)) self.buffs_elemental.append(buff_lv)
def export(self): """Export the parsed assets.""" # Enums self._export_enums( { "afflictions": cond_afflictions, "elements": cond_elements }, "conditions") self._export_enums_ex() self._export_enums({"weapon": Weapon.get_all_translatable_members()}, "weaponType") self._export_enums( {"elemental": Element.get_all_translatable_members()}, "elements") self._export_enums( {"unit": BuffValueUnit.get_all_translatable_members()}, "buffParam") self._export_enums({"status": Status.get_all_translatable_members()}, "status") self._export_enums( {"cancel": SkillCancelAction.get_all_translatable_members()}, "skill") self._export_enums_condition("allCondition") # Skill self._export_atk_skill() self._export_skill_identifiers("identifiers") # Abilties self._export_ex_abilities() # Info self._export_unit_info() self._export_normal_attack() # Story self._export_story() # Misc self._export_elem_bonus()
class SkillDataBase(Generic[HT, ET], ABC): """Base class for a single skill data.""" asset_manager: "AssetManager" skill_hit_data: "SkillHitData" skill_data: SkillDataEntry = field(init=False) skill_id: int = field(init=False) hit_data_mtx: list[list[HT]] = field(init=False) sp_gradual_fill_pct: list[float] = field(init=False) possible_conditions: set[ConditionComposite] = field( init=False, default_factory=ConditionComposite) max_level: int = field(init=False) @final def _init_possible_conditions_pre_conditions( self) -> Optional[set[tuple[Condition, ...]]]: pre_conditions: set[tuple[Condition, ...]] = { tuple(hit_data.pre_condition_comp) for hit_data_lv in self.hit_data_mtx for hit_data in hit_data_lv if hit_data.pre_condition_comp } if pre_conditions: if any( any(pre_condition in ConditionCategories.skill_addl_inputs for pre_condition in pre_condition_tuple) for pre_condition_tuple in pre_conditions): # Pre-condition has additional inputs condition, # no-additional-input (additional input = 0) condition is possible # Appears in Lathna S1 (`105505021`), Ramona S1 (`104501011`) pre_conditions.add((Condition.ADDL_INPUT_0, )) if any( any(pre_condition in ConditionCategories.skill_action_cancel for pre_condition in pre_condition_tuple) for pre_condition_tuple in pre_conditions): # Pre-condition has action cancelling condition, # no cancelling (no condition) is possible # Appears in handle Formal Joachim S1 (`109503011`) pre_conditions.add(()) if any( any(pre_condition in ConditionCategories.trigger for pre_condition in pre_condition_tuple) for pre_condition_tuple in pre_conditions): # Pre-condition has trigger, # Triggering conditions are not always happening pre_conditions.add(()) if any( any(pre_condition in ConditionCategories.skill_action_misc_var for pre_condition in pre_condition_tuple) for pre_condition_tuple in pre_conditions): # Skill has some variants. However, the skill can be used without triggering the variants. # Appears in Nobunaga S1 (`102501031`), Yoshitsune S1 (`109502021`) pre_conditions.add(()) if any(Condition.SELF_PASSIVE_ENHANCED in pre_condition_tuple for pre_condition_tuple in pre_conditions): # Pre-condition has passive enhancement, this is not always happening pre_conditions.add(()) return pre_conditions return None @final def _init_possible_conditions_base_elems(self): cond_elems: list[set[tuple[Condition, ...]]] = [] # Get all possible pre-conditions as a condition element if pre_conditions := self._init_possible_conditions_pre_conditions(): cond_elems.append(pre_conditions) # Get the elemental restriction from the action conditions if any action_conds_elem_flag: set[ElementFlag] = set() for hit_data_lv in self.hit_data_mtx: for hit_data in hit_data_lv: if not hit_data.action_condition_id: continue # No action condition action_conds_elem_flag.add( self.asset_manager.asset_action_cond.get_data_by_id( hit_data.action_condition_id).elemental_target) if action_conds_elem_flag: # Elemental action condition available # Convert discovered elemental flags to elements action_conds_elem: set[Element] = set() for elem_flag in action_conds_elem_flag: action_conds_elem.update(Element.from_flag(elem_flag)) # Convert elements to conditions and add it # - Dummy condition tuple for pre-condition of none, meaning other elements cond_elems.append({( ConditionCategories.target_element.convert_reversed(elem), ) for elem in action_conds_elem} | {()}) return cond_elems
def test_export_element_enums(asset_manager: AssetManager): export_enum(asset_manager, "element", Element.get_all_valid_elements()) export_enum(asset_manager, "element", Element.get_all_translatable_members())
def parse_raw(cls, data: dict[str, Union[str, int, float]]) -> "CharaDataEntry": return CharaDataEntry( id=data["_Id"], name_label=data["_Name"], name_label_2=data["_SecondName"], emblem_id=data["_EmblemId"], weapon=Weapon(data["_WeaponType"]), rarity=data["_Rarity"], max_limit_break_count=data["_MaxLimitBreakCount"], element=Element(data["_ElementalType"]), chara_type_id=data["_CharaType"], base_id=data["_BaseId"], variation_id=data["_VariationId"], max_hp=data["_MaxHp"], max_hp_1=data["_AddMaxHp1"], plus_hp_0=data["_PlusHp0"], plus_hp_1=data["_PlusHp1"], plus_hp_2=data["_PlusHp2"], plus_hp_3=data["_PlusHp3"], plus_hp_4=data["_PlusHp4"], plus_hp_5=data["_PlusHp5"], mc_full_bonus_hp=data["_McFullBonusHp5"], max_atk=data["_MaxAtk"], max_atk_1=data["_AddMaxAtk1"], plus_atk_0=data["_PlusAtk0"], plus_atk_1=data["_PlusAtk1"], plus_atk_2=data["_PlusAtk2"], plus_atk_3=data["_PlusAtk3"], plus_atk_4=data["_PlusAtk4"], plus_atk_5=data["_PlusAtk5"], mc_full_bonus_atk=data["_McFullBonusAtk5"], def_coef=data["_DefCoef"], mode_change_type=ModeChangeType(data["_ModeChangeType"]), mode_1_id=data["_ModeId1"], mode_2_id=data["_ModeId2"], mode_3_id=data["_ModeId3"], mode_4_id=data["_ModeId4"], keep_mode_on_revive=bool(data["_KeepModeOnRevive"]), combo_original_id=data["_OriginCombo"], combo_mode_1_id=data["_Mode1Combo"], combo_mode_2_id=data["_Mode2Combo"], skill_1_id=data["_Skill1"], skill_2_id=data["_Skill2"], ability_1_lv_1_id=data["_Abilities11"], ability_1_lv_2_id=data["_Abilities12"], ability_1_lv_3_id=data["_Abilities13"], ability_1_lv_4_id=data["_Abilities14"], ability_2_lv_1_id=data["_Abilities21"], ability_2_lv_2_id=data["_Abilities22"], ability_2_lv_3_id=data["_Abilities23"], ability_2_lv_4_id=data["_Abilities24"], ability_3_lv_1_id=data["_Abilities31"], ability_3_lv_2_id=data["_Abilities32"], ability_3_lv_3_id=data["_Abilities33"], ability_3_lv_4_id=data["_Abilities34"], ex_1_id=data["_ExAbilityData1"], ex_2_id=data["_ExAbilityData2"], ex_3_id=data["_ExAbilityData3"], ex_4_id=data["_ExAbilityData4"], ex_5_id=data["_ExAbilityData5"], cex_1_id=data["_ExAbility2Data1"], cex_2_id=data["_ExAbility2Data2"], cex_3_id=data["_ExAbility2Data3"], cex_4_id=data["_ExAbility2Data4"], cex_5_id=data["_ExAbility2Data5"], fs_type_id=data["_ChargeType"], fs_count_max=data["_MaxChargeLv"], ss_cost_max_self=data["_HoldEditSkillCost"], ss_skill_id=data["_EditSkillId"], ss_skill_num=SkillNumber.s1_s2_only(data["_EditSkillLevelNum"]), ss_skill_cost=data["_EditSkillCost"], ss_skill_relation_id=data["_EditSkillRelationId"], ss_release_item_id=data["_EditReleaseEntityId1"], ss_release_item_quantity=data["_EditReleaseEntityQuantity1"], win_face_eye_id=data["_WinFaceEyeMotion"], win_face_mouth_id=data["_WinFaceEyeMotion"], unique_weapon_id=data["_UniqueWeaponId"], unique_dragon_id=data["_UniqueDragonId"], unique_dragon_inherit_skill_lv=bool( data["_IsConvertDragonSkillLevel"]), is_dragon_drive=bool(data["_WinFaceMouthMotion"]), # ????? is_playable=bool(data["_IsPlayable"]), max_friendship_point=data["_MaxFriendshipPoint"], grow_material_start=cls.parse_datetime( data["_GrowMaterialOnlyStartDate"]), grow_material_end=cls.parse_datetime( data["_GrowMaterialOnlyEndDate"]), grow_material_id=data["_GrowMaterialId"], cv_en_label=data["_CvInfoEn"], cv_jp_label=data["_CvInfo"], release_date=cls.parse_datetime(data["_ReleaseStartDate"]))