production_line.consumed_res = {} self.lines[production_line.produced_res.keys() [0]] = production_line def _get_producer_building(self): return Entities.buildings[self.get_higher_level_building_id()] @classmethod def load(cls, db, building_id): # load the higher level building data because resource deposits don't actually produce anything name = cls._load_name(db, building_id) settler_level = cls._load_settler_level(building_id) return cls(building_id, name, settler_level) def get_expected_cost(self, resource_id, production_needed, settlement_manager): """ you don't actually build resource deposits """ return 0 @property def directly_buildable(self): """ You don't actually build resource deposits """ return False @property def ignore_production(self): return True decorators.bind_all(AbstractFakeResourceDeposit)
self.was_reached() else: self.report_success("Target ship was eliminated") def in_combat(self): if not self.session.world.diplomacy.are_enemies(self.owner, self.target_ship.owner): self.report_failure("Target ship was not hostile. Aborting mission.") return self.combat_phase = True self.log.debug("Player %s, Mission %s, 2/2 in combat", self.owner.name, self.__class__.__name__) self.state = self.missionStates.in_combat def flee_home(self): # check if fleet still exists if self.fleet.size() > 0: try: home_settlement = self.owner.settlements[0] return_point = self.unit_manager.get_warehouse_area(home_settlement, 10) self.fleet.move(return_point, self._state_fleet_callbacks[self.missionStates.fleeing_home]) self.state = self.missionStates.fleeing_home except MoveNotPossible: self.report_failure("Combat was lost, ships couldn't flee home") else: self.report_failure("Combat was lost, all ships were wiped out") @classmethod def create(cls, success_callback, failure_callback, fleet, target_ship): return ChaseShipsAndAttack(success_callback, failure_callback, fleet, target_ship) decorators.bind_all(ChaseShipsAndAttack)
if ship is None: self.owner.request_ship() else: self.log.info('%s.tick: send ship %s on a mission to found a settlement', self, ship) self._found_settlement(island, ship, False) else: for settlement_manager in self.owner.settlement_managers: if not settlement_manager.can_provide_resources(): continue if self.have_starting_resources(ship, settlement_manager.land_manager.settlement): if ship is None: self.owner.request_ship() else: self.log.info('%s.tick: send ship %s on a mission to get resources for a new settlement', self, ship) self._prepare_foundation_ship(settlement_manager, ship, False) return def can_found_feeder_island(self): """Return a boolean showing whether there is an island that could be turned into a feeder island.""" return bool(self._get_available_islands(self.personality.min_feeder_island_area)) def found_feeder_island(self): """Call this function to let the player know that a new feeder island is needed.""" if self.can_found_feeder_island(): self.owner.need_feeder_island = True def __str__(self): return '%s SettlementFounder' % (self.owner) decorators.bind_all(SettlementFounder)
"""Encapsulates handling of fife Image. Provides: - self.rendertarget: instance of fife.RenderTarget """ def __init__(self, minimap, targetrenderer): self.minimap = minimap self.targetrenderer = targetrenderer size = self.minimap.get_size() self.image = self.minimap.imagemanager.loadBlank(size[0], size[1]) self.rendertarget = targetrenderer.createRenderTarget( self.image ) self.set_drawing_enabled() def reset(self): """Reset image to original image""" # reload self.rendertarget.removeAll() size = self.minimap.get_size() self.rendertarget.addQuad( self.minimap._get_render_name("background"), fife.Point(0,0), fife.Point(0, size[1]), fife.Point(size[0], size[1]), fife.Point(size[0], 0), *Minimap.COLORS["water"]) def set_drawing_enabled(self): """Always call this.""" self.targetrenderer.setRenderTarget( self.rendertarget.getTarget().getName(), False, 0 ) bind_all(Minimap)
if coords in self.village: del self.village[coords] elif coords in self.production: del self.production[coords] self.roads.discard(coords) self.coastline.discard(coords) def display(self): """Show the plan on the map unless it is disabled in the settings.""" if not AI.HIGHLIGHT_PLANS: return village_color = (255, 255, 255) production_color = (255, 255, 0) coastline_color = (0, 0, 255) renderer = self.island.session.view.renderer['InstanceRenderer'] for tile in self.production.itervalues(): renderer.addColored(tile._instance, *production_color) for tile in self.village.itervalues(): renderer.addColored(tile._instance, *village_color) for coords in self.coastline: renderer.addColored(self.island.ground_map[coords]._instance, *coastline_color) def __str__(self): return '%s LandManager(%s)' % (self.owner if hasattr(self, 'owner') else 'unknown player', self.worldid if hasattr(self, 'worldid') else 'none') decorators.bind_all(LandManager)
# along with this program; if not, write to the # Free Software Foundation, Inc., # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # ################################################### from horizons.ai.aiplayer.building import AbstractBuilding from horizons.constants import BUILDINGS from horizons.util.python import decorators class AbstractFishDeposit(AbstractBuilding): def get_expected_cost(self, resource_id, production_needed, settlement_manager): """ You don't actually build fish deposits """ return 0 @property def directly_buildable(self): """ You don't actually build fish deposits """ return False @property def ignore_production(self): return True @classmethod def register_buildings(cls): cls._available_buildings[BUILDINGS.FISH_DEPOSIT_CLASS] = cls AbstractFishDeposit.register_buildings() decorators.bind_all(AbstractFishDeposit)
building_score = widgets.Label(name = 'building_score_%d' % player.worldid) building_score.text = unicode(stats.building_score) building_score.min_size = (70, 20) settler_score = widgets.Label(name = 'settler_score_%d' % player.worldid) settler_score.text = unicode(stats.settler_score) settler_score.min_size = (60, 20) unit_score = widgets.Label(name = 'unit_score_%d' % player.worldid) unit_score.text = unicode(stats.unit_score) unit_score.min_size = (50, 20) total_score = widgets.Label(name = 'total_score_%d' % player.worldid) total_score.text = unicode(stats.total_score) total_score.min_size = (70, 20) hbox = widgets.HBox() hbox.addChild(emblem) hbox.addChild(name) hbox.addChild(money_score) hbox.addChild(land_score) hbox.addChild(resource_score) hbox.addChild(building_score) hbox.addChild(settler_score) hbox.addChild(unit_score) hbox.addChild(total_score) self._content_vbox.addChild(hbox) decorators.bind_all(PlayersOverview)
@classmethod def _check_buildings(cls, session, position, island=None): """Check if there are buildings blocking the build""" if island is None: island = session.world.get_island(position.center) deposit = None for tile in island.get_tiles_tuple(position.tuple_iter()): if tile.object is None or \ tile.object.id != cls.buildable_on_deposit_type or \ (deposit is not None and tile.object != deposit): # only build on 1 deposit raise _NotBuildableError(BuildableErrorTypes.NEED_RES_SOURCE) deposit = tile.object return set([deposit.worldid]) @classmethod def _check_rotation(cls, session, position, rotation): """The rotation should be the same as the one of the underlying mountain""" tearset = cls._check_buildings(session, position) # will raise on problems # rotation fix code is only reached when building is buildable mountain = WorldObject.get_object_by_id(iter(tearset).next()) return mountain.rotation decorators.bind_all(Buildable) decorators.bind_all(BuildableSingle) decorators.bind_all(BuildableRect) decorators.bind_all(BuildableSingleFromShip) decorators.bind_all(BuildableSingleOnCoast) decorators.bind_all(BuildableSingleOnDeposit)
dy = y2 - y distance = (dx * dx + dy * dy)**0.5 if distance < personality.too_close_penalty_threshold: cost += personality.too_close_constant_penalty + personality.too_close_linear_penalty / ( distance + 1.0) else: cost += distance for settlement_manager in land_manager.owner.settlement_managers: cost += settlement_manager.settlement.warehouse.position.distance( (x, y)) * personality.linear_warehouse_penalty options.append((cost, x, y)) for _, x, y in sorted(options): if ship.check_move( Circle( Point(x + warehouse_class.width // 2, y + warehouse_class.height // 2), BUILDINGS.BUILD.MAX_BUILDING_SHIP_DISTANCE)): return (x, y) return None @classmethod def create(cls, ship, land_manager, success_callback, failure_callback): coords = cls.find_warehouse_location(ship, land_manager) return FoundSettlement(success_callback, failure_callback, land_manager, ship, coords) decorators.bind_all(FoundSettlement)
# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the # Free Software Foundation, Inc., # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # ################################################### from horizons.constants import BUILDINGS from horizons.util.python import decorators from .fakeresourcedeposit import AbstractFakeResourceDeposit class AbstractClayDeposit(AbstractFakeResourceDeposit): @classmethod def get_higher_level_building_id(cls): return BUILDINGS.CLAY_PIT @classmethod def register_buildings(cls): cls._available_buildings[BUILDINGS.CLAY_DEPOSIT] = cls AbstractClayDeposit.register_buildings() decorators.bind_all(AbstractClayDeposit)
production_builder = settlement_manager.production_builder purpose = self.get_purpose(resource_id) if not production_builder.unused_fields[purpose]: return (BUILD_RESULT.NEED_PARENT_FIRST, None) if not self.have_resources(settlement_manager): return (BUILD_RESULT.NEED_RESOURCES, None) assert production_builder.unused_fields[ purpose], 'expected field spot to be available' coords = production_builder.unused_fields[purpose][0] building = BasicBuilder(self.id, coords, 0).execute(settlement_manager.land_manager) assert building production_builder.unused_fields[purpose].popleft() production_builder.register_change_list([coords], purpose, None) return (BUILD_RESULT.OK, building) @classmethod def register_buildings(cls): cls._available_buildings[BUILDINGS.POTATO_FIELD] = cls cls._available_buildings[BUILDINGS.PASTURE] = cls cls._available_buildings[BUILDINGS.SUGARCANE_FIELD] = cls cls._available_buildings[BUILDINGS.TOBACCO_FIELD] = cls cls._available_buildings[BUILDINGS.HERBARY] = cls AbstractField.register_buildings() decorators.bind_all(AbstractField)
buyable_amount = self._get_max_buyable_amount() if buyable_amount <= 0: self.report_failure('No resources can be bought') return SellResource(self.settlement.get_component(TradePostComponent), self.ship, self.bought_resource, buyable_amount).execute(self.owner.session) self.log.info('%s bought %d of resource %d', self, buyable_amount, self.bought_resource) self.state = self.missionStates.returning_to_my_settlement self._return_to_my_settlement() def _return_to_my_settlement(self): self._move_to_warehouse_area( self.settlement_manager.settlement.warehouse.position, Callback(self._returned_to_my_settlement), Callback(self._return_to_my_settlement), 'Unable to return to %s' % self.settlement_manager.settlement.get_component( NamedComponent).name) def _returned_to_my_settlement(self): self._unload_all_resources(self.settlement_manager.settlement) self.report_success('Unloaded the bought resources at %s' % self.settlement_manager.settlement.get_component( NamedComponent).name) decorators.bind_all(InternationalTrade)
self.production_builder = settlement_manager.production_builder self.village_builder = settlement_manager.village_builder self.settlement = settlement_manager.settlement self.island = settlement_manager.island self.session = settlement_manager.session @property def can_be_activated(self): return super( SettlementGoal, self ).can_be_activated and self.personality.residences_required <= self.settlement.count_buildings( BUILDINGS.RESIDENTIAL) def __str__(self): return super(SettlementGoal, self).__str__( ) + ', ' + self.settlement_manager.settlement.get_component( NamedComponent).name def _log_generic_build_result(self, result, name): if result == BUILD_RESULT.OK: self.log.info('%s built a %s', self, name) elif result == BUILD_RESULT.NEED_RESOURCES: self.log.info('%s not enough materials to build a %s', self, name) elif result == BUILD_RESULT.SKIP: self.log.info('%s skipped building a %s', self, name) else: self.log.info('%s failed to build a %s (%d)', self, name, result) decorators.bind_all(SettlementGoal)
if self.last_change_listener is not None: self._build_logic.add_change_listener( self.last_change_listener, self) def force_update(self): self.update_preview(force=True) def update_preview(self, force=False): """Used as callback method""" if self.start_point is not None: end_point = self.end_point or self.start_point self.preview_build(self.start_point, end_point, force=force) def _rotate(self, degrees): self.rotation = (self.rotation + degrees) % 360 self.log.debug("BuildingTool: Building rotation now: %s", self.rotation) self.update_preview() self.draw_gui() def rotate_left(self): self._rotate(degrees=90) def rotate_right(self): self._rotate(degrees=270) decorators.bind_all(BuildingTool) decorators.bind_all(SettlementBuildingToolLogic) decorators.bind_all(ShipBuildingToolLogic) decorators.bind_all(BuildRelatedBuildingToolLogic)
cls.purpose_to_building[cls.SMELTERY] = BUILDINGS.SMELTERY cls.purpose_to_building[cls.TOOLMAKER] = BUILDINGS.TOOLMAKER cls.purpose_to_building[cls.CHARCOAL_BURNER] = BUILDINGS.CHARCOAL_BURNER cls.purpose_to_building[cls.BOAT_BUILDER] = BUILDINGS.BOAT_BUILDER cls.purpose_to_building[cls.SIGNAL_FIRE] = BUILDINGS.SIGNAL_FIRE cls.purpose_to_building[cls.TOBACCO_FIELD] = BUILDINGS.TOBACCO_FIELD cls.purpose_to_building[cls.TOBACCONIST] = BUILDINGS.TOBACCONIST cls.purpose_to_building[cls.SALT_PONDS] = BUILDINGS.SALT_PONDS cls.purpose_to_building[cls.FIRE_STATION] = BUILDINGS.FIRE_STATION cls.purpose_to_building[cls.DOCTOR] = BUILDINGS.DOCTOR cls.purpose_to_building[cls.HERBARY] = BUILDINGS.HERBARY cls.purpose_to_building[cls.STONE_PIT] = BUILDINGS.STONE_PIT cls.purpose_to_building[cls.STONEMASON] = BUILDINGS.STONEMASON for purpose, building_id in cls.purpose_to_building.iteritems(): cls.building_to_purpose[building_id] = purpose @classmethod def get_building(cls, purpose): return cls.purpose_to_building[purpose] @classmethod def get_purpose(cls, building_id): return cls.purpose_to_building[building_id] BUILDING_PURPOSE.init_translation() decorators.bind_all(BUILD_RESULT) decorators.bind_all(GOAL_RESULT) decorators.bind_all(BUILDING_PURPOSE)
class SignalFireEvaluator(BuildingEvaluator): need_collector_connection = False @classmethod def create(cls, area_builder, x, y, orientation): builder = BasicBuilder.create(BUILDINGS.SIGNAL_FIRE, (x, y), orientation) sea_area = 0 for coords in builder.position.get_radius_coordinates( Entities.buildings[BUILDINGS.SIGNAL_FIRE].radius): if coords in area_builder.session.world.water: sea_area += 1 personality = area_builder.owner.personality_manager.get( 'SignalFireEvaluator') alignment = cls._get_alignment(area_builder, builder.position.tuple_iter()) value = sea_area + alignment * personality.alignment_importance return SignalFireEvaluator(area_builder, builder, value) @property def purpose(self): return BUILDING_PURPOSE.SIGNAL_FIRE AbstractSignalFire.register_buildings() decorators.bind_all(AbstractSignalFire) decorators.bind_all(SignalFireEvaluator)
self.abstract_building = abstract_building self.children = children # [SimpleProductionChainSubtreeChoice, ...] self.production_ratio = production_ratio def assign_identifier(self, prefix): """Recursively assign an identifier to this subtree to know which subtree owns which resource quota.""" self.identifier = '%s/%d,%d' % (prefix, self.resource_id, self.abstract_building.id) for child in self.children: child.assign_identifier(self.identifier) def request_quota_change(self, quota_holder, amount, priority): """Try to reserve currently available production. Return the total amount that can be reserved.""" total_reserved = amount for child in self.children: total_reserved = min(total_reserved, child.request_quota_change(quota_holder, amount, priority)) self.resource_manager.request_quota_change(quota_holder + self.identifier, priority, self.resource_id, self.abstract_building.id, amount * self.production_ratio) return min(total_reserved, self.resource_manager.get_quota(quota_holder + self.identifier, self.resource_id, self.abstract_building.id) / self.production_ratio) def get_quota(self, quota_holder): """Return the current quota at the bottleneck.""" root_quota = self.resource_manager.get_quota(quota_holder + self.identifier, self.resource_id, self.abstract_building.id) / self.production_ratio if self.children: return min(root_quota, min(child.get_quota(quota_holder) for child in self.children)) return root_quota decorators.bind_all(ResourceManager) decorators.bind_all(SingleResourceManager) decorators.bind_all(SimpleProductionChainSubtreeChoice) decorators.bind_all(SimpleProductionChainSubtree)
production.add_production_finished_listener(self._ship_built) self.log.info('%s started building trading ship', self) def build_combat_ship(self): """Build a new frigate ship""" boat_builder = self._get_boat_builders()[0] AddProduction(boat_builder.get_component(Producer), PRODUCTIONLINES.FRIGATE).execute(self.owner.session) production = boat_builder.get_component(Producer)._get_production( PRODUCTIONLINES.FRIGATE) production.add_production_finished_listener(self._ship_built) self.log.info('%s started building combat ship', self) def _ship_built(self, production): """Called when a new ship has been built.""" self.log.info('%s ship building finished', self) self.owner.refresh_ships() @property def num_ships_being_built(self): """Return the number of ships being built by all the boat builders of the player.""" return sum( len(boat_builder.get_component(Producer).get_production_lines()) for boat_builder in self._get_boat_builders()) def __str__(self): return '%s UnitBuilder' % self.owner decorators.bind_all(UnitBuilder)
def _get_boat_builders(self): """Return a list of all boat builders owned by the player.""" result = [] # [building, ...] for settlement_manager in self.owner.settlement_managers: result.extend(settlement_manager.settlement.get_buildings_by_id(BUILDINGS.BOATBUILDER_CLASS)) return result def build_ship(self): """Build a new usable fishing boat.""" boat_builder = self._get_boat_builders()[0] AddProduction(boat_builder, PRODUCTIONLINES.HUKER).execute(self.owner.session) production = boat_builder._get_production(PRODUCTIONLINES.HUKER) production.add_production_finished_listener(self._ship_built) self.log.info('%s started building a ship', self) def _ship_built(self, production): """Called when a new ship has been built.""" self.log.info('%s ship building finished', self) self.owner.refresh_ships() @property def num_ships_being_built(self): """Return the number of ships being built by all the boat builders of the player.""" return sum(len(boat_builder.get_production_lines()) for boat_builder in self._get_boat_builders()) def __str__(self): return '%s UnitBuilder' % self.owner decorators.bind_all(UnitBuilder)
building = self.builder.execute(self.area_builder.land_manager) if not building: self.log.debug('%s, unknown error', self) return (BUILD_RESULT.UNKNOWN_ERROR, None) if self.record_plan_change: self._register_builder_position() return (BUILD_RESULT.OK, building) def __str__(self): point = self.builder.position.origin return '%s at %d, %d with value %f' % (self.__class__.__name__, point.x, point.y, self.value) @classmethod def get_best_evaluator(cls, evaluators): if not evaluators: return None best_index = 0 best_value = evaluators[0].value for i in xrange(1, len(evaluators)): if evaluators[i].value > best_value: best_index = i best_value = evaluators[i].value return evaluators[best_index] decorators.bind_all(BuildingEvaluator)
# TODO Add a check that figures out if all trees that should be planted are in range of the settlement. # If not, return range missing result (result, building) = super(LumberjackEvaluator, self).execute() if result != BUILD_RESULT.OK: return (result, None) production_builder = self.area_builder coastline = production_builder.land_manager.coastline island_ground_map = production_builder.island.ground_map forest_coords_list = [] for coords in building.position.get_radius_coordinates(Entities.buildings[BUILDINGS.LUMBERJACK].radius): if coords in production_builder.plan and production_builder.plan[coords][0] == BUILDING_PURPOSE.NONE and coords not in coastline: if island_ground_map[coords].object is not None and island_ground_map[coords].object.id == BUILDINGS.TREE: forest_coords_list.append(coords) elif island_ground_map[coords].settlement is not None and island_ground_map[coords].settlement.owner is self.area_builder.owner: builder = BasicBuilder(BUILDINGS.TREE, coords, 0) if not builder.have_resources(production_builder.land_manager): break if builder: assert builder.execute(production_builder.land_manager) forest_coords_list.append(coords) production_builder.register_change_list(forest_coords_list, BUILDING_PURPOSE.TREE, None) return (BUILD_RESULT.OK, building) AbstractLumberjack.register_buildings() decorators.bind_all(AbstractLumberjack) decorators.bind_all(LumberjackEvaluator)
found_fish = False for fish in fish_indexer.get_buildings_in_range(fisher_coords): fish_coords = fish.position.origin.to_tuple() if fish_map[fish_coords] > tick: continue distance = math.sqrt((fish_coords[0] - fisher_coords[0])**2 + (fish_coords[1] - fisher_coords[1])**2) move_time = cls.move_time * int(round(distance)) fish_map[ fish_coords] = tick + move_time + COLLECTORS.DEFAULT_WORK_DURATION + cls.fish_respawn_time if tick + 2 * move_time + COLLECTORS.DEFAULT_WORK_DURATION <= cls.simulation_time: fish_caught += 1 next_time = tick + 2 * move_time + COLLECTORS.DEFAULT_WORK_DURATION + COLLECTORS.DEFAULT_WAIT_TICKS heapq.heappush(heap, (next_time, fisher_coords)) found_fish = True break if not found_fish: heapq.heappush( heap, (tick + COLLECTORS.DEFAULT_WAIT_TICKS, fisher_coords)) return float(fish_caught) / cls.simulation_time AbstractFisher.register_buildings() decorators.bind_all(AbstractFisher) decorators.bind_all(FisherEvaluator) decorators.bind_all(FisherSimulator)
options.append((value, builder)) if options: return self.production_builder.build_best_option(options, BUILDING_PURPOSE.STORAGE) # enlarge the settlement area instead since just enlarging the collector area is impossible if self.village_builder.tent_queue: tent_size = Entities.buildings[BUILDINGS.RESIDENTIAL_CLASS].size tent_radius = Entities.buildings[BUILDINGS.RESIDENTIAL_CLASS].radius best_coords = None best_area = 0 for x, y in self.village_builder.tent_queue: new_area = 0 for coords in Rect.init_from_topleft_and_size(x, y, tent_size[0] - 1, tent_size[1] - 1).get_radius_coordinates(tent_radius): if coords in area_label and coords not in self.land_manager.roads and coords not in collector_area: new_area += 1 if new_area > best_area: best_coords = (x, y) best_area = new_area if best_coords is not None: return self.production_builder.extend_settlement_with_tent(Rect.init_from_topleft_and_size(best_coords[0], best_coords[1], tent_size[0] - 1, tent_size[1] - 1)) return BUILD_RESULT.IMPOSSIBLE def execute(self): result = self._enlarge_collector_area() self._log_generic_build_result(result, 'storage coverage building') return self._translate_build_result(result) decorators.bind_all(EnlargeCollectorAreaGoal)
def get_personality_name(self): return 'TobaccoProductsGoal' class MedicalHerbsProductsGoal(ProductionChainGoal): def __init__(self, settlement_manager): super(MedicalHerbsProductsGoal, self).__init__(settlement_manager, RES.MEDICAL_HERBS, 'medical herbs products producer') def get_personality_name(self): return 'MedicalHerbsProductsGoal' class SaltGoal(ProductionChainGoal): def __init__(self, settlement_manager): super(SaltGoal, self).__init__(settlement_manager, RES.SALT, 'salt producer') def get_personality_name(self): return 'SaltGoal' decorators.bind_all(ProductionChainGoal) decorators.bind_all(FaithGoal) decorators.bind_all(TextileGoal) decorators.bind_all(BricksGoal) decorators.bind_all(EducationGoal) decorators.bind_all(GetTogetherGoal) decorators.bind_all(ToolsGoal) decorators.bind_all(BoardsGoal) decorators.bind_all(FoodGoal) decorators.bind_all(CommunityGoal) decorators.bind_all(TobaccoProductsGoal) decorators.bind_all(SaltGoal)
return self._health[owner] def _load_fish_data(self): self._fish_data = {} for row in self("SELECT rowid, last_usage_tick FROM fish_data"): self._fish_data[int(row[0])] = int(row[1]) def get_last_fish_usage_tick(self, worldid): return self._fish_data[worldid] # Random savegamefile related utility that i didn't know where to put @classmethod def get_players_num(cls, savegamefile): """Return number of regular human and ai players""" return DbReader(savegamefile)("SELECT count(rowid) FROM player WHERE is_trader = 0 AND is_pirate = 0")[0][0] @classmethod def get_hash(cls, savegamefile): if not os.path.exists(savegamefile): return False fd = open(savegamefile, "rb") h = hashlib.sha1() h.update(fd.read()) filehash = h.hexdigest() fd.close() return filehash decorators.bind_all(SavegameAccessor)
def get_health(self, owner): return self._health[owner] def _load_fish_data(self): self._fish_data = {} for row in self("SELECT rowid, last_usage_tick FROM fish_data"): self._fish_data[int(row[0])] = int(row[1]) def get_last_fish_usage_tick(self, worldid): return self._fish_data[worldid] # Random savegamefile related utility that i didn't know where to put @classmethod def get_players_num(cls, savegamefile): """Return number of regular human and ai players""" return DbReader(savegamefile)("SELECT count(rowid) FROM player WHERE is_trader = 0 AND is_pirate = 0")[0][0] @classmethod def get_hash(cls, savegamefile): if not os.path.exists(savegamefile): return False with open(savegamefile, "rb") as f: h = hashlib.sha1() h.update(f.read()) filehash = h.hexdigest() return filehash decorators.bind_all(SavegameAccessor)
alignment += 1 value = min_distance - alignment * self.personality.alignment_coefficient options.append((-value, builder)) return self.production_builder.build_best_option(options, BUILDING_PURPOSE.STORAGE) def execute(self): result = self._improve_deposit_coverage() self._log_generic_build_result(result, "deposit coverage storage") return self._translate_build_result(result) class ClayDepositCoverageGoal(DepositCoverageGoal): _deposit_resource_id = RES.RAW_CLAY def get_personality_name(self): return "ClayDepositCoverageGoal" class MountainCoverageGoal(DepositCoverageGoal): _deposit_resource_id = RES.RAW_IRON def get_personality_name(self): return "MountainCoverageGoal" decorators.bind_all(DepositCoverageGoal) decorators.bind_all(ClayDepositCoverageGoal) decorators.bind_all(MountainCoverageGoal)
def get_buildings_in_range(self, reslist=None): """Returns all buildings in range . Overwrite in subclasses that need ranges around the pickup. @param res: optional, only search for buildings that provide res""" reach = RadiusRect(self.home_building.position, self.home_building.radius) return self.session.world.get_providers_in_range(reach, reslist=reslist) class DisasterRecoveryCollector(StorageCollector): """Collects disasters such as fire or pestilence.""" def finish_working(self, collector_already_home=False): super(DisasterRecoveryCollector, self).finish_working(collector_already_home=collector_already_home) building = self.job.object if hasattr(building, "disaster"): # make sure that building hasn't recovered any other way building.disaster.recover(building) def get_job(self): if self.home_building is not None and \ not self.session.world.disaster_manager.is_affected( self.home_building.settlement ): return None # not one disaster active, bail out return super(DisasterRecoveryCollector, self).get_job() decorators.bind_all(BuildingCollector) decorators.bind_all(FieldCollector) decorators.bind_all(FisherShipCollector) decorators.bind_all(SettlerCollector) decorators.bind_all(StorageCollector) decorators.bind_all(DisasterRecoveryCollector)
while heap: (_, distance_so_far, key) = heapq.heappop(heap) if distance[key] < distance_so_far: continue if (key[0], key[1]) in destination: final_key = key break for dir in xrange(4): coords = (key[0] + moves[dir][0], key[1] + moves[dir][1]) if coords not in path_nodes or coords in blocked_coords: continue reduced_dir = 0 if moves[dir][0] != 0 else 1 next_key = (coords[0], coords[1], reduced_dir) real_distance = distance_so_far + path_nodes[coords] + (0 if reduced_dir == key[2] else personality.turn_penalty) expected_distance = real_distance + beacon_tuple_distance_func(destination_beacon, coords) if next_key not in distance or distance[next_key][0] > real_distance: distance[next_key] = (real_distance, key) heapq.heappush(heap, (expected_distance, real_distance, next_key)) # save path if final_key is not None: path = [] while final_key is not None: path.append((final_key[0], final_key[1])) final_key = distance[final_key][1] return path return None decorators.bind_all(RoadPlanner)
""" An object of this class describes a goal that a settlement of an AI player attempts to fulfil. """ def __init__(self, settlement_manager): super(SettlementGoal, self).__init__(settlement_manager.owner) self.settlement_manager = settlement_manager self.land_manager = settlement_manager.land_manager self.production_builder = settlement_manager.production_builder self.village_builder = settlement_manager.village_builder self.settlement = settlement_manager.settlement @property def can_be_activated(self): return super(SettlementGoal, self).can_be_activated and self.personality.residences_required <= self.settlement.count_buildings(BUILDINGS.RESIDENTIAL) def __str__(self): return super(SettlementGoal, self).__str__() + ', ' + self.settlement_manager.settlement.get_component(NamedComponent).name def _log_generic_build_result(self, result, name): if result == BUILD_RESULT.OK: self.log.info('%s built a %s', self, name) elif result == BUILD_RESULT.NEED_RESOURCES: self.log.info('%s not enough materials to build a %s', self, name) elif result == BUILD_RESULT.SKIP: self.log.info('%s skipped building a %s', self, name) else: self.log.info('%s failed to build a %s (%d)', self, name, result) decorators.bind_all(SettlementGoal)
"""Show the plan on the map unless it is disabled in the settings.""" if not AI.HIGHLIGHT_PLANS: return unknown_color = (255, 0, 0) renderer = self.session.view.renderer['InstanceRenderer'] tile_colors = { BUILDING_PURPOSE.MAIN_SQUARE: (255, 0, 255), BUILDING_PURPOSE.RESIDENCE: (255, 255, 255), BUILDING_PURPOSE.ROAD: (30, 30, 30), BUILDING_PURPOSE.VILLAGE_SCHOOL: (128, 128, 255), BUILDING_PURPOSE.PAVILION: (255, 128, 128), BUILDING_PURPOSE.TAVERN: (255, 255, 0), BUILDING_PURPOSE.FIRE_STATION: (255, 64, 64), BUILDING_PURPOSE.DOCTOR: (255, 128, 64), BUILDING_PURPOSE.RESERVED: (0, 0, 255), } for coords, (purpose, _) in self.plan.iteritems(): tile = self.island.ground_map[coords] color = tile_colors.get(purpose, unknown_color) renderer.addColored(tile._instance, *color) def __str__(self): return '%s VillageBuilder(%s)' % (self.settlement_manager, self.worldid if hasattr( self, 'worldid') else 'none') decorators.bind_all(VillageBuilder)
from horizons.ai.aiplayer.goal.settlementgoal import SettlementGoal from horizons.constants import BUILDINGS, RES from horizons.util.python import decorators class DoctorGoal(SettlementGoal): def get_personality_name(self): return 'DoctorGoal' @property def can_be_activated(self): return super(DoctorGoal, self).can_be_activated and self.settlement_manager.get_resource_production(RES.BRICKS) > 0 @property def active(self): return super(DoctorGoal, self).active and self._is_active def update(self): super(DoctorGoal, self).update() if self.can_be_activated: self._is_active = any(AbstractBuilding.buildings[BUILDINGS.DOCTOR].iter_potential_locations(self.settlement_manager)) else: self._is_active = False def execute(self): result = AbstractBuilding.buildings[BUILDINGS.DOCTOR].build(self.settlement_manager, None)[0] self._log_generic_build_result(result, 'doctor') return self._translate_build_result(result) decorators.bind_all(DoctorGoal)
return self.personality.enabled and self.owner.settler_level >= self.personality.min_settler_level def execute(self): """Do whatever is best to get closer to fulfilling the goal (usually involves building a building).""" raise NotImplementedError("This function has to be overridden.") def update(self): """Update the goal to find out whether it is currently active and what its current priority is.""" pass @classmethod def _translate_build_result(cls, result): """Returns the goal execution state that corresponds to the given BUILD_RESULT constant.""" if result == BUILD_RESULT.OK: return GOAL_RESULT.BLOCK_ALL_BUILDING_ACTIONS elif result == BUILD_RESULT.NEED_RESOURCES: return GOAL_RESULT.BLOCK_SETTLEMENT_RESOURCE_USAGE elif result in [BUILD_RESULT.IMPOSSIBLE, BUILD_RESULT.UNKNOWN_ERROR, BUILD_RESULT.ALL_BUILT, BUILD_RESULT.SKIP]: return GOAL_RESULT.SKIP assert False, 'Unable to translate BUILD_RESULT %d to a GOAL_RESULT' % result def __lt__(self, other): if self.priority != other.priority: return self.priority < other.priority return self.sequence_number < other.sequence_number def __str__(self): return 'Goal(%d): %s(%d)' % (self.priority, self.__class__.__name__, self.sequence_number) decorators.bind_all(Goal)
"""Handle losing the potential land in the given coordinates list.""" # remove the affected tiles from the plan for coords in coords_list: if coords in self.plan: del self.plan[coords] def add_building(self, building): """Called when a new building is added in the area (the building already exists during the call).""" self.display() def remove_building(self, building): """Called when a building is removed from the area (the building still exists during the call).""" self.display() def display(self): """Show the plan on the map unless it is disabled in the settings.""" raise NotImplementedError('This function has to be overridden.') def _init_cache(self): """Initialise the cache that knows the last time the buildability of a rectangle may have changed in this area.""" self.last_change_id = -1 def register_change(self, x, y, purpose, data): """Register the (potential) change of the purpose of land at the given coordinates.""" if (x, y) in self.plan: self.plan[(x, y)] = (purpose, data) if purpose == BUILDING_PURPOSE.ROAD: self.land_manager.roads.add((x, y)) decorators.bind_all(AreaBuilder)
instance.act(action + "_" + str(action_set_id), facing_loc, True) return (instance, action_set_id) @classmethod def have_resources(cls, inventory_holders, owner): return Build.check_resources({}, cls.costs, owner, inventory_holders)[0] def init(self): """init the building, called after the constructor is run and the building is positioned (the settlement variable is assigned etc) """ pass def start(self): """This function is called when the building is built, to start production for example.""" pass def __str__(self): # debug return '%s(id=%s;worldid=%s)' % (self.name, self.id, self.worldid if hasattr(self, 'worldid') else 'none') class DefaultBuilding(BasicBuilding, BuildableSingle): """Building with default properties, that does nothing.""" pass decorators.bind_all(BasicBuilding)
for dir in xrange(4): coords = (key[0] + moves[dir][0], key[1] + moves[dir][1]) if coords not in path_nodes: continue reduced_dir = 0 if moves[dir][0] != 0 else 1 next_key = (coords[0], coords[1], reduced_dir) # determine whether this is a turn and if so then whether it is in the preferred direction turn = reduced_dir != key[2] if turn and distance[key][1] is None: continue # disallow turning as the first step; doesn't affect the ability to find the best path good_turn = self.__is_preferred_turn(distance[key][1][:2], key[:2], coords, clockwise) if turn else True # NOTE: all distances are in the form (actual distance, number of turns, number of non-preferred turns) real_distance = (distance_so_far[0] + 1, distance_so_far[1] + (1 if turn else 0), distance_so_far[2] + (0 if good_turn else 1)) expected_distance = (real_distance[0] + ((coords[0] - destination[0]) ** 2 + (coords[1] - destination[1]) ** 2) ** 0.5, real_distance[1], real_distance[2]) if next_key not in distance or distance[next_key][0] > real_distance: distance[next_key] = (real_distance, key) heapq.heappush(heap, (expected_distance, real_distance, next_key)) # save path if final_key is not None: path = [] while final_key is not None: path.append(final_key[:2]) final_key = distance[final_key][1] return path return None decorators.bind_all(RoadPathFinder)
area_builder, builder, BUILDINGS.CLAY_PIT) distance_to_collector = cls._distance_to_nearest_collector( area_builder, builder) if distance_to_clay_pit is None and distance_to_collector is None: return None personality = area_builder.owner.personality_manager.get( 'BrickyardEvaluator') distance_penalty = Entities.buildings[ BUILDINGS.BRICKYARD].radius * personality.distance_penalty alignment = cls._get_alignment(area_builder, builder.position.tuple_iter()) distance = cls._weighted_distance(distance_to_clay_pit, [ (personality.collector_distance_importance, distance_to_collector) ], distance_penalty) value = float( Entities.buildings[BUILDINGS.BRICKYARD].radius ) / distance + alignment * personality.alignment_importance return BrickyardEvaluator(area_builder, builder, value) @property def purpose(self): return BUILDING_PURPOSE.BRICKYARD AbstractBrickyard.register_buildings() decorators.bind_all(AbstractBrickyard) decorators.bind_all(BrickyardEvaluator)
for building_worldid, distance in reachable[coords]: if building_worldid not in actual_distance or actual_distance[building_worldid] > distance: actual_distance[building_worldid] = distance if not actual_distance: continue usefulness = min(len(actual_distance), self.personality.max_reasonably_served_buildings) for distance in actual_distance.itervalues(): usefulness += 1.0 / (distance + self.personality.collector_extra_distance) alignment = 1 for tile in self.production_builder.iter_neighbour_tiles(builder.position): coords = (tile.x, tile.y) if coords not in self.production_builder.plan or self.production_builder.plan[coords][0] != BUILDING_PURPOSE.NONE: alignment += 1 value = usefulness + alignment * self.personality.alignment_coefficient options.append((value, builder)) return self.production_builder.build_best_option(options, BUILDING_PURPOSE.STORAGE) def execute(self): result = self._build_extra_road() if result == BUILD_RESULT.IMPOSSIBLE: if self.production_builder.last_collector_improvement_storage + self.personality.collector_improvement_storage_expires <= Scheduler().cur_tick: result = self._build_extra_storage() self._log_generic_build_result(result, 'storage') return self._translate_build_result(result) decorators.bind_all(ImproveCollectorCoverageGoal)
value -= personality.remove_unused_pasture_penalty elif old_field_purpose == BUILDING_PURPOSE.SUGARCANE_FIELD: value -= personality.remove_unused_sugarcane_field_penalty elif old_field_purpose == BUILDING_PURPOSE.TOBACCO_FIELD: value -= personality.remove_unused_tobacco_field_penalty return ModifiedFieldEvaluator(area_builder, builder, value, old_field_purpose) def execute(self): if not self.builder.have_resources(): return (BUILD_RESULT.NEED_RESOURCES, None) building = self.builder.execute() if not building: self.log.debug('%s, unknown error', self) return (BUILD_RESULT.UNKNOWN_ERROR, None) # remove the old designation self.area_builder.unused_fields[self._old_field_purpose].remove( self.builder.point.to_tuple()) return (BUILD_RESULT.OK, building) AbstractFarm.register_buildings() FarmEvaluator.init_field_offsets() decorators.bind_all(AbstractFarm) decorators.bind_all(FarmEvaluator) decorators.bind_all(ModifiedFieldEvaluator)
self._handle_farm_removal(building) super(ProductionBuilder, self).remove_building(building) def manage_production(self): """Pauses and resumes production buildings when they have full output inventories.""" for building in self.production_buildings: for production in building._get_productions(): all_full = True # inventory full of the produced resources? to_check = production._prod_line.production if building.id != BUILDINGS.CLAY_PIT_CLASS else production.get_produced_res() for resource_id in to_check: if production.inventory.get_free_space_for(resource_id) > 0: all_full = False break if all_full: if not production.is_paused(): ToggleActive(building, production).execute(self.land_manager.session) self.log.info('%s paused a production at %s/%d', self, building.name, building.worldid) else: if production.is_paused(): ToggleActive(building, production).execute(self.land_manager.session) self.log.info('%s resumed a production at %s/%d', self, building.name, building.worldid) def __str__(self): return '%s.PB(%s/%d)' % (self.owner, self.settlement.name if hasattr(self, 'settlement') else 'unknown', self.worldid) decorators.bind_all(ProductionBuilder)
self.personality.collector_extra_distance) alignment = 1 for tile in self.production_builder.iter_neighbor_tiles( builder.position): coords = (tile.x, tile.y) if coords not in self.production_builder.plan or self.production_builder.plan[ coords][0] != BUILDING_PURPOSE.NONE: alignment += 1 value = usefulness + alignment * self.personality.alignment_coefficient options.append((value, builder)) return self.production_builder.build_best_option( options, BUILDING_PURPOSE.STORAGE) def execute(self): result = self._build_extra_road() if result == BUILD_RESULT.IMPOSSIBLE: if self.production_builder.last_collector_improvement_storage + self.personality.collector_improvement_storage_expires <= Scheduler( ).cur_tick: result = self._build_extra_storage() if result == BUILD_RESULT.OK: self.production_builder.last_collector_improvement_storage = Scheduler( ).cur_tick self._log_generic_build_result(result, 'storage') return self._translate_build_result(result) decorators.bind_all(ImproveCollectorCoverageGoal)
# This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the # Free Software Foundation, Inc., # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # ################################################### from horizons.ai.aiplayer.building import AbstractBuilding from horizons.ai.aiplayer.goal.settlementgoal import SettlementGoal from horizons.constants import BUILDINGS from horizons.util.python import decorators class SignalFireGoal(SettlementGoal): def get_personality_name(self): return 'SignalFireGoal' @property def active(self): return super(SignalFireGoal, self).active and not self.settlement.count_buildings(BUILDINGS.SIGNAL_FIRE) def execute(self): result = AbstractBuilding.buildings[BUILDINGS.SIGNAL_FIRE].build(self.settlement_manager, None)[0] self._log_generic_build_result(result, 'signal fire') return self._translate_build_result(result) decorators.bind_all(SignalFireGoal)
if abs(amount - self.quotas[quota_holder]) < 1e-7: pass elif amount < self.quotas[quota_holder]: # lower the amount of reserved import change = self.quotas[quota_holder] - amount self.available += change self.quotas[quota_holder] -= change else: # raise the amount of reserved import change = min(amount - self.quotas[quota_holder], self.available) self.available -= change self.quotas[quota_holder] += change def __str__(self): if not hasattr(self, "resource_id"): return "UninitializedSingleResourceTradeManager" result = 'Resource %d import %.5f/%.5f' % (self.resource_id, self.available, self.total) for quota_holder, quota in self.quotas.iteritems(): result += '\n quota assignment %.5f to %s' % (quota, quota_holder) for settlement_manager_id, amount in self.partners.iteritems(): try: settlement = WorldObject.get_object_by_id(settlement_manager_id).settlement settlement_name = settlement.get_component(NamedComponent).name except WorldObjectNotFound: settlement_name = 'unknown' result += '\n import %.5f from %s' % (amount, settlement_name) return result decorators.bind_all(TradeManager) decorators.bind_all(SingleResourceTradeManager)
# (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the # Free Software Foundation, Inc., # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # ################################################### from horizons.ai.aiplayer.goal.settlementgoal import SettlementGoal from horizons.util.python import decorators class TentGoal(SettlementGoal): def get_personality_name(self): return 'TentGoal' @property def active(self): return super(TentGoal, self).active and len(self.settlement_manager.village_builder.tent_queue) > 0 def execute(self): result = self.settlement_manager.village_builder.build_tent() self._log_generic_build_result(result, 'tent') return self._translate_build_result(result) decorators.bind_all(TentGoal)
building_class.size]: yield (coords[0], coords[1], 0) @property def evaluator_class(self): return ClayPitEvaluator @classmethod def register_buildings(cls): cls._available_buildings[BUILDINGS.CLAY_PIT] = cls class ClayPitEvaluator(BuildingEvaluator): @classmethod def create(cls, area_builder, x, y, orientation): builder = BasicBuilder.create(BUILDINGS.CLAY_PIT, (x, y), orientation) distance_to_collector = cls._distance_to_nearest_collector( area_builder, builder, False) value = 1.0 / (distance_to_collector + 1) return ClayPitEvaluator(area_builder, builder, value) @property def purpose(self): return BUILDING_PURPOSE.CLAY_PIT AbstractClayPit.register_buildings() decorators.bind_all(AbstractClayPit) decorators.bind_all(ClayPitEvaluator)
class FireStationEvaluator(BuildingEvaluator): need_collector_connection = False record_plan_change = False @classmethod def create(cls, production_builder, x, y, orientation): settlement_manager = production_builder.settlement_manager village_builder = settlement_manager.village_builder builder = BasicBuilder.create(BUILDINGS.FIRE_STATION, (x, y), orientation) assigned_residences = village_builder.special_building_assignments[BUILDING_PURPOSE.FIRE_STATION][(x, y)] total = len(assigned_residences) not_serviced = 0 for residence_coords in assigned_residences: if village_builder.plan[residence_coords][0] == BUILDING_PURPOSE.RESIDENCE: not_serviced += 1 if not_serviced <= 0 or not_serviced < total * settlement_manager.owner.personality_manager.get('AbstractFireStation').fraction_of_assigned_residences_built: return None return FireStationEvaluator(village_builder, builder, not_serviced) @property def purpose(self): return BUILDING_PURPOSE.FIRE_STATION AbstractFireStation.register_buildings() decorators.bind_all(AbstractFireStation) decorators.bind_all(FireStationEvaluator)
if best_sale is None or best_sale[0] < total_price: best_sale = (total_price, tradable_amount, resource_id) else: if best_buy is None or best_buy[1] < tradable_amount: best_buy = (total_price, tradable_amount, resource_id) buy_coefficient = self.personality.buy_coefficient_rich if self.owner.get_component( StorageComponent ).inventory[ RES. GOLD] > self.personality.little_money else self.personality.buy_coefficient_poor total_value = (best_sale[0] if best_sale else 0) + ( best_buy[1] if best_buy else 0) * buy_coefficient final_options.append( (total_value, best_buy[2] if best_buy else None, best_sale[2] if best_sale else None, settlement, settlement_manager)) bought_resource, sold_resource, settlement, settlement_manager = max( final_options)[1:] self.owner.start_mission( InternationalTrade(settlement_manager, settlement, ship, bought_resource, sold_resource, self.owner.report_success, self.owner.report_failure)) def tick(self): self._add_route() decorators.bind_all(InternationalTradeManager)
# the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the # Free Software Foundation, Inc., # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # ################################################### from fakeresourcedeposit import AbstractFakeResourceDeposit from horizons.constants import BUILDINGS from horizons.util.python import decorators class AbstractClayDeposit(AbstractFakeResourceDeposit): @classmethod def get_higher_level_building_id(cls): return BUILDINGS.CLAY_PIT @classmethod def register_buildings(cls): cls._available_buildings[BUILDINGS.CLAY_DEPOSIT] = cls AbstractClayDeposit.register_buildings() decorators.bind_all(AbstractClayDeposit)
alignment = cls._get_alignment_from_outline(area_builder, cls._get_outline(x, y)) value = area_value + alignment * personality.alignment_importance return LumberjackEvaluator(area_builder, builder, value) @property def purpose(self): return BUILDING_PURPOSE.LUMBERJACK def execute(self): (result, building) = super(LumberjackEvaluator, self).execute() if result != BUILD_RESULT.OK: return (result, None) for coords in building.position.get_radius_coordinates( Entities.buildings[BUILDINGS.LUMBERJACK].radius): if coords in self.area_builder.plan and self.area_builder.plan[ coords][0] == BUILDING_PURPOSE.NONE: self.area_builder.register_change(coords[0], coords[1], BUILDING_PURPOSE.TREE, None) # TODO: don't ignore the return value Builder.create(BUILDINGS.TREE, self.area_builder.land_manager, Point(coords[0], coords[1])).execute() return (BUILD_RESULT.OK, building) AbstractLumberjack.register_buildings() decorators.bind_all(AbstractLumberjack) decorators.bind_all(LumberjackEvaluator)
blue = player.color.b for settlement in player.settlements: for tile in settlement.ground_map.itervalues(): renderer.addColored(tile._instance, red, green, blue) else: # 'hide' functionality renderer.removeAllColored() def toggle_translucency(self): """Make certain building types translucent""" worldutils.toggle_translucency(self) def toggle_health_for_all_health_instances(self): worldutils.toggle_health_for_all_health_instances(self) def load_building(session, db, typeid, worldid): """Loads a saved building. Don't load buildings yourself in the game code.""" return Entities.buildings[typeid].load(session, db, worldid) def load_raw_world(map_file): WorldObject.reset() world = World(session=None) world.inited = True world.load_raw_map(SavegameAccessor(map_file, True), preview=True) return world decorators.bind_all(World) decorators.bind_all(load_building)
area_builder, builder, BUILDINGS.LUMBERJACK) alignment = cls._get_alignment(area_builder, builder.position.tuple_iter()) personality = area_builder.owner.personality_manager.get( 'ToolmakerEvaluator') distance_penalty = Entities.buildings[ BUILDINGS.TOOLMAKER].radius * personality.distance_penalty distance = cls._weighted_distance( distance_to_collector, [(personality.smeltery_distance_importance, distance_to_smeltery), (personality.charcoal_burner_distance_importance, distance_to_charcoal_burner), (personality.lumberjack_distance_importance, distance_to_lumberjack)], distance_penalty) value = float( Entities.buildings[BUILDINGS.TOOLMAKER].radius ) / distance + alignment * personality.alignment_importance return ToolmakerEvaluator(area_builder, builder, value) @property def purpose(self): return BUILDING_PURPOSE.BRICKYARD AbstractToolmaker.register_buildings() decorators.bind_all(AbstractToolmaker) decorators.bind_all(ToolmakerEvaluator)
while heap: (_, distance_so_far, key) = heapq.heappop(heap) if distance[key] < distance_so_far: continue if (key[0], key[1]) in destination: final_key = key break for dir in xrange(4): coords = (key[0] + moves[dir][0], key[1] + moves[dir][1]) if coords not in path_nodes or coords in blocked_coords: continue reduced_dir = 0 if moves[dir][0] != 0 else 1 next_key = (coords[0], coords[1], reduced_dir) real_distance = distance_so_far + path_nodes[coords] + (0 if reduced_dir == key[2] else personality.turn_penalty) expected_distance = real_distance + destination_beacon.distance_to_tuple(coords) if next_key not in distance or distance[next_key][0] > real_distance: distance[next_key] = (real_distance, key) heapq.heappush(heap, (expected_distance, real_distance, next_key)) # save path if final_key is not None: path = [] while final_key is not None: path.append((final_key[0], final_key[1])) final_key = distance[final_key][1] return path return None decorators.bind_all(RoadPlanner)
# GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the # Free Software Foundation, Inc., # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # ################################################### from horizons.ai.aiplayer.goal.settlementgoal import SettlementGoal from horizons.constants import BUILDINGS from horizons.util.python import decorators class CombatShipGoal(SettlementGoal): def get_personality_name(self): return 'CombatShipGoal' @property def active(self): return super(CombatShipGoal, self).active \ and self.owner.count_buildings(BUILDINGS.BOAT_BUILDER) \ and self.owner.need_more_combat_ships \ and not self.owner.unit_builder.num_ships_being_built def execute(self): self.settlement_manager.log.info('%s start building frigate', self) self.owner.unit_builder.build_combat_ship() decorators.bind_all(CombatShipGoal)
def producer_building(self): """Return a boolean showing whether this building is supposed to have usable production lines.""" return True def get_evaluators(self, settlement_manager, resource_id): """Return a list of every BuildingEvaluator for this building type in the given settlement.""" options = [] # [BuildingEvaluator, ...] for x, y, orientation in self.iter_potential_locations(settlement_manager): evaluator = self.evaluator_class.create(settlement_manager.production_builder, x, y, orientation) if evaluator is not None: options.append(evaluator) return options def build(self, settlement_manager, resource_id): """Try to build the best possible instance of this building in the given settlement. Returns (BUILD_RESULT constant, building instance).""" if not self.have_resources(settlement_manager): return (BUILD_RESULT.NEED_RESOURCES, None) for evaluator in sorted(self.get_evaluators(settlement_manager, resource_id)): result = evaluator.execute() if result[0] != BUILD_RESULT.IMPOSSIBLE: return result self.log.debug('%s.build(%s, %d): no possible evaluators', self.__class__.__name__, settlement_manager, resource_id if resource_id else -1) return (BUILD_RESULT.IMPOSSIBLE, None) def need_to_build_more_buildings(self, settlement_manager, resource_id): """Return a boolean showing whether another instance of the building should be built right now regardless of the production capacity.""" return False decorators.bind_all(AbstractBuilding)
def early_end(self): """Called to speed up session destruction.""" assert self._enabled self._enabled = False SettlementRangeChanged.unsubscribe(self._on_settlement_range_changed) def end(self): assert not self._enabled self.personality_manager = None self.world = None self.islands = None self.settlement_managers = None self._settlement_manager_by_settlement_id = None self.missions = None self.fishers = None self.settlement_founder = None self.unit_builder = None self.unit_manager = None self.behavior_manager = None self.combat_manager = None self.settlement_expansions = None self.goals = None self.special_domestic_trade_manager = None self.international_trade_manager = None self.strategy_manager.end() self.strategy_manager = None super(AIPlayer, self).end() decorators.bind_all(AIPlayer)
@classmethod def get_settings(cls, level): if level not in cls.levels: return None return cls.levels[level](level) @classmethod def register_levels(cls): cls.levels[cls.EASY_LEVEL] = EasySettings cls.levels[cls.DEFAULT_LEVEL] = DefaultSettings class DifficultyClass(object): def __init__(self, level): self.level = level class DefaultSettings(DifficultyClass): extra_happiness_constant = 0 happiness_multiplier = 1 tax_multiplier = 1 class EasySettings(DefaultSettings): tax_multiplier = 1.5 DifficultySettings.register_levels() decorators.bind_all(DifficultySettings) decorators.bind_all(DifficultyClass) decorators.bind_all(DefaultSettings) decorators.bind_all(EasySettings)
self.log.info('%s reached the other warehouse area (%s)', self, self.settlement.get_component(NamedComponent).name) if self.sold_resource is not None: sellable_amount = self._get_max_sellable_amount(self.ship.get_component(StorageComponent).inventory[self.sold_resource]) if sellable_amount > 0: BuyResource(self.settlement.get_component(TradePostComponent), self.ship, self.sold_resource, sellable_amount).execute(self.owner.session) if self.bought_resource is None: self.report_success('Sold %d of resource %d' % (sellable_amount, self.sold_resource)) return else: self.log.info('%s sold %d of resource %d', self, sellable_amount, self.sold_resource) buyable_amount = self._get_max_buyable_amount() if buyable_amount <= 0: self.report_failure('No resources can be bought') return SellResource(self.settlement.get_component(TradePostComponent), self.ship, self.bought_resource, buyable_amount).execute(self.owner.session) self.log.info('%s bought %d of resource %d', self, buyable_amount, self.bought_resource) self.state = self.missionStates.returning_to_my_settlement self._return_to_my_settlement() def _return_to_my_settlement(self): self._move_to_warehouse_area(self.settlement_manager.settlement.warehouse.position, Callback(self._returned_to_my_settlement), Callback(self._return_to_my_settlement), 'Unable to return to %s' % self.settlement_manager.settlement.get_component(NamedComponent).name) def _returned_to_my_settlement(self): self._unload_all_resources(self.settlement_manager.settlement) self.report_success('Unloaded the bought resources at %s' % self.settlement_manager.settlement.get_component(NamedComponent).name) decorators.bind_all(InternationalTrade)
class DoNothingGoal(Goal): """This goal makes the AI not do anything during a tick.""" def get_personality_name(self): return 'DoNothingGoal' @property def priority(self): return self._priority @property def active(self): return super(DoNothingGoal, self).active and self._is_active def update(self): """ whether to do nothing and if so then how important it is """ if self.owner.session.random.random() >= self.personality.likelihood: # don't be lazy self._is_active = False self._priority = 0 else: # be lazy self._is_active = True self._priority = self.owner.session.random.gauss(self.personality.default_priority, self.personality.priority_variance) def execute(self): # do nothing return GOAL_RESULT.BLOCK_ALL_BUILDING_ACTIONS decorators.bind_all(DoNothingGoal)
def get_personality_name(self): return 'FoundFeederIslandGoal' def _need_feeder_island(self): return self.production_builder.count_available_squares( 3, self.personality.feeder_island_requirement_cutoff )[1] < self.personality.feeder_island_requirement_cutoff def _have_feeder_island(self): for settlement_manager in self.owner.settlement_managers: if settlement_manager.feeder_island: available_squares = settlement_manager.production_builder.count_available_squares( 3, self.personality.usable_feeder_island_cutoff)[1] if available_squares >= self.personality.usable_feeder_island_cutoff: return True return False @property def active(self): return super(FoundFeederIslandGoal, self).active and self._need_feeder_island() and not self._have_feeder_island() and \ self.owner.settlement_founder.can_found_feeder_island() def execute(self): self.settlement_manager.log.info( '%s waiting for a feeder islands to be founded', self) self.owner.settlement_founder.found_feeder_island() return GOAL_RESULT.BLOCK_SETTLEMENT_RESOURCE_USAGE decorators.bind_all(FoundFeederIslandGoal)