Example #1
0
def merge_weapons():
    inc_data = requests.get("https://mhw-db.com/weapons").json()
    data = load_data().weapon_map

    not_exist = []
    mismatches_atk = []
    mismatches_def = []
    mismatches_other = []

    def print_all(items):
        for item in items:
            print(item)
        print()

    for weapon_inc in inc_data:
        inc_id = weapon_inc['id']
        inc_type = weapon_inc['type']
        name = weapon_inc['name']
        inc_label = f"{name} ({inc_type})"

        # Our system uses I/II/III, their's uses 1/2/3
        if name not in data.names('en'):
            name = name.replace(" 3", " III")
            name = name.replace(" 2", " II")
            name = name.replace(" 1", " I")

        if name not in data.names('en'):
            not_exist.append(f"{name} does not exist ({inc_type} {inc_id}).")
            continue # todo: add to our database

        existing = data.entry_of('en', name)
        
        # Incoming basic data for the weapon entry
        inc_attack = weapon_inc['attack']['display']
        inc_defense = weapon_inc['attributes'].get('defense', 0)
        inc_phial = weapon_inc['attributes'].get('phialType', None)
        inc_phial_power = None
        inc_kinsect = weapon_inc['attributes'].get('boostType', None)
        inc_affinity = weapon_inc['attributes'].get('affinity', 0)

        # Ensure minimum of 3 slots (avoid out of bounds)
        weapon_inc['slots'] += [{'rank':0}] * 3
        inc_slot1 = weapon_inc['slots'][0]['rank']
        inc_slot2 = weapon_inc['slots'][1]['rank']
        inc_slot3 = weapon_inc['slots'][2]['rank']

        # If there are two values and the second is a number, populate the phial power
        if inc_phial and ' ' in inc_phial:
            values = inc_phial.split(' ')
            if len(values) == 2 and values[1].isdigit():
                inc_phial = values[0]
                inc_phial_power = int(values[1])

        inc_shelling_type = None
        inc_shelling_level = None
        if 'shellingType' in weapon_inc['attributes']:
            (left, right) = weapon_inc['attributes']['shellingType'].split(' ')
            inc_shelling_type = left.lower()
            inc_shelling_level = int(right.lower().replace('lv', ''))

        # Simple validation comparisons
        if existing['attack'] != inc_attack:
            mismatches_atk.append(f"WARNING: {inc_label} has mismatching attack " +
                f"(internal {existing['attack']} | external {inc_attack} | ext id {inc_id})")
        if (existing['defense'] or 0) != inc_defense:
            mismatches_def.append(f"WARNING: {inc_label} has mismatching defense " +
                f"(internal {existing['defense']} | external {inc_defense} | ext id {inc_id})")
        if existing['kinsect_bonus'] and existing['kinsect_bonus'] != inc_kinsect:
            mismatches_other.append(f"Warning: {inc_label} has mismatching kinsect bonus")
        if existing['phial'] and existing['phial'] != inc_phial:
            mismatches_other.append(f"WARNING: {inc_label} has mismatching phial")
        if existing['phial_power'] and existing['phial_power'] != inc_phial_power:
            mismatches_other.append(f"WARNING: {inc_label} has mismatching phial power")
        if existing['shelling'] and existing['shelling'] != inc_shelling_type:
            mismatches_other.append(f"Warning: {inc_label} has mismatching shell type")
        if existing['shelling_level'] and existing['shelling_level'] != inc_shelling_level:
            mismatches_other.append(f"Warning: {inc_label} has mismatching shell level")

        def copy_maybe(field_name, value):
            "Inner function to copy a value if no value exists and there is a new val"
            if not existing[field_name] and value:
                existing[field_name] = value

        def copy_with_warning(field_name, value):
            if existing[field_name] != value:
                print(f"OVERRIDING: {inc_label} will get new {field_name}")
                existing[field_name] = value

        # Copy over new base data if there are new fields
        copy_maybe('kinsect_bonus', inc_kinsect)
        copy_maybe('phial', inc_phial)
        copy_maybe('phial_power', inc_phial_power)
        copy_maybe('shelling', inc_shelling_type)
        copy_maybe('shelling_level', inc_shelling_level)
        copy_maybe('affinity', inc_affinity)

        # Copy over with warning. TODO: Add arg to require opt in to overwrite slots
        copy_with_warning('slot_1', inc_slot1)
        copy_with_warning('slot_2', inc_slot2)
        copy_with_warning('slot_3', inc_slot3)

        # Add sharpness data for anything that's missing sharpness data
        if 'durability' in weapon_inc and not existing.get('sharpness', None):
            inc_sharpness = weapon_inc['durability'][5]
            maxed = weapon_inc['durability'][0] == inc_sharpness
            existing['sharpness'] = {
                'maxed': 'TRUE' if maxed else 'FALSE',
                'red': inc_sharpness['red'],
                'orange': inc_sharpness['orange'],
                'yellow': inc_sharpness['yellow'],
                'green': inc_sharpness['green'],
                'blue': inc_sharpness['blue'],
                'white': inc_sharpness['white'],
                'purple': 0
            }
        

    # print errors and warnings
    print_all(not_exist)
    print_all(mismatches_atk)
    print_all(mismatches_def)
    print_all(mismatches_other)

    weapon_base_schema = schema.WeaponBaseSchema()
    writer.save_base_map_csv('weapons/weapon_base_NEW.csv', data, schema=weapon_base_schema)
    writer.save_data_csv('weapons/weapon_sharpness_NEW.csv', data, key='sharpness')
Example #2
0
def update_weapons():
    mhdata = load_data()
    print("Existing Data loaded. Using to update weapon info")

    weapon_loader = WeaponDataLoader()
    item_text_handler = ItemTextHandler()
    skill_text_handler = SkillTextHandler()
    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 initial weapon binary data data")

    def bind_weapon_blade_ext(weapon_type: str, existing_entry,
                              binary: wp_dat.WpDatEntry):
        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:
            (phial, power) = s_axe_phials[binary.wep1_id]
            existing_entry['phial'] = phial
            existing_entry['phial_power'] = power
        if weapon_type == cfg.GUNLANCE:
            # first 5 are normals, second 5 are wide, third 5 are long
            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:
            existing_entry['kinsect_bonus'] = glaive_boosts[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)

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

    # Iterate over weapon types
    for weapon_type in cfg.weapon_types:
        print(f"Processing {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
        weapon_tree = weapon_loader.load_tree(weapon_type)
        print(f"Loaded {weapon_type} weapon tree binary data")

        multiplier = cfg.weapon_multiplier[weapon_type]

        # Iterate over nodes in the weapon tree (does depth first search)
        for weapon_node in weapon_tree:
            binary = weapon_node.binary
            name = weapon_node.name
            existing_entry = mhdata.weapon_map.entry_of('en', name['en'])

            new_entry = {}
            if existing_entry:
                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_node.parent != None:
                new_entry['previous_en'] = weapon_node.parent.name['en']

            # Bind info
            new_entry['weapon_type'] = weapon_type
            new_entry['rarity'] = binary.rarity + 1
            new_entry['attack'] = binary.raw_damage * multiplier
            new_entry['affinity'] = binary.affinity
            new_entry['defense'] = binary.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"]:
                print(f"Skipping {name['en']} element data")
            else:
                hidden = binary.hidden_element_id != 0
                element_id = binary.hidden_element_id if hidden else binary.element_id
                element_atk = binary.hidden_element_damage if hidden else binary.element_damage

                new_entry['element_hidden'] = hidden
                new_entry['element1'] = elements[element_id]
                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, binary)
                new_entry['sharpness'] = sharpness_reader.sharpness_for(binary)
            elif weapon_type in cfg.weapon_types_gun:
                (ammo_name, ammo_data) = ammo_reader.create_data_for(
                    wtype=weapon_type,
                    tree=weapon_node.tree,
                    binary=weapon_node.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_node.craft:
                new_entry['craft'].append({
                    'type':
                    'Create',
                    **convert_recipe(item_text_handler, weapon_node.craft)
                })
            if weapon_node.upgrade:
                new_entry['craft'].append({
                    'type':
                    'Upgrade',
                    **convert_recipe(item_text_handler, weapon_node.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.WeaponCraftSchema())

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

    print("Weapon files updated\n")

    add_missing_items(item_text_handler.encountered, mhdata=mhdata)
Example #3
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")