def parse_attributes():
    logging.debug('Parsing attributes...')

    ies_path = os.path.join(constants.PATH_INPUT_DATA, 'ies_ability.ipf', 'ability.ies')

    with open(ies_path, 'rb') as ies_file:
        for row in csv.DictReader(ies_file, delimiter=',', quotechar='"'):
            obj = {}
            obj['$ID'] = int(row['ClassID'])
            obj['$ID_NAME'] = row['ClassName']
            obj['Description'] = parser_translations.translate(row['Desc']).strip() + '{nl}'
            obj['Icon'] = parser_assets.parse_entity_icon(row['Icon'])
            obj['Name'] = parser_translations.translate(row['Name'])

            obj['IsToggleable'] = row['AlwaysActive'] == 'NO'

            obj['DescriptionRequired'] = None
            obj['LevelMax'] = -1
            obj['Unlock'] = None
            obj['UnlockArgs'] = {}
            obj['UpgradePrice'] = []
            obj['Link_Jobs'] = []
            obj['Link_Skills'] = [skill for skill in row['SkillCategory'].split(';') if len(skill)]

            globals.attributes[obj['$ID']] = obj
            globals.attributes_by_name[obj['$ID_NAME']] = obj
示例#2
0
def parse_maps():
    logging.debug('Parsing Maps...')

    ies_path = os.path.join(constants.PATH_INPUT_DATA, 'ies.ipf', 'map.ies')

    with open(ies_path, 'rb') as ies_file:
        for row in csv.DictReader(ies_file, delimiter=',', quotechar='"'):
            obj = {}
            obj['$ID'] = int(row['ClassID'])
            obj['$ID_NAME'] = row['ClassName']
            obj['Icon'] = None
            obj['Name'] = parser_translations.translate(row['Name'])

            obj['HasChallengeMode'] = row['ChallengeMode'] == 'YES'
            obj['HasWarp'] = int(row['WarpCost']) > 0
            obj['Level'] = int(row['QuestLevel'])
            obj['Prop_EliteMonsterCapacity'] = int(row['EliteMonsterCapacity'])
            obj['Prop_MaxHateCount'] = int(row['MaxHateCount'])
            obj['Prop_RewardEXPBM'] = float(row['MaxHateCount'])
            obj['Stars'] = int(row['MapRank'])
            obj['Type'] = TOSMapType.value_of(row['MapType'])
            obj['Warp'] = int(row['WarpCost'])
            obj['WorldMap'] = [int(coord) for coord in row['WorldMap'].split('/')] if row['WorldMap'] else None

            obj['Link_Items'] = []
            obj['Link_Items_Exploration'] = []
            obj['Link_Maps'] = []
            obj['Link_Maps_Floors'] = []
            obj['Link_NPCs'] = []

            globals.maps[obj['$ID']] = obj
            globals.maps_by_name[obj['$ID_NAME']] = obj
            globals.maps_by_position['-'.join(row['WorldMap'].split('/')) if obj['WorldMap'] else ''] = obj
示例#3
0
def parse():
    parse_items('item.ies')
    parse_items('item_colorspray.ies')
    parse_items('item_gem.ies')
    parse_items('item_equip.ies')
    parse_items('item_equip_ep12.ies')
    parse_items('item_premium.ies')
    parse_items('item_quest.ies')
    parse_items('recipe.ies')

    # Hotfix: Insert 'Silver' as an Item
    obj = {}
    obj['$ID'] = -1
    obj['$ID_NAME'] = 'Moneybag1'
    obj['Icon'] = parser_assets.parse_entity_icon('icon_item_silver')
    obj['Name'] = parser_translations.translate(u'실버')
    obj['Tradability'] = 'FFFF'
    obj['Type'] = TOSItemGroup.UNUSED

    for key in globals.items.values()[0]:
        if key not in obj:
            obj[key] = None

    globals.items[obj['$ID']] = obj
    globals.items_by_name[obj['$ID_NAME']] = obj
def parse_equipment_sets(file_name):
    logging.debug('Parsing equipment sets...')

    ies_path = os.path.join(constants.PATH_INPUT_DATA, 'ies.ipf', file_name)
    ies_file = open(ies_path, 'rb')
    ies_reader = csv.DictReader(ies_file, delimiter=',', quotechar='"')

    for row in ies_reader:
        obj = {}
        obj['$ID'] = int(row['ClassID'])
        obj['$ID_NAME'] = row['ClassName']
        obj['Name'] = parser_translations.translate(
            row['Name']) if 'Name' in row else None

        obj['Link_Items'] = []

        # Parse bonus
        obj['Bonus2'] = parser_translations.translate(
            row['EffectDesc_2']) if row['EffectDesc_2'] != '' else None
        obj['Bonus3'] = parser_translations.translate(
            row['EffectDesc_3']) if row['EffectDesc_3'] != '' else None
        obj['Bonus4'] = parser_translations.translate(
            row['EffectDesc_4']) if row['EffectDesc_4'] != '' else None
        obj['Bonus5'] = parser_translations.translate(
            row['EffectDesc_5']) if row['EffectDesc_5'] != '' else None
        obj['Bonus6'] = parser_translations.translate(
            row['EffectDesc_6']) if row['EffectDesc_6'] != '' else None
        obj['Bonus7'] = parser_translations.translate(
            row['EffectDesc_7']) if row['EffectDesc_7'] != '' else None

        globals.equipment_sets[obj['$ID']] = obj
        globals.equipment_sets_by_name[obj['$ID_NAME']] = obj
示例#5
0
def parse_jobs():
    logging.debug('Parsing Jobs...')

    ies_path = os.path.join(constants.PATH_INPUT_DATA, 'ies.ipf', 'job.ies')

    with open(ies_path, 'rb') as ies_file:
        for row in csv.DictReader(ies_file, delimiter=',', quotechar='"'):
            obj = {}
            obj['$ID'] = int(row['ClassID'])
            obj['$ID_NAME'] = row['ClassName']
            obj['Description'] = parser_translations.translate(row['Caption1'])
            obj['Icon'] = parser_assets.parse_entity_icon(row['Icon'])
            obj['Name'] = parser_translations.translate(row['Name'])

            obj['CircleMax'] = int(row['MaxCircle'])
            obj['JobDifficulty'] = TOSJobDifficulty.value_of(
                row['ControlDifficulty'])
            obj['JobTree'] = TOSJobTree.value_of(row['CtrlType'])
            obj['JobType'] = [
                TOSJobType.value_of(v.strip())
                for v in row['ControlType'].split(',')
            ] if len(row['ControlType']) else None
            obj['IsHidden'] = row['HiddenJob'] == 'YES'
            obj['IsSecret'] = obj['IsHidden'] and len(row['PreFunction']) > 0
            obj['IsStarter'] = int(row['Rank']) == 1
            obj['Rank'] = int(row['Rank'])
            obj['Stat_CON'] = int(row['CON'])
            obj['Stat_DEX'] = int(row['DEX'])
            obj['Stat_INT'] = int(row['INT'])
            obj['Stat_SPR'] = int(row['MNA'])
            obj['Stat_STR'] = int(row['STR'])
            obj['StatBase_CON'] = 0
            obj['StatBase_DEX'] = 0
            obj['StatBase_INT'] = 0
            obj['StatBase_SPR'] = 0
            obj['StatBase_STR'] = 0

            obj['Link_Attributes'] = []
            obj['Link_Skills'] = []

            globals.jobs[obj['$ID']] = obj
            globals.jobs_by_name[obj['$ID_NAME']] = obj
def parse_books_dialog():
    logging.debug('Parsing books dialog...')

    ies_path = os.path.join(constants.PATH_INPUT_DATA, 'ies_client.ipf',
                            'dialogtext.ies')
    ies_file = open(ies_path, 'rb')
    ies_reader = csv.DictReader(ies_file, delimiter=',', quotechar='"')

    for row in ies_reader:
        if row['ClassName'] not in globals.books_by_name:
            continue

        book = globals.books_by_name[row['ClassName']]
        book['Text'] = parser_translations.translate(row['Text'])

    ies_file.close()
def parse_gems_bonus(is_rebuild):
    logging.debug('Parsing gems bonus...')

    xml_path = os.path.join(constants.PATH_INPUT_DATA, 'xml.ipf',
                            'socket_property.xml')
    xml = ET.parse(xml_path).getroot()

    SLOTS = ['TopLeg', 'HandOrFoot', 'MainOrSubWeapon'] if is_rebuild else\
            ['TopLeg', 'Foot', 'Hand', 'Weapon', 'SubWeapon']

    # example: <Item Name="gem_circle_1">
    for item in xml:
        gem = globals.gems_by_name[item.get('Name')]

        for level in item:
            if level.get('Level') == '0':
                continue

            for slot in SLOTS:
                bonus = level.get('PropList_' + slot)
                penalty = level.get('PropList_' + slot + '_Penalty')

                for slot in (slot.split('Or') if 'Or' in slot else
                             [slot]):  # support for Re:Build 2-in-1 slots
                    for prop in [bonus, penalty]:
                        if prop is not None and prop != 'None':
                            if gem['TypeGem'] == TOSGemType.SKILL:
                                gem['Bonus' + parse_gems_slot(slot)].append({
                                    'Stat':
                                    parser_translations.translate(
                                        prop).replace('OptDesc/', '')
                                })
                            elif gem['TypeGem'] == TOSGemType.STATS:
                                prop_slot = prop.split('/')

                                stat = TOSEquipmentStat.value_of('ADD_' +
                                                                 prop_slot[0])
                                stat = TOSEquipmentStat.value_of(
                                    prop_slot[0]) if stat is None else stat

                                gem['Bonus' + parse_gems_slot(slot)].append({
                                    'Stat':
                                    stat,
                                    'Value':
                                    int(prop_slot[1])
                                })
示例#8
0
def parse_maps():
    logging.debug('Parsing maps...')

    ies_path = os.path.join(constants.PATH_INPUT_DATA, 'ies.ipf', 'map.ies')
    ies_file = open(ies_path, 'rb')
    ies_reader = csv.DictReader(ies_file, delimiter=',', quotechar='"')

    for row in ies_reader:
        obj = {}
        obj['$ID'] = int(row['ClassID'])
        obj['$ID_NAME'] = row['ClassName']
        obj['Icon'] = ''
        obj['Name'] = parser_translations.translate(row['Name'])

        # TODO: parse remaining properties

        globals.maps[obj['$ID']] = obj
        globals.maps_by_name[obj['$ID_NAME']] = obj

    ies_file.close()
示例#9
0
def parse_monsters(file_name):
    logging.debug('Parsing %s...', file_name)

    LUA = luautil.load_script('calc_property_monster.lua', [
        'GET_MON_STAT',
        'SCR_Get_MON_STR',
        'SCR_Get_MON_INT',
        'SCR_Get_MON_CON',
        'SCR_Get_MON_MNA',
        'SCR_Get_MON_DEX',
        'SCR_Get_MON_MHP',
        'SCR_Get_MON_MSP',
        'SCR_GET_MON_EXP',
        'SCR_GET_MON_JOBEXP',
        'SCR_Get_MON_DEF',
        'SCR_Get_MON_MDEF',
        'SCR_Get_MON_HR',
        'SCR_Get_MON_DR',
        'SCR_Get_MON_CRTHR',
        'SCR_Get_MON_CRTDR',
        'SCR_Get_MON_CRTATK',
        'SCR_Get_MON_MINPATK',
        'SCR_Get_MON_MAXPATK',
        'SCR_Get_MON_MINMATK',
        'SCR_Get_MON_MAXMATK',
        'SCR_Get_MON_BLK',
        'SCR_Get_MON_BLK_BREAK',
        'SCR_MON_ITEM_ARMOR_CALC',
        'SCR_MON_ITEM_ARMOR_DEF_CALC',
        'SCR_MON_ITEM_ARMOR_MDEF_CALC',
        'SCR_MON_ITEM_WEAPON_CALC',
        'SCR_MON_ITEM_GRADE_RATE',
        'SCR_MON_ITEM_REINFORCE_ARMOR_CALC',
        'SCR_MON_ITEM_REINFORCE_WEAPON_CALC',
        'SCR_MON_ITEM_TRANSCEND_CALC',
        'SCR_RACE_TYPE_RATE',
        'SCR_SIZE_TYPE_RATE',
    ])

    ies_path = os.path.join(constants.PATH_INPUT_DATA, "ies.ipf", file_name.lower())
    ies_file = open(ies_path, 'rb')
    ies_reader = csv.DictReader(ies_file, delimiter=',', quotechar='"')

    for row in ies_reader:
        if row['MonRank'].upper() not in MONSTER_RANK_WHITELIST:
            continue

        #logging.debug('Parsing monster: %s :: %s', row['ClassID'], row['ClassName'])

        # HotFix: these properties need to be calculated before the remaining ones
        row['Lv'] = int(row['Level']) if int(row['Level']) > 1 else 1
        row['CON'] = LUA['SCR_Get_MON_CON'](row)
        row['DEX'] = LUA['SCR_Get_MON_DEX'](row)
        row['INT'] = LUA['SCR_Get_MON_INT'](row)
        row['MNA'] = LUA['SCR_Get_MON_MNA'](row)
        row['STR'] = LUA['SCR_Get_MON_STR'](row)

        obj = {}
        obj['$ID'] = int(row['ClassID'])
        obj['$ID_NAME'] = row['ClassName']
        obj['Description'] = parser_translations.translate(row['Desc'])
        obj['Icon'] = parser_assets.parse_entity_icon(row['Icon'])
        obj['Name'] = parser_translations.translate(row['Name'])

        obj['Armor'] = TOSEquipmentMaterial.value_of(row['ArmorMaterial'])
        obj['Element'] = TOSElement.value_of(row['Attribute'])
        obj['Level'] = int(row['Lv'])
        obj['Race'] = TOSMonsterRace.value_of(row['RaceType'])
        obj['Rank'] = TOSMonsterRank.value_of(row['MonRank'])
        obj['Size'] = TOSMonsterSize.value_of(row['Size'])
        obj['EXP'] = int(LUA['SCR_GET_MON_EXP'](row)) if obj['Level'] < 999 else 0
        obj['EXPClass'] = int(LUA['SCR_GET_MON_JOBEXP'](row)) if obj['Level'] < 999 else 0
        obj['Stat_CON'] = int(row['CON'])
        obj['Stat_DEX'] = int(row['DEX'])
        obj['Stat_INT'] = int(row['INT'])
        obj['Stat_SPR'] = int(row['MNA'])
        obj['Stat_STR'] = int(row['STR'])
        obj['Stat_HP'] = int(LUA['SCR_Get_MON_MHP'](row))
        obj['Stat_SP'] = int(LUA['SCR_Get_MON_MSP'](row))
        obj['Stat_ATTACK_MAGICAL_MAX'] = int(LUA['SCR_Get_MON_MAXMATK'](row))
        obj['Stat_ATTACK_MAGICAL_MIN'] = int(LUA['SCR_Get_MON_MINMATK'](row))
        obj['Stat_ATTACK_PHYSICAL_MAX'] = int(LUA['SCR_Get_MON_MAXPATK'](row))
        obj['Stat_ATTACK_PHYSICAL_MIN'] = int(LUA['SCR_Get_MON_MINPATK'](row))
        obj['Stat_DEFENSE_MAGICAL'] = int(LUA['SCR_Get_MON_MDEF'](row))
        obj['Stat_DEFENSE_PHYSICAL'] = int(LUA['SCR_Get_MON_DEF'](row))
        obj['Stat_Accuracy'] = int(LUA['SCR_Get_MON_HR'](row))
        obj['Stat_Evasion'] = int(LUA['SCR_Get_MON_DR'](row))
        obj['Stat_CriticalDamage'] = int(LUA['SCR_Get_MON_CRTATK'](row))
        obj['Stat_CriticalDefense'] = int(LUA['SCR_Get_MON_CRTDR'](row))
        obj['Stat_CriticalRate'] = int(LUA['SCR_Get_MON_CRTHR'](row))
        obj['Stat_BlockRate'] = int(LUA['SCR_Get_MON_BLK'](row))
        obj['Stat_BlockPenetration'] = int(LUA['SCR_Get_MON_BLK_BREAK'](row))

        obj['Link_Drops'] = []
        obj['Link_Spawns'] = []

        globals.monsters[obj['$ID']] = obj
        globals.monsters_by_name[obj['$ID_NAME']] = obj

    ies_file.close()
示例#10
0
def parse_skills(is_rebuild):
    logging.debug('Parsing skills...')

    LUA = luautil.load_script('calc_property_skill.lua', '*', False)
    LUA_EMBEDDED = [
        'SCR_ABIL_ADD_SKILLFACTOR',
        'SCR_ABIL_ADD_SKILLFACTOR_TOOLTIP',
        'SCR_Get_SpendSP',
        'SCR_REINFORCEABILITY_TOOLTIP',
    ]

    ies_path = os.path.join(constants.PATH_INPUT_DATA, 'ies.ipf', 'skill.ies')

    with open(ies_path, 'rb') as ies_file:
        for row in csv.DictReader(ies_file, delimiter=',', quotechar='"'):
            # Ignore 'Common_' skills (e.g. Bokor's Summon abilities)
            if row['ClassName'].find('Common_') == 0:
                continue

            obj = {}
            obj['$ID'] = int(row['ClassID'])
            obj['$ID_NAME'] = row['ClassName']
            obj['Description'] = parser_translations.translate(row['Caption'])
            obj['Icon'] = parser_assets.parse_entity_icon(row['Icon'])
            obj['Name'] = parser_translations.translate(row['Name'])

            obj['Effect'] = parser_translations.translate(row['Caption2'])
            obj['Element'] = TOSElement.value_of(row['Attribute'])
            obj['IsShinobi'] = row[
                'CoolDown'] == 'SCR_GET_SKL_COOLDOWN_BUNSIN' or (
                    row['CoolDown']
                    and 'Bunshin_Debuff' in LUA[row['CoolDown']])
            obj['OverHeat'] = {
                'Value': int(row['SklUseOverHeat']),
                'Group': row['OverHeatGroup']
            } if not is_rebuild else int(
                row['SklUseOverHeat']
            )  # Re:Build overheat is now simpler to calculate
            obj['Prop_BasicCoolDown'] = int(row['BasicCoolDown'])
            obj['Prop_BasicPoison'] = int(row['BasicPoison'])
            obj['Prop_BasicSP'] = int(math.floor(float(row['BasicSP'])))
            obj['Prop_LvUpSpendPoison'] = int(row['LvUpSpendPoison'])
            obj['Prop_LvUpSpendSp'] = float(row['LvUpSpendSp'])
            obj['Prop_SklAtkAdd'] = float(row['SklAtkAdd'])
            obj['Prop_SklAtkAddByLevel'] = float(row['SklAtkAddByLevel'])
            obj['Prop_SklFactor'] = float(row['SklFactor'])
            obj['Prop_SklFactorByLevel'] = float(row['SklFactorByLevel'])
            obj['Prop_SklSR'] = float(row['SklSR'])
            obj['Prop_SpendItemBaseCount'] = int(row['SpendItemBaseCount'])
            obj['RequiredStance'] = row['ReqStance']
            obj['RequiredStanceCompanion'] = TOSRequiredStanceCompanion.value_of(
                row['EnableCompanion'])
            obj['RequiredSubWeapon'] = row['UseSubweaponDamage'] == 'YES'

            obj['CoolDown'] = None
            obj['IsEnchanter'] = False
            obj['IsPardoner'] = False
            obj['IsRunecaster'] = False
            obj['Prop_LevelPerGrade'] = -1  # Remove when Re:Build goes global
            obj['Prop_MaxLevel'] = -1
            obj['Prop_UnlockGrade'] = -1  # Remove when Re:Build goes global
            obj['Prop_UnlockClassLevel'] = -1
            obj['SP'] = None
            obj['TypeAttack'] = []
            obj['Link_Attributes'] = []
            obj['Link_Gem'] = None
            obj['Link_Job'] = None

            # Parse TypeAttack
            if row['ValueType'] == 'Buff':
                obj['TypeAttack'].append(TOSAttackType.BUFF)
            if row['ClassType'] is not None:
                obj['TypeAttack'].append(
                    TOSAttackType.value_of(row['ClassType']))
            if row['AttackType'] is not None:
                obj['TypeAttack'].append(
                    TOSAttackType.value_of(row['AttackType']))

            obj['TypeAttack'] = list(set(obj['TypeAttack']))
            obj['TypeAttack'] = [
                attack for attack in obj['TypeAttack']
                if attack is not None and attack != TOSAttackType.UNKNOWN
            ]

            # Add missing Description header
            if not re.match(r'{#.+}{ol}(\[.+?\]){\/}{\/}{nl}',
                            obj['Description']):
                header = [
                    '[' + TOSAttackType.to_string(attack) + ']'
                    for attack in obj['TypeAttack']
                ]

                header_color = ''
                header_color = '993399' if TOSAttackType.MAGIC in obj[
                    'TypeAttack'] else header_color
                header_color = 'DD5500' if TOSAttackType.MELEE in obj[
                    'TypeAttack'] else header_color
                header_color = 'DD5500' if TOSAttackType.MISSILE in obj[
                    'TypeAttack'] else header_color

                if obj['Element'] != TOSElement.MELEE:
                    header.append('[' + TOSElement.to_string(obj['Element']) +
                                  ']')

                obj['Description'] = '{#' + header_color + '}{ol}' + ' - '.join(
                    header) + '{/}{/}{nl}' + obj['Description']

            # Parse effects
            for effect in re.findall(r'{(.*?)}', obj['Effect']):
                if effect in EFFECT_DEPRECATE:
                    # Hotfix: sometimes IMC changes which effects are used, however they forgot to properly communicate to the translation team.
                    # This code is responsible for fixing that and warning so the in-game translations can be fixed
                    logging.warning('[%32s] Deprecated effect [%s] in Effect',
                                    obj['$ID_NAME'], effect)

                    effect_deprecate = effect
                    effect = EFFECT_DEPRECATE[effect]

                    obj['Effect'] = re.sub(
                        r'\b' + re.escape(effect_deprecate) + r'\b', effect,
                        obj['Effect'])

                if effect in row:
                    key = 'Effect_' + effect

                    # HotFix: make sure all skills have the same Effect columns (1/2)
                    if key not in EFFECTS:
                        EFFECTS.append('Effect_' + effect)

                    if row[effect] != 'ZERO':
                        obj[key] = parse_skills_lua_source(
                            LUA, LUA_EMBEDDED, row[effect])
                        obj[key] = parse_skills_lua_source_to_javascript(
                            row, obj[key])
                    else:
                        # Hotfix: similar to the hotfix above
                        logging.warning(
                            '[%32s] Deprecated effect [%s] in Effect',
                            obj['$ID_NAME'], effect)
                        obj[key] = None
                else:
                    continue

            # Parse formulas
            if row['CoolDown']:
                obj['CoolDown'] = parse_skills_lua_source(
                    LUA, LUA_EMBEDDED, row['CoolDown'])
                obj['CoolDown'] = parse_skills_lua_source_to_javascript(
                    row, obj['CoolDown'])
            if row['SpendSP']:
                obj['SP'] = parse_skills_lua_source(LUA, LUA_EMBEDDED,
                                                    row['SpendSP'])
                obj['SP'] = parse_skills_lua_source_to_javascript(
                    row, obj['SP'])

            globals.skills[obj['$ID']] = obj
            globals.skills_by_name[obj['$ID_NAME']] = obj

    # HotFix: make sure all skills have the same Effect columns (2/2)
    for skill in globals.skills.values():
        for effect in EFFECTS:
            if effect not in skill:
                skill[effect] = None
示例#11
0
def parse_monsters(file_name):
    logging.debug('Parsing %s...', file_name)

    LUA_RUNTIME = luautil.LUA_RUNTIME
    LUA_SOURCE = luautil.LUA_SOURCE

    ies_path = os.path.join(constants.PATH_INPUT_DATA, "ies.ipf",
                            file_name.lower())
    ies_file = open(ies_path, 'rb')
    ies_reader = csv.DictReader(ies_file, delimiter=',', quotechar='"')

    for row in ies_reader:
        #logging.debug('Parsing monster: %s :: %s', row['ClassID'], row['ClassName'])

        # HotFix: these properties need to be calculated before the remaining ones
        row['Lv'] = int(row['Level']) if int(row['Level']) > 1 else 1
        row['CON'] = LUA_RUNTIME['SCR_Get_MON_CON'](row)
        row['DEX'] = LUA_RUNTIME['SCR_Get_MON_DEX'](row)
        row['INT'] = LUA_RUNTIME['SCR_Get_MON_INT'](row)
        row['MNA'] = LUA_RUNTIME['SCR_Get_MON_MNA'](row)
        row['STR'] = LUA_RUNTIME['SCR_Get_MON_STR'](row)

        obj = {}
        obj['$ID'] = int(row['ClassID'])
        obj['$ID_NAME'] = row['ClassName']
        obj['Description'] = parser_translations.translate(row['Desc'])
        obj['Icon'] = parser_assets.parse_entity_icon(
            row['Icon']) if row['Icon'] != 'ui_CreateMonster' else None
        obj['Name'] = parser_translations.translate(row['Name'])
        obj['Type'] = TOSMonsterType.value_of(row['GroupName'])

        if obj['Type'] == TOSMonsterType.MONSTER:
            obj['Armor'] = TOSEquipmentMaterial.value_of(row['ArmorMaterial'])
            obj['Element'] = TOSElement.value_of(row['Attribute'])
            obj['Level'] = int(row['Lv'])
            obj['Race'] = TOSMonsterRace.value_of(row['RaceType'])
            obj['Rank'] = TOSMonsterRank.value_of(row['MonRank'])
            obj['Size'] = TOSMonsterSize.value_of(
                row['Size']) if row['Size'] else None
            obj['EXP'] = int(LUA_RUNTIME['SCR_GET_MON_EXP'](
                row)) if obj['Level'] < 999 else 0
            obj['EXPClass'] = int(LUA_RUNTIME['SCR_GET_MON_JOBEXP'](
                row)) if obj['Level'] < 999 else 0
            obj['Stat_CON'] = int(row['CON'])
            obj['Stat_DEX'] = int(row['DEX'])
            obj['Stat_INT'] = int(row['INT'])
            obj['Stat_SPR'] = int(row['MNA'])
            obj['Stat_STR'] = int(row['STR'])
            obj['Stat_HP'] = int(LUA_RUNTIME['SCR_Get_MON_MHP'](row))
            obj['Stat_SP'] = int(LUA_RUNTIME['SCR_Get_MON_MSP'](row))
            obj['Stat_ATTACK_MAGICAL_MAX'] = int(
                LUA_RUNTIME['SCR_Get_MON_MAXMATK'](row))
            obj['Stat_ATTACK_MAGICAL_MIN'] = int(
                LUA_RUNTIME['SCR_Get_MON_MINMATK'](row))
            obj['Stat_ATTACK_PHYSICAL_MAX'] = int(
                LUA_RUNTIME['SCR_Get_MON_MAXPATK'](row))
            obj['Stat_ATTACK_PHYSICAL_MIN'] = int(
                LUA_RUNTIME['SCR_Get_MON_MINPATK'](row))
            obj['Stat_DEFENSE_MAGICAL'] = int(
                LUA_RUNTIME['SCR_Get_MON_MDEF'](row))
            obj['Stat_DEFENSE_PHYSICAL'] = int(
                LUA_RUNTIME['SCR_Get_MON_DEF'](row))
            obj['Stat_Accuracy'] = int(LUA_RUNTIME['SCR_Get_MON_HR'](row))
            obj['Stat_Evasion'] = int(LUA_RUNTIME['SCR_Get_MON_DR'](row))
            obj['Stat_CriticalDamage'] = int(
                LUA_RUNTIME['SCR_Get_MON_CRTATK'](row))
            obj['Stat_CriticalDefense'] = int(
                LUA_RUNTIME['SCR_Get_MON_CRTDR'](row))
            obj['Stat_CriticalRate'] = int(
                LUA_RUNTIME['SCR_Get_MON_CRTHR'](row))
            obj['Stat_BlockRate'] = int(LUA_RUNTIME['SCR_Get_MON_BLK'](row))
            obj['Stat_BlockPenetration'] = int(
                LUA_RUNTIME['SCR_Get_MON_BLK_BREAK'](row))

            obj['Link_Items'] = []
            obj['Link_Maps'] = []

            globals.monsters[obj['$ID']] = obj
            globals.monsters_by_name[obj['$ID_NAME']] = obj
        elif obj['Type'] == TOSMonsterType.NPC:
            obj['Icon'] = parser_assets.parse_entity_icon(
                row['MinimapIcon']) if row['MinimapIcon'] else obj['Icon']

            globals.npcs[obj['$ID']] = obj
            globals.npcs_by_name[obj['$ID_NAME']] = obj

    ies_file.close()
示例#12
0
def parse_items(file_name):
    logging.debug('Parsing %s...', file_name)

    ies_path = os.path.join(constants.PATH_INPUT_DATA, "ies.ipf", file_name)
    ies_file = open(ies_path, 'rb')
    ies_reader = csv.DictReader(ies_file, delimiter=',', quotechar='"')

    for row in ies_reader:
        item_type = TOSItemGroup.RECIPE if file_name == 'recipe.ies' else TOSItemGroup.value_of(
            row['GroupName'])
        item_type_equipment = TOSEquipmentType.value_of(
            row['ClassType']) if 'ClassType' in row else None

        #logging.debug('Parsing item: %s :: %s', row['ClassID'], row['ClassName'])

        obj = {}
        obj['$ID'] = int(row['ClassID'])
        obj['$ID_NAME'] = row['ClassName']
        obj['Description'] = parser_translations.translate(
            row['Desc']) if 'Desc' in row else None
        obj['Icon'] = parser_assets.parse_entity_icon(row['Icon'])
        obj['Name'] = parser_translations.translate(
            row['Name']) if 'Name' in row else None

        obj['Price'] = row['SellPrice']
        obj['TimeCoolDown'] = float(int(row['ItemCoolDown']) /
                                    1000) if 'ItemCoolDown' in row else None
        obj['TimeLifeTime'] = float(int(
            row['LifeTime'])) if 'LifeTime' in row else None
        obj['Tradability'] = '%s%s%s%s' % (
            'T' if row['MarketTrade'] == 'YES' else 'F',  # Market
            'T' if row['UserTrade'] == 'YES' else 'F',  # Players
            'T' if row['ShopTrade'] == 'YES' else 'F',  # Shop
            'T' if row['TeamTrade'] == 'YES' else 'F',  # Team Storage
        )
        obj['Type'] = item_type
        obj['Weight'] = float(row['Weight']) if 'Weight' in row else None

        obj['Link_Collections'] = []
        obj['Link_Cubes'] = []
        obj['Link_MonsterDrops'] = []
        obj['Link_RecipeTarget'] = []
        obj['Link_RecipeMaterial'] = []

        if item_type == TOSItemGroup.BOOK:
            globals.books[obj['$ID']] = obj
            globals.books_by_name[obj['$ID_NAME']] = obj
        elif item_type == TOSItemGroup.CARD:
            globals.cards[obj['$ID']] = obj
            globals.cards_by_name[obj['$ID_NAME']] = obj
        elif item_type == TOSItemGroup.COLLECTION:
            globals.collections[obj['$ID']] = obj
            globals.collections_by_name[obj['$ID_NAME']] = obj
        elif item_type == TOSItemGroup.CUBE:
            globals.cubes[obj['$ID']] = obj
            globals.cubes_by_name[obj['$ID_NAME']] = obj
            globals.cubes_by_stringarg[row['StringArg']] = obj
        elif item_type == TOSItemGroup.GEM:
            globals.gems[obj['$ID']] = obj
            globals.gems_by_name[obj['$ID_NAME']] = obj
        elif item_type == TOSItemGroup.RECIPE:
            globals.recipes[obj['$ID']] = obj
            globals.recipes_by_name[obj['$ID_NAME']] = obj
        elif item_type in ITEM_GROUP_FASHION_WHITELIST\
                or item_type_equipment in TYPE_EQUIPMENT_COSTUME_LIST\
                or 'ClassType2' in row and row['ClassType2'] == 'Premium':
            globals.equipment[obj['$ID']] = obj
            globals.equipment_by_name[obj['$ID_NAME']] = obj
        elif item_type in ITEM_GROUP_ITEM_WHITELIST:
            globals.items[obj['$ID']] = obj
            globals.items_by_name[obj['$ID_NAME']] = obj
        elif item_type in ITEM_GROUP_EQUIPMENT_WHITELIST and item_type_equipment is not None:
            globals.equipment[obj['$ID']] = obj
            globals.equipment_by_name[obj['$ID_NAME']] = obj

    ies_file.close()
def parse_links_jobs():
    logging.debug("Parsing attributes <> jobs...")

    LUA = luautil.load_script('ability_price.lua', '*')
    LUA_UNLOCK = luautil.load_script('ability_unlock.lua', '*', False)

    # Parse level, unlock and formula
    ies_path = os.path.join(constants.PATH_INPUT_DATA, 'ies.ipf', 'job.ies')

    with open(ies_path, 'rb') as ies_file:
        for row in csv.DictReader(ies_file, delimiter=',', quotechar='"'):
            job = globals.jobs_by_name[row['ClassName']]
            ies_path = os.path.join(constants.PATH_INPUT_DATA, 'ies_ability.ipf', 'ability_' + row['EngName'].lower() + '.ies')

            # If this job is still under development, skip
            if not os.path.isfile(ies_path):
                continue

            with open(ies_path, 'rb') as ies_file:
                for row in csv.DictReader(ies_file, delimiter=',', quotechar='"'):
                    attribute = globals.attributes_by_name[row['ClassName']]
                    attribute['DescriptionRequired'] = attribute['DescriptionRequired'] if attribute['DescriptionRequired'] else ''
                    attribute['DescriptionRequired'] = attribute['DescriptionRequired'] + '{nl}{b}' + parser_translations.translate(row['UnlockDesc']) + '{b}'
                    attribute['LevelMax'] = int(row['MaxLevel'])

                    # Parse attribute cost
                    if row['ScrCalcPrice']:
                        for lv in range(int(row['MaxLevel'])):
                            attribute['UpgradePrice'].append(LUA[row['ScrCalcPrice']](None, row['ClassName'], lv + 1, attribute['LevelMax'])[0])
                        attribute['UpgradePrice'] = [value for value in attribute['UpgradePrice'] if value > 0]

                    # Parse attribute skill (in case it is missing in the ability.ies)
                    if not attribute['Link_Skills'] and row['UnlockArgStr'] in globals.skills_by_name:
                        logging.debug('adding missing skill %s', row['UnlockArgStr'])
                        skill = globals.skills_by_name[row['UnlockArgStr']]

                        globals.link(
                            attribute, 'Link_Skills', globals.get_attribute_link(attribute),
                            skill, 'Link_Attributes', globals.get_skill_link(skill)
                        )

                    # Parse attribute job
                    if not attribute['Link_Skills'] or 'All' in attribute['Link_Skills']:
                        globals.link(
                            attribute, 'Link_Jobs', globals.get_attribute_link(attribute),
                            job, 'Link_Attributes', globals.get_job_link(job)
                        )

                    # Parse attribute unlock
                    attribute['Unlock'] = luautil.lua_function_source_to_javascript(
                        luautil.lua_function_source(LUA_UNLOCK[row['UnlockScr']])[1:-1]  # remove 'function' and 'end'
                    ) if not attribute['Unlock'] and row['UnlockScr'] else attribute['Unlock']

                    attribute['UnlockArgs'][job['$ID']] = {
                        'UnlockArgStr': row['UnlockArgStr'],
                        'UnlockArgNum': row['UnlockArgNum'],
                    }
def parse_equipment():
    logging.debug('Parsing equipment...')

    LUA = luautil.load_script('item_calculate.lua', [
        'GET_COMMON_PROP_LIST',
        'GET_BASIC_ATK',
        'GET_BASIC_MATK',
        'INIT_ARMOR_PROP',
        'INIT_WEAPON_PROP',
        'SCR_GET_ITEM_GRADE_RATIO',
        'SCR_REFRESH_ACC',
        'SCR_REFRESH_ARMOR',
        'SCR_REFRESH_HAIRACC',
        'SCR_REFRESH_WEAPON',
        'GET_REINFORCE_ADD_VALUE_ATK',
        'GET_REINFORCE_ADD_VALUE',
        'GET_REINFORCE_PRICE',
    ])
    LUA_REINFORCE = luautil.load_script('lib_reinforce_131014.lua', ['GET_REINFORCE_PRICE'])
    LUA_TRANSCEND = luautil.load_script('item_transcend_shared.lua', ['GET_TRANSCEND_MATERIAL_COUNT'])

    ies_path = os.path.join(constants.PATH_INPUT_DATA, 'ies.ipf', 'item_equip.ies')
    ies_file = open(ies_path, 'rb')
    ies_reader = csv.DictReader(ies_file, delimiter=',', quotechar='"')

    for row in ies_reader:
        if int(row['ClassID']) not in globals.equipment:
            continue

        item_grade = equipment_grade_ratios[int(row['ItemGrade'])]
        item_type_equipment = TOSEquipmentType.value_of(row['ClassType'].upper())
        obj = globals.equipment[int(row['ClassID'])]

        # Calculate all properties using in-game formulas
        tooltip_script = row['RefreshScp']
        tooltip_script = 'SCR_REFRESH_ACC' if not tooltip_script and 'Accessory_' in row['MarketCategory'] else tooltip_script
        tooltip_script = 'SCR_REFRESH_ARMOR' if not tooltip_script and 'Armor_' in row['MarketCategory'] else tooltip_script
        tooltip_script = 'SCR_REFRESH_HAIRACC' if not tooltip_script and 'HairAcc_' in row['MarketCategory'] else tooltip_script
        tooltip_script = 'SCR_REFRESH_WEAPON' if not tooltip_script and ('Weapon_' in row['MarketCategory'] or 'ChangeEquip_' in row['MarketCategory']) else tooltip_script

        if tooltip_script:
            try:
                LUA[tooltip_script](row)
            except LuaError as error:
                if row['ClassID'] not in ['11130', '635061']:
                    logging.error('LUA error when processing item ClassID: %s', row['ClassID'])
                    raise error

        # Add additional fields
        obj['AnvilATK'] = []
        obj['AnvilDEF'] = []
        obj['AnvilPrice'] = []
        obj['Bonus'] = []
        obj['Durability'] = int(row['MaxDur']) / 100
        obj['Durability'] = -1 if obj['Durability'] <= 0 else obj['Durability']
        obj['Grade'] = TOSEquipmentGrade.value_of(int(row['ItemGrade']))
        obj['Level'] = int(row['ItemLv']) if int(row['ItemLv']) > 0 else int(row['UseLv'])
        obj['Material'] = TOSEquipmentMaterial.value_of(row['Material'])
        obj['Potential'] = int(row['MaxPR'])
        obj['RequiredClass'] = '%s%s%s%s%s' % (
            'T' if any(j in row['UseJob'] for j in ['All', 'Char3']) else 'F',  # Archer
            'T' if any(j in row['UseJob'] for j in ['All', 'Char4']) else 'F',  # Cleric
            'T' if any(j in row['UseJob'] for j in ['All', 'Char5']) else 'F',  # Scout
            'T' if any(j in row['UseJob'] for j in ['All', 'Char1']) else 'F',  # Swordsman
            'T' if any(j in row['UseJob'] for j in ['All', 'Char2']) else 'F',  # Wizard
        )
        obj['RequiredLevel'] = int(row['UseLv'])
        obj['Sockets'] = int(row['BaseSocket'])
        obj['SocketsLimit'] = int(row['MaxSocket_COUNT'])
        obj['Stars'] = int(row['ItemStar'])
        obj['Stat_ATTACK_MAGICAL'] = int(row['MATK']) if 'MATK' in row else 0
        obj['Stat_ATTACK_PHYSICAL_MIN'] = int(row['MINATK']) if 'MINATK' in row else 0
        obj['Stat_ATTACK_PHYSICAL_MAX'] = int(row['MAXATK']) if 'MAXATK' in row else 0
        obj['Stat_DEFENSE_MAGICAL'] = int(row['MDEF']) if 'MDEF' in row else 0
        obj['Stat_DEFENSE_PHYSICAL'] = int(row['DEF']) if 'DEF' in row else 0
        obj['TranscendPrice'] = []
        obj['TypeAttack'] = TOSAttackType.value_of(row['AttackType'])
        obj['TypeEquipment'] = item_type_equipment
        obj['Unidentified'] = int(row['NeedAppraisal']) == 1
        obj['UnidentifiedRandom'] = int(row['NeedRandomOption']) == 1

        obj['Link_Set'] = None

        # HotFix: if it's a Rapier, use THRUST as the TypeAttack
        if obj['TypeEquipment'] == TOSEquipmentType.RAPIER:
            obj['TypeAttack'] = TOSAttackType.MELEE_THRUST

        # HotFix: in case it doesn't give physical nor magical defense (e.g. agny necklace)
        if 'ADD_FIRE' in row['BasicTooltipProp'].split(','):
            lv = obj['Level']
            gradeRatio = (int(item_grade['BasicRatio']) / 100.0)

            row['ADD_FIRE'] = floor(lv * gradeRatio)

        # Anvil
        if any(prop in row['BasicTooltipProp'] for prop in ['ATK', 'DEF', 'MATK', 'MDEF']):
            for lv in range(40):
                row['Reinforce_2'] = lv

                if any(prop in row['BasicTooltipProp'] for prop in ['DEF', 'MDEF']):
                    obj['AnvilDEF'].append(LUA['GET_REINFORCE_ADD_VALUE'](None, row, 0, 1))
                    obj['AnvilPrice'].append(LUA_REINFORCE['GET_REINFORCE_PRICE'](row, {}, None))
                if any(prop in row['BasicTooltipProp'] for prop in ['ATK', 'MATK']):
                    obj['AnvilATK'].append(LUA['GET_REINFORCE_ADD_VALUE_ATK'](row, 0, 1, None))
                    obj['AnvilPrice'].append(LUA_REINFORCE['GET_REINFORCE_PRICE'](row, {}, None))

        obj['AnvilPrice'] = [value for value in obj['AnvilPrice'] if value > 0]
        obj['AnvilATK'] = [value for value in obj['AnvilATK'] if value > 0] if len(obj['AnvilPrice']) > 0 else None
        obj['AnvilDEF'] = [value for value in obj['AnvilDEF'] if value > 0] if len(obj['AnvilPrice']) > 0 else None

        # Bonus
        for stat in EQUIPMENT_STAT_COLUMNS:
            if stat in row:
                value = floor(float(row[stat]))

                if value != 0:
                    obj['Bonus'].append([
                        TOSEquipmentStat.value_of(stat),    # Stat
                        value                               # Value
                    ])

        # More Bonus
        if 'OptDesc' in row and len(row['OptDesc']) > 0:
            for bonus in parser_translations.translate(row['OptDesc']).split('{nl}'):
                bonus = bonus.strip()
                bonus = bonus[bonus.index('-'):] if '-' in bonus else bonus

                obj['Bonus'].append([
                    TOSEquipmentStat.UNKNOWN,           # Stat
                    bonus.replace('- ', '').strip()     # Value
                ])

        # Transcendence
        for lv in range(10):
            row['Transcend'] = lv
            obj['TranscendPrice'].append(LUA_TRANSCEND['GET_TRANSCEND_MATERIAL_COUNT'](row, None))

        obj['TranscendPrice'] = [value for value in obj['TranscendPrice'] if value > 0]