def log_planets(): universe = fo.get_universe() planets_table = Table([ Text('id'), Text('name'), Text('system'), Text('type'), Sequence('specials'), Text('species'), Sequence('buildings') ], table_name='Planets summary') # group planets by system for sid in fo.get_systems(): for pid in fo.sys_get_planets(sid): planet = universe.getPlanet(pid) planet_type = fo.planet_get_type(pid).name planet_size = fo.planet_get_size(pid).name if planet_type != planet_size: planet_type = '%s %s' % (planet_type, planet_size) buildings = [ universe.getBuilding(x).name for x in planet.buildingIDs ] planets_table.add_row([ pid, planet.name, planet.systemID, planet_type, list(planet.specials), planet.speciesName, buildings ]) # Printing too much info at once will lead to truncation of text for line in planets_table.get_table().split('\n'): print line
def handle_interfaces_mismatch(): """ Handle cases when AI and universe generation interfaces mismatch. """ try: import freeorion as fo universe = fo.get_universe() empire_of_first_ai = fo.get_empire(2) galaxy_data = fo.get_galaxy_setup_data() return fo, universe, empire_of_first_ai, galaxy_data except ImportError: pass try: import freeOrionAIInterface as fo universe = fo.getUniverse() empire_of_first_ai = fo.getEmpire(2) galaxy_data = fo.getGalaxySetupData() return fo, universe, empire_of_first_ai, galaxy_data except ImportError: pass
def log_planets(): universe = fo.get_universe() planets_table = Table( [Text('id'), Text('name'), Text('system'), Text('type'), Sequence('specials'), Text('species'), Sequence('buildings')], table_name='Planets summary') # group planets by system for sid in fo.get_systems(): for pid in fo.sys_get_planets(sid): planet = universe.getPlanet(pid) planet_type = fo.planet_get_type(pid).name planet_size = fo.planet_get_size(pid).name if planet_type != planet_size: planet_type = '%s %s' % (planet_type, planet_size) buildings = [universe.getBuilding(x).name for x in planet.buildingIDs] planets_table.add_row([ pid, planet.name, planet.systemID, planet_type, list(planet.specials), planet.speciesName, buildings ]) # Printing too much info at once will lead to truncation of text for line in planets_table.get_table().split('\n'): print line
def inspect_universe_generation_interface(*args, **kwargs): import freeorion as fo tech = fo.getTech('LRN_NASCENT_AI') universe = fo.get_universe() empire = fo.get_empire(1) rules = fo.getGameRules() ship_hull = fo.getShipHull('SH_XENTRONIUM') species = fo.getSpecies('SP_ABADDONI') generate_stub( fo, instances=[ fo.getFieldType('FLD_ION_STORM'), fo.getBuildingType('BLD_SHIPYARD_BASE'), ship_hull, ship_hull.slots, fo.getShipPart('SR_WEAPON_1_1'), fo.getSpecial('MODERATE_TECH_NATIVES_SPECIAL'), species, fo.diplomaticMessage(1, 2, fo.diplomaticMessageType.acceptPeaceProposal), rules, tech, tech.unlockedItems, universe, universe.effectAccounting, universe.buildingIDs, fo.get_galaxy_setup_data(), empire, empire.colour, empire.productionQueue, empire.researchQueue, ], classes_to_ignore=( 'IntBoolMap', 'IntDblMap', 'IntFltMap', 'IntIntMap', 'IntPairVec', 'IntSetSet', 'MeterTypeAccountingInfoVecMap', 'MeterTypeMeterMap', 'MeterTypeStringPair', 'MonsterFleetPlan', 'PairIntInt_IntMap', 'RuleValueStringStringPair', 'ShipPartMeterMap', 'VisibilityIntMap', 'AccountingInfoVec', 'IntSet', 'StringSet', 'StringVec', ), path=".", dump=False, )
def log_systems(): universe = fo.get_universe() systems_table = Table( [Text('id'), Text('name'), Sequence('planets'), Sequence('connections'), Text('star')], table_name='System summary') for sid in fo.get_systems(): system = universe.getSystem(sid) systems_table.add_row([ sid, system.name, fo.sys_get_planets(sid), fo.sys_get_starlanes(sid), system.starType.name ]) # Printing too much info at once will lead to truncation of text for line in systems_table.get_table().split('\n'): print(line)
def log_systems(): universe = fo.get_universe() systems_table = Table( [Text('id'), Text('name'), Sequence('planets'), Sequence('connections'), Text('star')], table_name='System summary') for sid in fo.get_systems(): system = universe.getSystem(sid) systems_table.add_row([ sid, system.name, fo.sys_get_planets(sid), fo.sys_get_starlanes(sid), system.starType.name ]) # Printing too much info at once will lead to truncation of text for line in systems_table.get_table().split('\n'): print line
def inspect_universe_generation_interface(*args, **kwargs): import freeorion as fo universe = fo.get_universe() # this field should be visible to AI empire_of_first_ai = fo.get_empire(2) # first AI fo.create_field_in_system( "FLD_NEBULA_1", 100, universe.getPlanet(empire_of_first_ai.capitalID).systemID) instances = list(get_item_with_location(get_common_instances())) generate_stub( fo, instances=instances, classes_to_ignore=classes_to_exclude_from_universe, path=".", dump=False, )
def log_systems(): universe = fo.get_universe() systems_table = Table( Text("id"), Text("name"), Sequence("planets"), Sequence("connections"), Text("star"), table_name="System summary", ) for sid in fo.get_systems(): system = universe.getSystem(sid) systems_table.add_row( sid, system.name, fo.sys_get_planets(sid), fo.sys_get_starlanes(sid), system.starType.name, ) systems_table.print_table(print)
def inspect_universe_generation_interface(*args, **kwargs): import freeorion as fo tech = fo.getTech('LRN_ARTIF_MINDS') universe = fo.get_universe() empire = fo.get_empire(1) rules = fo.getGameRules() hull_type = fo.getHullType('SH_XENTRONIUM') species = fo.getSpecies('SP_ABADDONI') inspect( fo, instances=[ fo.getFieldType('FLD_ION_STORM'), fo.getBuildingType('BLD_SHIPYARD_BASE'), hull_type, hull_type.slots, fo.getPartType('SR_WEAPON_1_1'), fo.getSpecial('MODERATE_TECH_NATIVES_SPECIAL'), species, fo.diplomaticMessage(1, 2, fo.diplomaticMessageType.acceptPeaceProposal), rules, tech, tech.unlockedItems, rules.getRulesAsStrings, universe, universe.effectAccounting, universe.buildingIDs, fo.get_galaxy_setup_data(), empire, empire.colour, empire.productionQueue, empire.researchQueue, ], classes_to_ignore=( 'IntBoolMap', 'IntDblMap', 'IntFltMap', 'IntIntMap', 'IntPairVec', 'IntSetSet', 'MeterTypeAccountingInfoVecMap', 'MeterTypeMeterMap', 'MeterTypeStringPair', 'MonsterFleetPlan', 'PairIntInt_IntMap', 'RuleValueStringStringPair', 'ShipPartMeterMap', 'VisibilityIntMap', 'AccountingInfoVec', 'IntSet', 'StringSet', 'StringVec', ), path=".", )
def log_planets(): universe = fo.get_universe() planets_table = Table( Text("id"), Text("name"), Text("system"), Text("type"), Sequence("specials"), Text("species"), Sequence("buildings"), table_name="Planets summary", ) # group planets by system for sid in fo.get_systems(): for pid in fo.sys_get_planets(sid): planet = universe.getPlanet(pid) planet_type = fo.planet_get_type(pid).name planet_size = fo.planet_get_size(pid).name if planet_type != planet_size: planet_type = "%s %s" % (planet_type, planet_size) buildings = [ universe.getBuilding(x).name for x in planet.buildingIDs ] planets_table.add_row( pid, planet.name, planet.systemID, planet_type, list(planet.specials), planet.speciesName, buildings, ) planets_table.print_table(print)
def inspect_universe_generation(): """ Inspect function for universe generation interface. We have no way to run it without modifying of game code. To generate interface put call before return section of universe_generation.universe_generator.create_universe function """ import freeorion as fo techs = fo.techs() universe = fo.get_universe() planet_ids = universe.planetIDs system_ids = universe.systemIDs system = universe.getSystem(system_ids[0]) building_ids = universe.buildingIDs building = universe.getBuilding(building_ids[0]) empire_ids = fo.get_all_empires() empire = fo.get_empire(empire_ids[0]) fields_ids = universe.fieldIDs field = universe.getField(fields_ids[0]) fleets_ids = universe.fleetIDs fleet = universe.getFleet(fleets_ids[0]) tech = fo.getTech(techs[0]) unlocked_items = tech.unlockedItems ship = universe.getShip(list(fleet.shipIDs)[0]) # meter = ship.getMeter(fo.meterType.maxFuel) design = ship.design universe_object = universe.getObject(universe.systemIDs[0]) # fo.getHullType ? species = None special = None planets = [universe.getPlanet(pid) for pid in planet_ids] for planet in planets: species_name = planet.speciesName if species_name: species = fo.getSpecies(species_name) specials = list(planet.specials) if specials: special = fo.getSpecial(specials[0]) inspect( fo, instances=[ fo.get_galaxy_setup_data(), universe, planet_ids, universe.getPlanet(planet_ids[0]), system, techs, tech, tech.unlockedTechs, building, fo.getBuildingType(building.buildingTypeName), empire, field, fo.getFieldType(field.fieldTypeName), fleet, ship, # meter, design, fleet.shipIDs, # int set wtf? universe_object, system.starlanesWormholes, empire.systemSupplyRanges, empire.supplyProjections(), empire.obstructedStarlanes(), empire.planetsWithWastedPP, unlocked_items, species, special ], classes_to_ignore=( 'FleetPlan', 'GGColor', 'MonsterFleetPlan', 'PlayerSetupData', 'ShipPartMeterMap', 'ShipSlotVec', 'VisibilityIntMap', 'diplomaticMessage', 'diplomaticStatusUpdate', 'meter', ), path='' ) # fo.sys_get_star_type(system), # fo.planet_get_size(pid), # fo.planet_get_type(planet), # fo.species_get_planet_environment(species, planet_type), # fo.species_preferred_focus(species), # fo.getBuildingType(string) # fo.getFieldType(string) # fo.getHullType(string) # fo.getPartType(string) # fo.getShipDesign(number) # fo.getSpecial(string) # fo.getSpecies(string) # fo.getTech(string) # fo.getTechCategories(obj) # fo.get_empire(number) # fo.planet_get_species(number) # fo.techsInCategory(string) exit(1)
def inspect_universe_generation(): """ Inspect function for universe generation interface. We have no way to run it without modifying of game code. To generate interface put call before return section of universe_generation.universe_generator.create_universe function """ import freeorion as fo techs = fo.techs() universe = fo.get_universe() planet_ids = universe.planetIDs system_ids = universe.systemIDs system = universe.getSystem(system_ids[0]) building_ids = universe.buildingIDs building = universe.getBuilding(building_ids[0]) empire_ids = fo.get_all_empires() empire = fo.get_empire(empire_ids[0]) fields_ids = universe.fieldIDs field = universe.getField(fields_ids[0]) fleets_ids = universe.fleetIDs fleet = universe.getFleet(fleets_ids[0]) tech = fo.getTech(techs[0]) unlocked_items = tech.unlockedItems ship = universe.getShip(list(fleet.shipIDs)[0]) # meter = ship.getMeter(fo.meterType.maxFuel) design = ship.design universe_object = universe.getObject(universe.systemIDs[0]) # fo.getHullType ? species = None special = None planets = [universe.getPlanet(pid) for pid in planet_ids] for planet in planets: species_name = planet.speciesName if species_name: species = fo.getSpecies(species_name) specials = list(planet.specials) if specials: special = fo.getSpecial(specials[0]) inspect( fo, instances=[ fo.get_galaxy_setup_data(), universe, planet_ids, universe.getPlanet(planet_ids[0]), system, techs, tech, tech.unlockedTechs, building, fo.getBuildingType(building.buildingTypeName), empire, field, fo.getFieldType(field.fieldTypeName), fleet, ship, # meter, design, fleet.shipIDs, # int set wtf? universe_object, system.starlanesWormholes, empire.systemSupplyRanges, empire.supplyProjections(), empire.obstructedStarlanes(), empire.planetsWithWastedPP, unlocked_items, species, special ], classes_to_ignore=( 'FleetPlan', 'GGColor', 'MonsterFleetPlan', 'PlayerSetupData', 'ShipPartMeterMap', 'ShipSlotVec', 'VisibilityIntMap', 'diplomaticMessage', 'diplomaticStatusUpdate', 'meter', ), path='') # fo.sys_get_star_type(system), # fo.planet_get_size(pid), # fo.planet_get_type(planet), # fo.species_get_planet_environment(species, planet_type), # fo.species_preferred_focus(species), # fo.getBuildingType(string) # fo.getFieldType(string) # fo.getHullType(string) # fo.getShipPart(string) # fo.getShipDesign(number) # fo.getSpecial(string) # fo.getSpecies(string) # fo.getTech(string) # fo.getTechCategories(obj) # fo.get_empire(number) # fo.planet_get_species(number) # fo.techsInCategory(string) exit(1)
def generate_monsters(monster_freq, systems): """ Adds space monsters to systems. """ # first, calculate the basic chance for monster generation in a system # based on the monster frequency that has been passed # get the corresponding value for the specified monster frequency from the universe tables basic_chance = universe_tables.MONSTER_FREQUENCY[monster_freq] # a value of 0 means no monsters, in this case return immediately if basic_chance <= 0: return print "Default monster spawn chance:", basic_chance expectation_tally = 0.0 actual_tally = 0 # get all monster fleets that have a spawn rate and limit both > 0 and at least one monster ship design in it # (a monster fleet with no monsters in it is pointless) and store them in a list fleet_plans = fo.load_monster_fleet_plan_list() # create a map where we store a spawn counter for each monster fleet # this counter will be set to the spawn limit initially and decreased every time the monster fleet is spawned # this map (dict) needs to be separate from the list holding the fleet plans because the order in which items # are stored in a dict is undefined (can be different each time), which would result in different distribution # even when using the same seed for the RNG spawn_limits = {fp: fp.spawn_limit() for fp in fleet_plans if fp.spawn_rate() > 0.0 and fp.spawn_limit() > 0 and fp.ship_designs()} # map nests to monsters for ease of reporting nest_name_map = {"KRAKEN_NEST_SPECIAL": "SM_KRAKEN_1", "SNOWFLAKE_NEST_SPECIAL": "SM_SNOWFLAKE_1", "JUGGERNAUT_NEST_SPECIAL": "SM_JUGGERNAUT_1"} tracked_plan_tries = {name: 0 for name in nest_name_map.values()} tracked_plan_counts = {name: 0 for name in nest_name_map.values()} tracked_plan_valid_locations = {fp: 0 for fp in fleet_plans if fp.name() in tracked_plan_counts} if not fleet_plans: return universe = fo.get_universe() # Fleet plans that include ships capable of altering starlanes. # @content_tag{CAN_ALTER_STARLANES} universe_generator special handling # for fleets containing a hull design with this tag. fleet_can_alter_starlanes = {fp for fp in fleet_plans if any([universe.getGenericShipDesign(design).hull_type.hasTag("CAN_ALTER_STARLANES") for design in fp.ship_designs()])} # dump a list of all monster fleets meeting these conditions and their properties to the log print "Monster fleets available for generation at game start:" fp_location_cache = {} for fleet_plan in fleet_plans: print "...", fleet_plan.name(), ": spawn rate", fleet_plan.spawn_rate(), print "/ spawn limit", fleet_plan.spawn_limit(), print "/ effective chance", basic_chance * fleet_plan.spawn_rate(), fp_location_cache[fleet_plan] = set(fleet_plan.locations(systems)) print ("/ can be spawned at", len(fp_location_cache[fleet_plan]), "of", len(systems), "systems") if fleet_plan.name() in nest_name_map.values(): universe_statistics.tracked_monsters_chance[fleet_plan.name()] = basic_chance * fleet_plan.spawn_rate() # initialize a manager for monsters that can alter the map # required to prevent their placement from disjoining the map starlane_altering_monsters = StarlaneAlteringMonsters(systems) # collect info for tracked monster nest valid locations planets = [p for s in systems for p in fo.sys_get_planets(s)] tracked_nest_valid_locations = {nest: len(fo.special_locations(nest, planets)) for nest in nest_name_map} # for each system in the list that has been passed to this function, find a monster fleet that can be spawned at # the system and which hasn't already been added too many times, then attempt to add that monster fleet by # testing the spawn rate chance random.shuffle(systems) for system in systems: # collect info for tracked monster valid locations for fp in tracked_plan_valid_locations: if system in fp_location_cache[fp]: tracked_plan_valid_locations[fp] += 1 # filter out all monster fleets whose location condition allows this system and whose counter hasn't reached 0. suitable_fleet_plans = [fp for fp in fleet_plans if system in fp_location_cache[fp] and spawn_limits.get(fp, 0) and (fp not in fleet_can_alter_starlanes or starlane_altering_monsters.can_place_at(system, fp))] # if there are no suitable monster fleets for this system, continue with the next if not suitable_fleet_plans: continue # randomly select one monster fleet out of the suitable ones and then test if we want to add it to this system # by making a roll against the basic chance multiplied by the spawn rate of this monster fleet expectation_tally += basic_chance * sum([fp.spawn_rate() for fp in suitable_fleet_plans]) / len(suitable_fleet_plans) fleet_plan = random.choice(suitable_fleet_plans) if fleet_plan.name() in tracked_plan_tries: tracked_plan_tries[fleet_plan.name()] += 1 if random.random() > basic_chance * fleet_plan.spawn_rate(): print("\t\t At system %4d rejected monster fleet %s from %d suitable fleets" % (system, fleet_plan.name(), len(suitable_fleet_plans))) # no, test failed, continue with the next system continue actual_tally += 1 if fleet_plan.name() in tracked_plan_counts: tracked_plan_counts[fleet_plan.name()] += 1 # all prerequisites and the test have been met, now spawn this monster fleet in this system # create monster fleet try: if fleet_plan in fleet_can_alter_starlanes: starlane_altering_monsters.place(system, fleet_plan) else: populate_monster_fleet(fleet_plan, system) # decrement counter for this monster fleet spawn_limits[fleet_plan] -= 1 except MapGenerationError as err: report_error(str(err)) continue print "Actual # monster fleets placed: %d; Total Placement Expectation: %.1f" % (actual_tally, expectation_tally) # finally, compile some statistics to be dumped to the log later universe_statistics.monsters_summary = [ (fp.name(), fp.spawn_limit() - counter) for fp, counter in spawn_limits.iteritems() ] universe_statistics.tracked_monsters_tries.update(tracked_plan_tries) universe_statistics.tracked_monsters_summary.update(tracked_plan_counts) universe_statistics.tracked_monsters_location_summary.update( (fp.name(), count) for fp, count in tracked_plan_valid_locations.iteritems()) universe_statistics.tracked_nest_location_summary.update( (nest_name_map[nest], count) for nest, count in tracked_nest_valid_locations.items())
def generate_monsters(monster_freq, systems): """ Adds space monsters to systems. """ # first, calculate the basic chance for monster generation in a system # based on the monster frequency that has been passed # get the corresponding value for the specified monster frequency from the universe tables basic_chance = universe_tables.MONSTER_FREQUENCY[monster_freq] # a value of 0 means no monsters, in this case return immediately if basic_chance <= 0: return print "Default monster spawn chance:", basic_chance expectation_tally = 0.0 actual_tally = 0 # get all monster fleets that have a spawn rate and limit both > 0 and at least one monster ship design in it # (a monster fleet with no monsters in it is pointless) and store them in a list fleet_plans = fo.load_monster_fleet_plan_list() # create a map where we store a spawn counter for each monster fleet # this counter will be set to the spawn limit initially and decreased every time the monster fleet is spawned # this map (dict) needs to be separate from the list holding the fleet plans because the order in which items # are stored in a dict is undefined (can be different each time), which would result in different distribution # even when using the same seed for the RNG spawn_limits = { fp: fp.spawn_limit() for fp in fleet_plans if fp.spawn_rate() > 0.0 and fp.spawn_limit() > 0 and fp.ship_designs() } # map nests to monsters for ease of reporting nest_name_map = { "KRAKEN_NEST_SPECIAL": "SM_KRAKEN_1", "SNOWFLAKE_NEST_SPECIAL": "SM_SNOWFLAKE_1", "JUGGERNAUT_NEST_SPECIAL": "SM_JUGGERNAUT_1" } tracked_plan_tries = {name: 0 for name in nest_name_map.values()} tracked_plan_counts = {name: 0 for name in nest_name_map.values()} tracked_plan_valid_locations = { fp: 0 for fp in fleet_plans if fp.name() in tracked_plan_counts } tracked_nest_valid_locations = {nest: 0 for nest in nest_name_map} if not fleet_plans: return universe = fo.get_universe() # Fleet plans that include ships capable of altering starlanes. ## @content_tag{CAN_ALTER_STARLANES} universe_generator special handling for fleets containing a hull design with this tag. fleet_can_alter_starlanes = { fp for fp in fleet_plans if any([ universe.getGenericShipDesign(design).hull_type.hasTag( "CAN_ALTER_STARLANES") for design in fp.ship_designs() ]) } # dump a list of all monster fleets meeting these conditions and their properties to the log print "Monster fleets available for generation at game start:" for fleet_plan in fleet_plans: print "...", fleet_plan.name(), ": spawn rate", fleet_plan.spawn_rate( ), print "/ spawn limit", fleet_plan.spawn_limit(), print "/ effective chance", basic_chance * fleet_plan.spawn_rate(), if len(systems) < 100: # Note: The WithinStarlaneJumps condition in fp.location() # is the most time costly function in universe generation print "/ can be spawned at", len( [s for s in systems if fleet_plan.location(s)]), "systems" else: print # to terminate the print line if fleet_plan.name() in nest_name_map.values(): statistics.tracked_monsters_chance[ fleet_plan.name()] = basic_chance * fleet_plan.spawn_rate() # initialize a manager for monsters that can alter the map # required to prevent their placement from disjoining the map starlane_altering_monsters = StarlaneAlteringMonsters(systems) # for each system in the list that has been passed to this function, find a monster fleet that can be spawned at # the system and which hasn't already been added too many times, then attempt to add that monster fleet by # testing the spawn rate chance for system in systems: # collect info for tracked monster nest valid locations for planet in fo.sys_get_planets(system): for nest in tracked_nest_valid_locations: # print "\t tracked monster check planet: %d size: %s for nest: %20s | result: %s" # % (planet, fo.planet_get_size(planet), nest, fo.special_location(nest, planet)) if fo.special_location(nest, planet): tracked_nest_valid_locations[nest] += 1 # collect info for tracked monster valid locations for fp in tracked_plan_valid_locations: if fp.location(system): tracked_plan_valid_locations[fp] += 1 # filter out all monster fleets whose location condition allows this system and whose counter hasn't reached 0. # Note: The WithinStarlaneJumps condition in fp.location() is # the most time costly function in universe generation. suitable_fleet_plans = [ fp for fp in fleet_plans if spawn_limits[fp] and fp.location(system) and ( fp not in fleet_can_alter_starlanes or starlane_altering_monsters.can_place_at(system, fp)) ] # if there are no suitable monster fleets for this system, continue with the next if not suitable_fleet_plans: continue # randomly select one monster fleet out of the suitable ones and then test if we want to add it to this system # by making a roll against the basic chance multiplied by the spawn rate of this monster fleet expectation_tally += basic_chance * sum( [fp.spawn_rate() for fp in suitable_fleet_plans]) / len(suitable_fleet_plans) fleet_plan = random.choice(suitable_fleet_plans) if fleet_plan.name() in tracked_plan_tries: tracked_plan_tries[fleet_plan.name()] += 1 if random.random() > basic_chance * fleet_plan.spawn_rate(): print( "\t\t At system %4d rejected monster fleet %s from %d suitable fleets" % (system, fleet_plan.name(), len(suitable_fleet_plans))) # no, test failed, continue with the next system continue actual_tally += 1 if fleet_plan.name() in tracked_plan_counts: tracked_plan_counts[fleet_plan.name()] += 1 # all prerequisites and the test have been met, now spawn this monster fleet in this system # create monster fleet try: if fleet_plan in fleet_can_alter_starlanes: starlane_altering_monsters.place(system, fleet_plan) else: populate_monster_fleet(fleet_plan, system) # decrement counter for this monster fleet spawn_limits[fleet_plan] -= 1 except MapGenerationError as e: report_error(str(e)) continue print "Actual # monster fleets placed: %d; Total Placement Expectation: %.1f" % ( actual_tally, expectation_tally) # finally, compile some statistics to be dumped to the log later statistics.monsters_summary = [(fp.name(), fp.spawn_limit() - counter) for fp, counter in spawn_limits.iteritems()] statistics.tracked_monsters_tries.update(tracked_plan_tries) statistics.tracked_monsters_summary.update(tracked_plan_counts) statistics.tracked_monsters_location_summary.update([ (fp.name(), count) for fp, count in tracked_plan_valid_locations.iteritems() ]) statistics.tracked_nest_location_summary.update([ (nest_name_map[nest], count) for nest, count in tracked_nest_valid_locations.items() ])