Exemple #1
0
def update_decorations(mhdata, item_data: ItemCollection):
    print("Updating decorations")

    data = DecorationCollection(item_data)
    skill_text_handler = SkillTextHandler()

    # write artifact file (used to debug)
    def create_deco_artifact(d):
        return {'name': d.name['en'], 'slot': d.size, 'rarity': d.rarity}

    artifacts.write_dicts_artifact(
        "decorations_all.csv", list(map(create_deco_artifact,
                                        data.decorations)))

    for entry in mhdata.decoration_map.values():
        deco_name = entry['name_en']
        try:
            deco = data.by_name(entry['name_en'])
        except KeyError:
            print(f"Could not find decoration {deco_name} in the game files")
            continue

        entry['name'] = deco.name
        entry['rarity'] = deco.rarity
        for i in range(2):
            skill_name = None
            skill_pts = None
            if i < len(deco.skills):
                (skill_id, skill_pts) = deco.skills[i]
                skill_name = skill_text_handler.get_skilltree_name(
                    skill_id)['en']
            entry[f'skill{i+1}_name'] = skill_name
            entry[f'skill{i+1}_level'] = skill_pts

    writer = create_writer()

    writer.save_base_map_csv(
        "decorations/decoration_base.csv",
        mhdata.decoration_map,
        schema=schema.DecorationBaseSchema(),
        translation_filename="decorations/decoration_base_translations.csv")

    print("Decoration files updated\n")
Exemple #2
0
def translate_skills(mhdata):
    print("Translating skills")

    skilltext = SkillTextHandler()
    for skill in mhdata.skill_map.values():
        skill_name = skill['name']['en']
        try:
            (new_name, new_description) = skilltext.get_skilltree_translation(skill_name)
            skill['name'] = new_name
            skill['description'] = new_description
        except KeyError:
            print(f"Could not find skill {skill_name} in the game files")
            continue

        for level in skill['levels']:
            current_description = level['description']['en']
            try:
                description = skilltext.get_skill_description_translation(current_description)
                level['description'] = description
            except KeyError:
                print(f"Failed to find description translations for skill {skill_name} level {level['level']}")

    writer = create_writer()

    writer.save_base_map_csv(
        "skills/skill_base.csv",
        mhdata.skill_map,
        schema=schema.SkillBaseSchema(),
        translation_filename="skills/skill_base_translations.csv",
        translation_extra=['description']
    )

    writer.save_data_csv(
        "skills/skill_levels.csv",
        mhdata.skill_map,
        key='levels',
        schema=schema.SkillLevelSchema()
    )

    print("Skill files updated\n")
Exemple #3
0
def update_armor(mhdata, item_updater: ItemUpdater):
    "Populates and updates armor information using the armorset_base as a source of truth"

    armor_series = load_armor_series()

    # Get number of times armor can be upgraded by rarity level.
    # The first is max level pre-augment, the second is max post-augment
    # Thanks to the MHWorld Modders for the above info
    rarity_upgrades = {}
    for entry in load_schema(arm_up.ArmUp,
                             "common/equip/arm_upgrade.arm_up").entries:
        rarity_upgrades[entry.index + 1] = (entry.unk10 - 1, entry.unk11 - 1)

    print("Binary armor data loaded")

    print("Writing list of armorset names (in order) to artifacts")
    artifacts.write_names_artifact(
        'setnames.txt', [s.name['en'] for s in armor_series.values()])

    # Will store results. Language lookup and validation will be in english
    new_armorset_map = DataMap(languages="en",
                               start_id=mhdata.armorset_map.max_id + 1)
    new_armor_map = DataMap(languages="en",
                            start_id=mhdata.armor_map.max_id + 1)
    new_armorset_bonus_map = DataMap(languages="en")

    # Temporary storage for later processes
    all_set_skill_ids = OrderedSet()
    skill_text_handler = SkillTextHandler()
    armor_data_by_name = {}

    print(
        "Updating set data, keyed by the existing names in armorset_base.csv")
    for armorset_entry in mhdata.armorset_map.values():
        armorseries_data = armor_series.get(armorset_entry.name('en'))
        if not armorseries_data:
            print(
                f"Armor series {armorset_entry.name('en')} doesn't exist in binary, skipping"
            )
            new_armorset_map.insert(armorset_entry)
            continue

        new_entry = {
            **armorset_entry, 'name': armorseries_data.name,
            'rank': armorseries_data.rank
        }

        first_armor = armorseries_data.armors[0].binary
        if first_armor.set_skill1_lvl > 0:
            skill_id = first_armor.set_skill1
            all_set_skill_ids.add(skill_id)
            new_entry['bonus'] = skill_text_handler.get_skilltree_name(
                skill_id)['en']

        for part in cfg.armor_parts:
            armor = armorseries_data.get_part(part)
            if armor:
                armor_data_by_name[armor.name['en']] = armor
                new_entry[part] = armor.name['en']
            else:
                new_entry[part] = None

        new_armorset_map.insert(new_entry)

    print("Armorset entries updated")

    print("Updating armor")
    for armorset_entry in new_armorset_map.values():
        # Handle armor pieces
        for part, armor_name in datafn.iter_armorset_pieces(armorset_entry):
            existing_armor = mhdata.armor_map.entry_of('en', armor_name)
            armor_data = armor_data_by_name.get(armor_name, None)

            if not armor_data:
                if not existing_armor:
                    print(
                        f"Error: Invalid entry {armor_name}, does not exist in current DB nor is it in armor data"
                    )
                    continue
                print(
                    f"Failed to find binary armor data for {armor_name}, maintaining existing data"
                )
                new_armor_map.insert(existing_armor)
                continue

            armor_binary = armor_data.binary
            rarity = armor_binary.rarity + 1

            # Initial new armor data
            new_data = {
                'name':
                armor_data.name,
                'rarity':
                rarity,
                'type':
                part,
                'gender':
                gender_list[armor_binary.gender],
                'slot_1':
                armor_binary.gem_slot1_lvl,
                'slot_2':
                armor_binary.gem_slot2_lvl,
                'slot_3':
                armor_binary.gem_slot3_lvl,
                'defense_base':
                armor_binary.defense,
                'defense_max':
                armor_binary.defense + rarity_upgrades[rarity][0] * 2,
                'defense_augment_max':
                armor_binary.defense + rarity_upgrades[rarity][1] * 2,
                'defense_fire':
                armor_binary.fire_res,
                'defense_water':
                armor_binary.water_res,
                'defense_thunder':
                armor_binary.thunder_res,
                'defense_ice':
                armor_binary.ice_res,
                'defense_dragon':
                armor_binary.dragon_res,
                'skills': {},
                'craft': {}
            }

            if existing_armor:
                new_data['id'] = existing_armor.id

            # Add skills to new armor data
            for i in range(1, 2 + 1):
                skill_lvl = getattr(armor_binary, f"skill{i}_lvl")
                if skill_lvl != 0:
                    skill_id = getattr(armor_binary, f"skill{i}")
                    name_en = skill_text_handler.get_skilltree_name(
                        skill_id)['en']
                    new_data['skills'][f'skill{i}_name'] = name_en
                    new_data['skills'][f'skill{i}_pts'] = skill_lvl
                else:
                    new_data['skills'][f'skill{i}_name'] = None
                    new_data['skills'][f'skill{i}_pts'] = None

            # Add recipe to new armor data. Also tracks the encounter.
            new_data['craft'] = convert_recipe(item_updater, armor_data.recipe)

            # Add new data to new armor map
            new_armor_map.insert(new_data)

    # Process set skills. As we don't currently understand the set -> skill map, we only translate
    # We pull the already established set skill name from existing CSV
    for bonus_entry in mhdata.armorset_bonus_map.values():
        skilltree = skill_text_handler.get_skilltree(bonus_entry.name('en'))
        name_dict = skill_text_handler.get_skilltree_name(skilltree.index)
        new_armorset_bonus_map.insert({**bonus_entry, 'name': name_dict})

    # Write new data
    writer = create_writer()

    writer.save_base_map_csv(
        "armors/armorset_base.csv",
        new_armorset_map,
        schema=schema.ArmorSetSchema(),
        translation_filename="armors/armorset_base_translations.csv")

    writer.save_base_map_csv(
        "armors/armor_base.csv",
        new_armor_map,
        schema=schema.ArmorBaseSchema(),
        translation_filename="armors/armor_base_translations.csv")

    writer.save_data_csv("armors/armor_skills_ext.csv",
                         new_armor_map,
                         key="skills")

    writer.save_data_csv("armors/armor_craft_ext.csv",
                         new_armor_map,
                         key="craft")

    writer.save_base_map_csv(
        "armors/armorset_bonus_base.csv",
        new_armorset_bonus_map,
        schema=schema.ArmorSetBonus(),
        translation_filename="armors/armorset_bonus_base_translations.csv")

    print("Armor files updated\n")
Exemple #4
0
def update_weapons(mhdata, item_updater: ItemUpdater):
    skill_text_handler = SkillTextHandler()

    print("Beginning load of binary weapon data")
    weapon_loader = WeaponDataLoader()
    notes_data = load_schema(wep_wsl.WepWsl, "common/equip/wep_whistle.wep_wsl")
    sharpness_reader = SharpnessDataReader()
    ammo_reader = WeaponAmmoLoader()
    coating_data = load_schema(bbtbl.Bbtbl, "common/equip/bottle_table.bbtbl")
    print("Loaded weapon binary data")

    def bind_weapon_blade_ext(weapon_type: str, existing_entry, weapon):
        binary: wp_dat.WpDatEntry = weapon.binary
        for key in ['kinsect_bonus', 'phial', 'phial_power', 'shelling', 'shelling_level', 'notes']:
            existing_entry[key] = None
        if weapon_type == cfg.CHARGE_BLADE:
            existing_entry['phial'] = cb_phials[binary.wep1_id]
        if weapon_type == cfg.SWITCH_AXE:
            try:
                (phial, power) = s_axe_phials[binary.wep1_id]
                existing_entry['phial'] = phial
                existing_entry['phial_power'] = power
            except:
                raise KeyError(f"Failed to load saxe phials for {weapon.name['en']} (SAXE ID: {binary.wep1_id})")
        if weapon_type == cfg.GUNLANCE:
            # first 5 are normals, second 5 are wide, third 5 are long
            if binary.wep1_id >= 15:
                value = binary.wep1_id - 15
                shelling = ['normal', 'wide', 'long'][value % 3]
                level = value // 3 + 6
            else:
                shelling = ['normal', 'wide', 'long'][binary.wep1_id // 5]
                level = (binary.wep1_id % 5) + 1
            existing_entry['shelling'] = shelling
            existing_entry['shelling_level'] = level
        if weapon_type == cfg.INSECT_GLAIVE:
            try:
                existing_entry['kinsect_bonus'] = glaive_boosts[binary.wep1_id]
            except:
                raise KeyError(f"Failed to load kinsect bonus for {weapon.name['en']} (BOOST ID: {binary.wep1_id})")
        if weapon_type == cfg.HUNTING_HORN:
            note_entry = notes_data[binary.wep1_id]
            notes = [note_entry.note1, note_entry.note2, note_entry.note3]
            notes = [str(note_colors[n]) for n in notes]
            existing_entry['notes'] = "".join(notes)

    # Load weapon tree binary data
    weapon_trees = {}
    for weapon_type in cfg.weapon_types:
        weapon_tree = weapon_loader.load_tree(weapon_type)
        print(f"Loaded {weapon_type} weapon tree binary data")
        weapon_trees[weapon_type] = weapon_tree

    # Load Kulve Augment Data
    kulve_augments = weapon_loader.load_kulve_augments()
    artifacts.write_dicts_artifact("kulve_augments.csv", kulve_augments.flattened())

    # Write artifact lines
    print("Writing artifact files for weapons (use it to add new weapons)")
    write_weapon_artifacts(mhdata, weapon_trees, ammo_reader)

    # Store new weapon entries
    new_weapon_map = DataMap(languages=["en"], start_id=mhdata.weapon_map.max_id+1, keys_ex=["weapon_type"])

    # Iterate over existing weapons, merge new data in
    for existing_entry in mhdata.weapon_map.values():
        weapon_type = existing_entry['weapon_type']
        weapon_tree = weapon_trees[weapon_type]

        # Note: weapon data ordering is unknown. order field and tree_id asc are sometimes wrong
        # Therefore its unsorted, we have to work off the spreadsheet order
        multiplier = cfg.weapon_multiplier[weapon_type]

        weapon = weapon_tree.by_name(existing_entry.name('en'))
        if not weapon:
            print(f"Could not find binary entry for {existing_entry.name('en')}")
            new_weapon_map.insert(existing_entry)
            continue
        
        is_kulve = existing_entry['category'] == 'Kulve'
        is_special = existing_entry['category'] in ('Kulve', 'Safi')
        binary = weapon.binary
        name = weapon.name

        new_entry = { **existing_entry }
        
        # Bind name and parent
        new_entry['name'] = name
        new_entry['weapon_type'] = weapon_type
        new_entry['previous_en'] = None
        if weapon.parent != None:
            new_entry['previous_en'] = weapon.parent.name['en']

        # Apply augmentation if its a kulve weapon that can get augmented
        if is_kulve:
            augment_params = kulve_augments.get(weapon_type, weapon.rarity)
            if augment_params:
                weapon = AugmentedWeapon(weapon, augment_params, 4)
                

        # Bind info
        new_entry['weapon_type'] = weapon_type
        new_entry['rarity'] = weapon.rarity
        new_entry['attack'] = (weapon.attack * multiplier).quantize(Decimal('1.'), rounding=ROUND_HALF_UP)
        new_entry['affinity'] = weapon.affinity
        new_entry['defense'] = weapon.defense or None
        new_entry['slot_1'] = binary.gem_slot1_lvl
        new_entry['slot_2'] = binary.gem_slot2_lvl
        new_entry['slot_3'] = binary.gem_slot3_lvl
        new_entry['elderseal'] = elderseal[binary.elderseal]

        # Bind Elements
        if name['en'] in ["Twin Nails", "Fire and Ice", "Blizzard and Blaze"]:
            print(f"Skipping {name['en']} element data")
        else:
            hidden = binary.hidden_element_id != 0
            element_atk = weapon.element_value

            new_entry['element_hidden'] = hidden
            new_entry['element1'] = weapon.element_type
            new_entry['element1_attack'] = element_atk * 10 if element_atk else None
            new_entry['element2'] = None
            new_entry['element2_attack'] = None

        # Bind skill
        skill = skill_text_handler.get_skilltree_name(binary.skill_id)
        new_entry['skill'] = skill['en'] if binary.skill_id != 0 else None
        
        # Bind Extras (Blade/Gun/Bow data)
        if weapon_type in cfg.weapon_types_melee:
            bind_weapon_blade_ext(weapon_type, new_entry, weapon)
            new_entry['sharpness'] = sharpness_reader.sharpness_for(binary)
        elif weapon_type in cfg.weapon_types_gun:
            tree = weapon.tree
            if is_special:
                tree = existing_entry['category']
            (ammo_name, ammo_data) = ammo_reader.create_data_for(
                wtype=weapon_type, 
                tree=tree,
                binary=weapon.binary)
            new_entry['ammo_config'] = ammo_name
        else:
            # TODO: Bows have an Enabled+ flag. Find out what it means
            # 1 = enabled, 2 = enabled+
            coating_binary = coating_data[binary.special_ammo_type]
            new_entry['bow'] = {
                'close': coating_binary.close_range > 0,
                'power': coating_binary.power > 0,
                'paralysis': coating_binary.paralysis > 0,
                'poison': coating_binary.poison > 0,
                'sleep': coating_binary.sleep > 0,
                'blast': coating_binary.blast > 0
            }

        # crafting data
        new_entry['craft'] = []
        if weapon.craft:
            new_entry['craft'].append({
                'type': 'Create',
                **convert_recipe(item_updater, weapon.craft)
            })
        if weapon.upgrade:
            new_entry['craft'].append({
                'type': 'Upgrade',
                **convert_recipe(item_updater, weapon.upgrade)
            })

        new_weapon_map.insert(new_entry)

    # Write new data
    writer = create_writer()

    writer.save_base_map_csv(
        "weapons/weapon_base.csv",
        new_weapon_map,
        schema=schema.WeaponBaseSchema(),
        translation_filename="weapons/weapon_base_translations.csv"
    )

    writer.save_data_csv(
        "weapons/weapon_sharpness.csv",
        new_weapon_map, 
        key="sharpness",
        schema=schema.WeaponSharpnessSchema()
    )

    writer.save_data_csv(
        "weapons/weapon_bow_ext.csv",
        new_weapon_map,
        key="bow",
        schema=schema.WeaponBowSchema()
    )

    writer.save_data_csv(
        "weapons/weapon_craft.csv",
        new_weapon_map, 
        key="craft",
        schema=schema.WeaponRecipeSchema()
    )

    writer.save_keymap_csv(
        "weapons/weapon_ammo.csv",
        ammo_reader.data,
        schema=schema.WeaponAmmoSchema()
    )

    print("Weapon files updated\n")
Exemple #5
0
def update_charms(mhdata, item_updater: ItemUpdater,
                  armor_collection: ArmorCollection):
    "Populates and updates charm information using the charm_base as a source of truth"

    print("Writing list of charm names (in order) to artifacts")

    def get_charm_raw(c):
        return {
            'name_en': c.name['en'],
            'parent': c.parent and c.parent.name['en']
        }

    artifacts.write_dicts_artifact(
        'charms_raw.csv', [get_charm_raw(c) for c in armor_collection.charms])

    skill_text_handler = SkillTextHandler()
    charm_by_name = {c.name['en']: c for c in armor_collection.charms}

    new_charm_map = DataMap(languages=["en"])
    for charm_entry in mhdata.charm_map.values():
        new_charm_entry = {**charm_entry}

        data = charm_by_name.get(charm_entry['name_en'])
        if not data:
            print(
                f"Warning: Charm {charm_entry['name_en']} has no associated binary data"
            )
            new_charm_map.insert(new_charm_entry)
            continue

        new_charm_entry['name'] = data.name
        new_charm_entry['previous_en'] = data.parent and data.parent.name['en']
        new_charm_entry['rarity'] = data.rarity

        # Add skills to new armor data
        skills = data.skills + ([(None, None)] * (2 - len(data.skills)))
        for i, (skill_id, skill_lvl) in enumerate(skills):
            if skill_id is None:
                new_charm_entry[f'skill{i+1}_name'] = None
                new_charm_entry[f'skill{i+1}_level'] = None
            else:
                name_en = skill_text_handler.get_skilltree_name(skill_id)['en']
                new_charm_entry[f'skill{i+1}_name'] = name_en
                new_charm_entry[f'skill{i+1}_level'] = skill_lvl

        new_charm_entry['craft'] = []
        recipes = [('Create', data.craft), ('Upgrade', data.upgrade)]
        for rtype, recipe in recipes:
            if recipe:
                new_charm_entry['craft'].append({
                    'type':
                    rtype,
                    **convert_recipe(item_updater, recipe)
                })

        new_charm_map.insert(new_charm_entry)

    # Write new data
    writer = create_writer()

    writer.save_base_map_csv(
        'charms/charm_base.csv',
        new_charm_map,
        translation_filename="charms/charm_base_translations.csv",
        schema=schema.CharmBaseSchema())

    writer.save_data_csv("charms/charm_craft.csv", new_charm_map, key="craft")

    print("Charm files updated\n")