def parse(lines, filename, headings=None): """ headings: Specify the headings explicitly. Otherwise they are read from the first line in the file. """ reader = csv.reader(lines, dialect=ParadoxDialect) if headings is None: headings = next(reader) result = pyradox.Tree() for row_index, row_tokens in enumerate(reader): if len(row_tokens) == 0: continue # skip blank lines if len(row_tokens) != len(headings): warnings.warn_explicit( 'Row length (%d) should be same as headings length (%d).' % (len(row_tokens), len(headings)), ParseWarning, filename, row_index + 2) # first column is the key key = pyradox.token.make_primitive(row_tokens[0], default_token_type='str') tree_row = pyradox.Tree() result.append(key, tree_row) for col_index in range(min(len(headings), len(row_tokens))): heading = headings[col_index] row_token = row_tokens[col_index] value = pyradox.token.make_primitive(row_token, default_token_type='str') tree_row.append(heading, value) return result
def get_hulls(beta = False): game = 'HoI4_beta' if beta else 'HoI4' equipments = pyradox.parse_merge('common/units/equipment', game = game, filter_pattern = "ship_hull", merge_levels = 1)['equipments'] archetypes = pyradox.Tree() # Compute archetypes. for key, hull in equipments.items(): if hull['is_archetype']: hull = copy.deepcopy(hull) hull['module_slots'].resolve_references() archetypes[key] = hull hulls = pyradox.Tree() # Compute final hulls. for key, hull in equipments.items(): if hull['is_buildable'] is False: continue hull = copy.deepcopy(hull) archetype = archetypes[hull['archetype']] hull.inherit(archetype) hull.weak_update(archetype) if 'parent' in hull: parent = hulls[hull['parent']] hull.inherit(parent) hull['module_slots'].resolve_references() hull['is_archetype'] = False hull['is_buildable'] = True hulls[key] = hull return archetypes, hulls
def compute_effects(k, v): result = '<ul>' def equipment_bonus(equipment_bonuses): result = '' for equipment_type, effects in equipment_bonuses.items(): equipment_type_name = ( pyradox.yml.get_localisation(equipment_type, game='HoI4') or pyradox.format.human_title(equipment_type) or pyradox.format.human_title(equipment_type)) for effect_key, magnitude in effects.items(): effect_name = pyradox.yml.get_localisation( 'modifier_' + effect_key, game='HoI4') or pyradox.format.human_title(effect_key) magnitude_string = compute_magnitude_string( effect_key, magnitude) result += '<li>%s %s: %s</li>' % ( equipment_type_name, effect_name, magnitude_string) return result if 'research_bonus' in v: for category, magnitude in v['research_bonus'].items(): category_string = pyradox.yml.get_localisation( category + '_research', game='HoI4') or (pyradox.format.human_title(category) + ' Research Time') magnitude_string = compute_magnitude_string( category, -magnitude, False) result += '<li>%s: %s</li>' % (category_string, magnitude_string) if 'equipment_bonus' in v: result += equipment_bonus(v['equipment_bonus']) for trait_key in v.find_all('traits'): trait = traits[trait_key] subresult = '' for effect_key, magnitude in trait.items(): if effect_key in ['sprite', 'random', 'ai_will_do']: continue elif effect_key == 'equipment_bonus': subresult += equipment_bonus(magnitude) else: effect_name = pyradox.yml.get_localisation( 'modifier_' + effect_key, game='HoI4') or pyradox.format.human_title(effect_key) magnitude_string = compute_magnitude_string( effect_key, magnitude) subresult += '<li>%s: %s</li>' % (effect_name, magnitude_string) if trait_key not in trait_result.keys(): row = pyradox.Tree() row['name'] = pyradox.yml.get_localisation(trait_key, game='HoI4').replace( '\\n', ' ') row['type'] = v['type'] row['text'] = '<ul>' + subresult + '</ul>' trait_result[trait_key] = row result += subresult result += '</ul>' return result
def make_ship(hull, design): ship = copy.deepcopy(hull) ship['design_modules'] = pyradox.Tree() for slot_key, module_key, module in design: ship['design_modules'].append(slot_key, module_key) # resource costs for slot_key, module_key,module in design: if 'build_cost_resources' in module: for resource, amount in module['build_cost_resources'].items(): ship['resources'][resource] = ( (ship['resources'][resource] or 0) + amount) ship['total_resources'] = sum(ship['resources'].values()) # add_stats for slot_key, module_key, module in design: if 'add_stats' in module: for stat, amount in module['add_stats'].items(): ship[stat] = (ship[stat] or 0) + amount # average stats average_dict = {} for slot_key, module_key, module in design: if 'add_average_stats' in module: for stat, amount in module['add_average_stats'].items(): if stat in average_dict: prev_total, prev_count = average_dict[stat] else: prev_total, prev_count = 0.0, 0 average_dict[stat] = (prev_total + amount, prev_count + 1) for stat, (total, count) in average_dict.items(): ship[stat] = (ship[stat] or 0) + total / count # multiply stats multiply_dict = {} for slot_key, module_key, module in design: if 'multiply_stats' in module: for stat, amount in module['multiply_stats'].items(): if stat not in multiply_dict: multiply_dict[stat] = 0.0 multiply_dict[stat] += amount for stat, amount in multiply_dict.items(): ship[stat] *= (1.0 + amount) return ship
def __init__(self, token_data, filename, start_pos, is_top_level): self.token_data = token_data # The tokenized version of the file. List of (token_type, token_string, token_line_number) tuples. self.filename = filename # File the tree is being parsed from. Used for warning and error messages. self.is_top_level = is_top_level # True iff this tree is the top level of the file. self.result = pyradox.Tree() # The resulting tree. self.pos = start_pos # Current token position. self.pending_comments = [] # Comments pending assignment. self.key = None # The key currently being processed. self.key_string = None # The original token string for that key. self.operator = None # The operator currently being processed. Usually '='. self.in_group = False # Whether the parser is currently inside a group. self.next = self.process_key # The next case to execute.
def parse_merge(path, game=None, filter_pattern = None, merge_levels = 0, apply_defines = False, *args, **kwargs): """Given a directory, return a Tree as if all .txt files in the directory were a single file""" path, game = pyradox.config.combine_path_and_game(path, game) result = pyradox.Tree() for filename in os.listdir(path): fullpath = os.path.join(path, filename) if os.path.isfile(fullpath): if should_parse(fullpath, filename, filter_pattern): tree = parse_file(fullpath, game = game, *args, **kwargs) if apply_defines: tree = tree.apply_defines() result.merge(tree, merge_levels) return result
def generate_row(decision_id, decision): row = pyradox.Tree() row['id'] = decision_id if 'has_tech' in decision['available']: tech = decision['available']['has_tech'] row['tech_type'] = tech[:-1] row['tech_level'] = tech[-1] else: row['tech_type'] = '' row['tech_level'] = '' row['cic'] = decision['modifier']['civilian_factory_use'] if isinstance(decision['days_remove'], int): row['time'] = decision['days_remove'] else: # TODO: determine from code? row['time'] = 30 if 'fire_only_once' in decision: pass else: row['repeatable'] = decision['visible'].find('value', recurse=True, default=1) for effect_key, effect in decision['remove_effect'].items(): if not isinstance(effect_key, int): continue if 'add_resource' in effect: row['state'] = effect_key row['resource'] = effect['add_resource']['type'] row['amount'] = effect['add_resource']['amount'] row['state_name'] = hoi4.state.get_state_name(row['state']) row['owner_name'] = hoi4.state.get_state_owner(row['state'])['name'] row['cost'] = row['cic'] * row['time'] * 5 return row
import re import os import pyradox def compute_country_tag_and_name(filename): m = re.match('.*([A-Z]{3})\s*-\s*(.*)\.txt$', filename) return m.group(1), m.group(2) economics = pyradox.txt.parse_file( os.path.join(pyradox.get_game_directory('HoI4'), 'common', 'ideas', '_economic.txt'))['ideas'] result = pyradox.Tree() for filename, country in pyradox.txt.parse_dir( os.path.join(pyradox.get_game_directory('HoI4'), 'history', 'countries')): country = country.at_time('1936.1.1') tag, name = compute_country_tag_and_name(filename) country['tag'] = tag ruling_party = country['set_politics']['ruling_party'] country['name'] = pyradox.yml.get_localisation('%s_%s' % (tag, ruling_party), game='HoI4') result[tag] = country if 'add_ideas' in country: for idea in country['add_ideas']:
elif key == 'max_level': max_level = value elif 'level_cost_' in key: level = int(key[len('level_cost_'):]) if level <= 2: costs[level - 1] = value else: bonus_key = key base_value = value bonuses[bonus_key] = (power_type, base_value, max_level, tuple(costs)) result = '{|class = "wikitable sortable"\n' result += '! Idea group !! Linear cost !! Base cost !! Adjusted for<br/>early ideas !! Max level ratio !! Final cost !! Bonuses unaccounted for\n' result_tree = pyradox.Tree() for file_name, file_data in pyradox.txt.parse_dir( os.path.join(pyradox.get_game_directory('EU4'), 'common', 'ideas')): for idea_set_name, idea_set in file_data.items(): index = 0 base_cost = 0.0 early_cost = 0.0 total_linear_cost = 0.0 unaccounted = [] # not appearing in designer level_counts = { 'adm': 0.0, 'dip': 0.0, 'mil': 0.0, }
def units_at_year(year): units = hoi4.load.get_units() # archetype_key -> best equipment equipment_models = {} for unit_key, unit_data in units.items(): unit_data["year"] = year unit_data["last_upgrade"] = default_year if "active" not in unit_data.keys(): unit_data["active"] = True for tech_key, tech in techs.items(): if not isinstance(tech, pyradox.Tree): continue if (tech["start_year"] or year) > year: continue if 'folder' in tech and 'doctrine' in tech['folder']['name']: continue # ignore doctrines if "enable_subunits" in tech: for unit_key in tech.find_all("enable_subunits"): units[unit_key]["active"] = True units[unit_key]["last_upgrade"] = max( units[unit_key]["last_upgrade"], tech["start_year"]) if tech["allow"] and tech["allow"]["always"] == False: continue # ignore unallowed techs, but allow subunits through if "enable_equipments" in tech: for equipment_key in tech.find_all("enable_equipments"): equipment = equipments[equipment_key] if "archetype" in equipment: archetype_key = equipment["archetype"] equipment_models[archetype_key] = equipments[equipment_key] equipment_models[equipment_key] = equipments[equipment_key] # TODO: drop ordering assumption? # non-equipment modifiers for unit_key, unit_data in units.items(): for tech_unit_key, stats in tech.items(): if tech_unit_key == unit_key or tech_unit_key in unit_data.find_all( 'categories'): units[unit_key]["last_upgrade"] = max( units[unit_key]["last_upgrade"], tech["start_year"]) for stat_key, stat_value in stats.items(): if (not type(stat_value) is pyradox.Tree): unit_data[stat_key] = (unit_data[stat_key] or 0.0) + stat_value # fill in equipment for unit_key, unit_data in units.items(): unit_data["equipments"] = pyradox.Tree() for archetype_key in unit_data["need"]: if archetype_key in equipment_models: equipment = equipment_models[archetype_key] unit_data["equipments"][archetype_key] = equipment unit_data["last_upgrade"] = max(unit_data["last_upgrade"], equipment["year"]) if not equipments[archetype_key]["is_archetype"]: print( "Warning: non-archetype equipment %s defined for %s" % (archetype_key, unit_key)) else: unit_data["equipments"][archetype_key] = False return units
import _initpath import os import pyradox result_tree = pyradox.Tree() for group_name, group_data in pyradox.txt.parse_merge( os.path.join(pyradox.get_game_directory('EU4'), 'common', 'ideas')).items(): if 'trigger' not in group_data: continue trigger = group_data['trigger'] for tag in trigger.find_all('tag'): result_tree[tag] = group_name if 'or' in trigger: for tag in trigger['or'].find_all('tag'): result_tree[tag] = group_name outfile = open('out/idea_map.txt', mode='w') outfile.write(str(result_tree)) outfile.close()
commander_type_keys = { 'create_field_marshal': 'Field Marshal', 'create_corps_commander': 'General', 'create_navy_leader': 'Admiral', } columns = ( ('Country', '{{flag|%(country)s}}', None), ('Name', '%(name)s', None), ('Type', lambda k, v: commander_type_keys[k], None), ('Skill', '%(skill)d', None), ('Traits', list_commander_traits, None), ) commanders = pyradox.Tree() for filename, country in pyradox.txt.parse_dir( os.path.join(pyradox.get_game_directory('HoI4'), 'history', 'countries')): tag, _ = compute_country_tag_and_name(filename) ruling_party = country['set_politics']['ruling_party'] country_name = pyradox.yml.get_localisation('%s_%s' % (tag, ruling_party), game='HoI4') for commander_type_key in commander_type_keys.keys(): for leader in country.find_all(commander_type_key): leader['country'] = country_name commanders.append(commander_type_key, leader) out = open("out/military_commanders.txt", "w", encoding="utf-8") out.write(
import hoi4 import re import os import hoi4 import pyradox game = 'HoI4' def compute_country_tag_and_name(filename): m = re.match('.*([A-Z]{3})\s*-\s*(.*)\.txt$', filename) return m.group(1), m.group(2) countries = {} total = pyradox.Tree() for filename, country in pyradox.txt.parse_dir(os.path.join(pyradox.get_game_directory('HoI4'), 'history', 'countries')): tag, name = compute_country_tag_and_name(filename) country['tag'] = tag ruling_party = country['set_politics']['ruling_party'] or 'neutrality' country['name'] = pyradox.yml.get_localisation('%s_%s' % (tag, ruling_party), game = 'HoI4') countries[tag] = country states = pyradox.txt.parse_merge(os.path.join(pyradox.get_game_directory('HoI4'), 'history', 'states')) state_categories = pyradox.txt.parse_merge(os.path.join(pyradox.get_game_directory(game), 'common', 'state_category'), verbose=False, merge_levels = 1) state_categories = state_categories['state_categories'] for state in states.values():
import _initpath import pyradox import os import copy import math import stellaris.weapon csv_data = pyradox.csv.parse_file( ['common', 'component_templates', 'weapon_components.csv'], game='Stellaris') txt_data = pyradox.parse_merge(['common', 'component_templates'], game='Stellaris') total_data = pyradox.Tree() for weapon in txt_data.find_all('weapon_component_template'): if weapon['hidden']: continue key = weapon['key'] total_data[key] = weapon + csv_data[key] column_specs = [ ('Weapon/Role', stellaris.weapon.icon_and_name_and_role), ('Size', stellaris.weapon.slot_string), ('{{icon|minerals}}<br/>Cost', '%(cost)d'), ('{{icon|power}}<br/>Power', lambda k, v: str(abs(v['power']))), ('{{icon|damage}}<br/>Average<br/>damage', lambda k, v: '%0.1f' % stellaris.weapon.average_damage(v)), ('{{icon|time}}<br/>Cooldown', '%(cooldown)d'), ('{{icon|weapons range}}<br/>Range', '%(range)d'),
'theorist', ] military_chief_types = [ 'army_chief', 'navy_chief', 'air_chief', ] military_high_command_types = [ 'high_command', ] types_to_tabulate = military_chief_types result = pyradox.Tree() idea_data = pyradox.txt.parse_merge(os.path.join( pyradox.get_game_directory('HoI4'), 'common', 'ideas'), merge_levels=2)['ideas'] for idea_type in types_to_tabulate: ideas = idea_data[idea_type] type_name = pyradox.yml.get_localisation(idea_type, game='HoI4') for idea_key, idea in ideas.items(): if idea_key == 'designer': continue row = pyradox.Tree() row['type'] = type_name if 'allowed' not in idea: row['country'] = 'Generic' elif 'tag' in idea['allowed']:
import hoi4 import pyradox import os.path import json all_years = pyradox.Tree() unit_type = 'land' for year in hoi4.unitstats.unit_type_years[unit_type]: units = hoi4.unitstats.units_at_year(year) all_years += units with open("out/%s_units_by_year.txt" % unit_type, "w") as out_file: columns = [("Unit", hoi4.unitstats.compute_unit_name) ] + hoi4.unitstats.base_columns[unit_type] + [ ("Unit", hoi4.unitstats.compute_unit_name) ] tables = { year: pyradox.Tree() for year in hoi4.unitstats.unit_type_years[unit_type] } for unit_key, unit in all_years.items(): if unit["year"] in hoi4.unitstats.unit_type_years[ unit_type] and hoi4.unitstats.compute_unit_type( unit) == unit_type and hoi4.unitstats.is_availiable(unit): tables[unit["year"]].append(unit_key, unit) for year in hoi4.unitstats.unit_type_years[unit_type]: out_file.write("== %d ==\n" % year) out_file.write(
territory_costs[province['owner']] += province_cost(province) result = '{|class = "wikitable sortable"\n' result += '! Country !! Tag !! Territory cost !! Ruler cost !! Government cost !! Technology cost !! Total cost \n' for tag in sorted(government_costs.keys()): if territory_costs[tag] == 0: continue result += '|-\n' total_cost = sum(government_costs[tag]) + territory_costs[tag] result += '| %s || %s || %d || %0.1f || %d || %d || %d \n' % ( load.country.get_country_name(tag), tag, territory_costs[tag], government_costs[tag][0], government_costs[tag][1], government_costs[tag][2], total_cost) result += '|}\n' print(result) result_tree = pyradox.Tree() for tag in sorted(government_costs.keys()): nation_tree = pyradox.Tree() nation_tree['territory'] = territory_costs[tag] nation_tree['ruler'] = government_costs[tag][0] nation_tree['government'] = government_costs[tag][1] nation_tree['technology'] = government_costs[tag][2] result_tree[tag] = nation_tree outfile = open('out/non_idea_costs.txt', mode = 'w') outfile.write(str(result_tree)) outfile.close()
import _initpath import pyradox import os import copy import math import stellaris.weapon txt_data = pyradox.parse_merge(['common', 'component_templates'], game='Stellaris', apply_defines=True) default_values = pyradox.Tree() default_values['hull_damage'] = 1.0 default_values['armor_damage'] = 1.0 default_values['shield_damage'] = 1.0 default_values['armor_penetration'] = 0.0 default_values['shield_penetration'] = 0.0 default_values['tracking'] = 0.0 default_values['prerequisites'] = 'Ship part strike craft scout 1' result_data = pyradox.Tree() for strike_craft in txt_data.find_all('strike_craft_component_template'): if strike_craft['hidden']: continue key = strike_craft['key'] strike_craft.weak_update(default_values) strike_craft['size'] = 'hangar' result_data[key] = strike_craft column_specs = [ ('Weapon/Role', stellaris.weapon.icon_and_name_and_role),
row['state'] = effect_key row['resource'] = effect['add_resource']['type'] row['amount'] = effect['add_resource']['amount'] row['state_name'] = hoi4.state.get_state_name(row['state']) row['owner_name'] = hoi4.state.get_state_owner(row['state'])['name'] row['cost'] = row['cic'] * row['time'] * 5 return row # Load resource decisions. decisions = pyradox.txt.parse_file( ['common', 'decisions', 'resource_prospecting.txt'], game=game) table = pyradox.Tree() for decision_id, decision in decisions['prospect_for_resources'].items(): row = generate_row(decision_id, decision) table.append(decision_id, row) columns = ( ('State', '%(state_name)s'), ('Owner (1936)', '{{flag|%(owner_name)s}}'), ('Tech type', '%(tech_type)s'), ('Tech level', '%(tech_level)s'), ('{{icon|cic}}', '%(cic)s'), ('{{icon|time}}', '%(time)s'), ('{{icon|construction cost}}', '%(cost)d'), ('Resource', '{{icon|%(resource)s}} %(resource)s'), ('Amount', '%(amount)d'),
import pyradox from unitstats import * files = {} for unit_type in base_columns.keys(): files[unit_type] = open("out/%s_units_by_unit.txt" % unit_type, "w") unit_data = {} for year in range(1936, 1948): unit_data[year] = units_at_year(year) by_unit = pyradox.Tree() for year, data in unit_data.items(): for unit, stats in data.items(): if unit not in by_unit.keys(): by_unit[unit] = pyradox.Tree() by_unit[unit][year] = stats for unit_type, unit_file in files.items(): for unit, data in by_unit.items(): if data[1936]["type"] != unit_type: continue unit_file.write("== %s ==\n" % pyradox.format.human_string(unit, True)) unit_file.write(pyradox.table.make_table(data, 'wiki', base_columns[unit_type], lambda k, v: v["active"])) unit_file.write("=== Derived statistics ===\n") unit_file.write(pyradox.table.make_table(data, 'wiki', derived_columns[unit_type], lambda k, v: v["active"])) for unit_file in files.values():
import _initpath import os import re import collections import pyradox import pyradox start_date = pyradox.Date('1444.11.11') counts = pyradox.Tree() # province counts # parse all files in a directory, producing instances of pyradox.Tree for filename, data in pyradox.txt.parse_dir(os.path.join(pyradox.get_game_directory('EU4'), 'history', 'provinces')): # pyradox.Tree has many dict methods, such as .keys() if 'base_tax' not in data.keys(): continue trade_good = 'unknown' for curr_good in data.find_walk('trade_goods'): if curr_good != 'unknown': trade_good = curr_good if trade_good not in counts: counts[trade_good] = 1 else: counts[trade_good] += 1 print([(key, counts[key]) for key in counts.keys()])
('ship_hull_pre_dreadnought', 'heavy_then_light', 1932), ('ship_hull_super_heavy_1', 'heavy_then_light', 1940), ('ship_hull_super_heavy_1', 'heavy_then_light', 1944), ('ship_hull_submarine_1', 'torpedo', 1932), ('ship_hull_submarine_2', 'torpedo', 1936), ('ship_hull_submarine_3', 'torpedo', 1940), ('ship_hull_submarine_4', 'torpedo', 1944), ('ship_hull_cruiser_submarine', 'torpedo', 1940), ('ship_hull_carrier_1', 'carrier_fast', 1936), ('ship_hull_carrier_2', 'carrier_fast', 1940), ('ship_hull_carrier_3', 'carrier_fast', 1944), ('ship_hull_carrier_conversion_ca', 'carrier_fast', 1936), ('ship_hull_carrier_conversion_bb', 'carrier_fast', 1936), ] models = pyradox.Tree() for hull_key, strategy_key, year in model_specs: hull = hulls[hull_key] strategy = strategies[strategy_key] ship = design_ship(hull, strategy, year=year) ship['model_year'] = year model_key = '%s, %s, %d' % (hull_key, strategy_key, year) ship['model_id'] = model_key models[model_key] = ship print('List of hulls:') for hull_key in hulls: if 'hull' in hull_key: print(hull_key)