Example #1
0
            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)
Example #4
0
	"""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)
Example #6
0
# 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)
Example #8
0
	@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)
Example #9
0
                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)
Example #10
0
#
# 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)
Example #11
0
        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)
Example #14
0
            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)
Example #15
0
		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)
Example #18
0
        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)
Example #21
0
		# 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)
Example #22
0
            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)
Example #24
0
	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)
	"""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)
	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)
Example #30
0
		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)
Example #32
0
        """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)
Example #33
0
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)
Example #34
0
		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)
Example #36
0
        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)
Example #38
0
            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)
Example #40
0
            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)
Example #42
0
                                     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)
Example #43
0
# 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)
Example #45
0
# (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)
Example #46
0
                        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)
Example #48
0
                    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)
Example #49
0
# 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)
Example #51
0
				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)
Example #52
0
            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)
Example #55
0
	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)
Example #56
0
    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)
Example #59
0
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)
Example #60
0
    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)