def build(self, settlement_manager, resource_id):
		village_builder = settlement_manager.village_builder
		building_purpose = self.get_purpose(resource_id)
		building_id = BUILDING_PURPOSE.get_building(building_purpose)
		building_class = Entities.buildings[building_id]

		for coords, (purpose, (section, _)) in village_builder.plan.iteritems():
			if section > village_builder.current_section or purpose != building_purpose:
				continue

			object = village_builder.land_manager.island.ground_map[coords].object
			if object is not None and object.id == self.id:
				continue

			if building_purpose != BUILDING_PURPOSE.MAIN_SQUARE:
				if not self._need_producer(settlement_manager, coords, resource_id):
					continue

			if not village_builder.have_resources(building_id):
				return (BUILD_RESULT.NEED_RESOURCES, None)
			if coords not in village_builder.settlement.buildability_cache.cache[building_class.size]:
				position = Rect.init_from_topleft_and_size_tuples(coords, building_class.size)
				return (BUILD_RESULT.OUT_OF_SETTLEMENT, position)

			building = BasicBuilder(building_id, coords, 0).execute(settlement_manager.land_manager)
			assert building
			if self.get_purpose(resource_id) == BUILDING_PURPOSE.MAIN_SQUARE and not village_builder.roads_built:
				village_builder.build_roads()
			return (BUILD_RESULT.OK, building)
		return (BUILD_RESULT.SKIP, None)
Ejemplo n.º 2
0
	def _create_village_producer_assignments(self):
		"""
		Create an assignment of residence spots to village producer spots.

		This is useful for deciding which of the village producers would be most useful.
		"""

		self.producer_assignment = {} # {BUILDING_PURPOSE constant: {village producer coordinates: [residence coordinates, ...]}}
		purposes = [BUILDING_PURPOSE.PAVILION, BUILDING_PURPOSE.VILLAGE_SCHOOL, BUILDING_PURPOSE.TAVERN]
		residence_positions = self._get_sorted_residence_positions()
		residence_range = Entities.buildings[BUILDINGS.RESIDENTIAL_CLASS].radius

		for purpose in purposes:
			producer_positions = sorted(self._get_position(coords, BUILDING_PURPOSE.get_building(purpose)) for coords, (pos_purpose, _) in self.plan.iteritems() if pos_purpose == purpose)
			self.producer_assignment[purpose] = {}
			for producer_position in producer_positions:
				self.producer_assignment[purpose][producer_position.origin.to_tuple()] = []

			options = []
			for producer_position in producer_positions:
				for position in residence_positions:
					distance = producer_position.distance(position)
					if distance <= residence_range:
						options.append((distance, producer_position.origin.to_tuple(), position.origin.to_tuple()))
			options.sort(reverse = True)

			assigned_residence_coords = set()
			for _, producer_coords, residence_coords in options:
				if residence_coords in assigned_residence_coords:
					continue
				if len(self.producer_assignment[purpose][producer_coords]) >= self.personality.max_coverage_building_capacity:
					continue
				assigned_residence_coords.add(residence_coords)
				self.producer_assignment[purpose][producer_coords].append(residence_coords)
Ejemplo n.º 3
0
    def _create_special_village_building_assignments(self):
        """
		Create an assignment of residence spots to special village building spots.

		This is useful for deciding which of the special village buildings would be most useful.
		"""

        distance_rect_rect = distances.distance_rect_rect
        self.special_building_assignments = {
        }  # {BUILDING_PURPOSE constant: {village producer coordinates: [residence coordinates, ...]}}
        residence_positions = self._get_sorted_building_positions(
            BUILDING_PURPOSE.RESIDENCE)

        building_types = []
        for purpose in [
                BUILDING_PURPOSE.PAVILION, BUILDING_PURPOSE.VILLAGE_SCHOOL,
                BUILDING_PURPOSE.TAVERN
        ]:
            building_types.append(
                (purpose, Entities.buildings[BUILDINGS.RESIDENTIAL].radius,
                 self.personality.max_coverage_building_capacity))
        building_types.append(
            (BUILDING_PURPOSE.FIRE_STATION,
             Entities.buildings[BUILDINGS.FIRE_STATION].radius,
             self.personality.max_fire_station_capacity))
        building_types.append((BUILDING_PURPOSE.DOCTOR,
                               Entities.buildings[BUILDINGS.DOCTOR].radius,
                               self.personality.max_doctor_capacity))

        for purpose, range, max_capacity in building_types:
            producer_positions = sorted(
                self._get_position(coords,
                                   BUILDING_PURPOSE.get_building(purpose))
                for coords, (pos_purpose, _) in self.plan.iteritems()
                if pos_purpose == purpose)
            self.special_building_assignments[purpose] = {}
            for producer_position in producer_positions:
                self.special_building_assignments[purpose][
                    producer_position.origin.to_tuple()] = []

            options = []
            for producer_position in producer_positions:
                for position in residence_positions:
                    distance = distance_rect_rect(producer_position, position)
                    if distance <= range:
                        options.append(
                            (distance, producer_position.origin.to_tuple(),
                             position.origin.to_tuple()))
            options.sort(reverse=True)

            assigned_residence_coords = set()
            for _, producer_coords, residence_coords in options:
                if residence_coords in assigned_residence_coords:
                    continue
                if len(self.special_building_assignments[purpose]
                       [producer_coords]) >= max_capacity:
                    continue
                assigned_residence_coords.add(residence_coords)
                self.special_building_assignments[purpose][
                    producer_coords].append(residence_coords)
Ejemplo n.º 4
0
	def build(self, settlement_manager, resource_id):
		village_builder = settlement_manager.village_builder
		building_purpose = self.get_purpose(resource_id)

		for coords, (purpose, (section, _)) in village_builder.plan.iteritems():
			if section > village_builder.current_section or purpose != building_purpose:
				continue

			object = village_builder.land_manager.island.ground_map[coords].object
			if object is not None and object.id == self.id:
				continue

			if building_purpose != BUILDING_PURPOSE.MAIN_SQUARE:
				if not self._need_producer(settlement_manager, coords, resource_id):
					continue

			builder = village_builder.make_builder(BUILDING_PURPOSE.get_building(purpose), coords[0], coords[1], False)
			if not builder.have_resources():
				return (BUILD_RESULT.NEED_RESOURCES, None)
			if not self.in_settlement(settlement_manager, builder.position):
				return (BUILD_RESULT.OUT_OF_SETTLEMENT, builder.position)

			building = builder.execute()
			if not building:
				return (BUILD_RESULT.UNKNOWN_ERROR, None)
			if self.get_purpose(resource_id) == BUILDING_PURPOSE.MAIN_SQUARE and not village_builder.roads_built:
				village_builder.build_roads()
			return (BUILD_RESULT.OK, building)
		return (BUILD_RESULT.SKIP, None)
	def build(self, settlement_manager, resource_id):
		village_builder = settlement_manager.village_builder
		building_purpose = self.get_purpose(resource_id)

		for coords, (purpose, (section, _)) in village_builder.plan.iteritems():
			if section > village_builder.current_section or purpose != building_purpose:
				continue

			object = village_builder.land_manager.island.ground_map[coords].object
			if object is not None and object.id == self.id:
				continue

			if building_purpose != BUILDING_PURPOSE.MAIN_SQUARE:
				if not self._need_producer(settlement_manager, coords, resource_id):
					continue

			builder = village_builder.make_builder(BUILDING_PURPOSE.get_building(purpose), coords[0], coords[1], False)
			if not builder.have_resources():
				return (BUILD_RESULT.NEED_RESOURCES, None)
			if not self.in_settlement(settlement_manager, builder.position):
				return (BUILD_RESULT.OUT_OF_SETTLEMENT, builder.position)

			building = builder.execute()
			if not building:
				return (BUILD_RESULT.UNKNOWN_ERROR, None)
			if self.get_purpose(resource_id) == BUILDING_PURPOSE.MAIN_SQUARE and not village_builder.roads_built:
				village_builder.build_roads()
			return (BUILD_RESULT.OK, building)
		return (BUILD_RESULT.SKIP, None)
	def _need_producer(self, settlement_manager, coords, resource_id):
		if not settlement_manager.settlement.count_buildings(BUILDING_PURPOSE.get_building(self.get_purpose(resource_id))):
			return True # if none exist and we need the resource then build it
		assigned_residences = settlement_manager.village_builder.special_building_assignments[self.get_purpose(resource_id)][coords]
		total = len(assigned_residences)
		not_serviced = 0
		for residence_coords in assigned_residences:
			if settlement_manager.village_builder.plan[residence_coords][0] != BUILDING_PURPOSE.RESIDENCE:
				continue
			not_serviced += 1

		if not_serviced > 0 and not_serviced >= total * settlement_manager.owner.personality_manager.get('AbstractVillageBuilding').fraction_of_assigned_residences_built:
			return True
		return False
	def _need_producer(self, settlement_manager, coords, resource_id):
		if not settlement_manager.settlement.count_buildings(BUILDING_PURPOSE.get_building(self.get_purpose(resource_id))):
			return True # if none exist and we need the resource then build it
		assigned_residences = settlement_manager.village_builder.special_building_assignments[self.get_purpose(resource_id)][coords]
		total = len(assigned_residences)
		not_serviced = 0
		for residence_coords in assigned_residences:
			if settlement_manager.village_builder.plan[residence_coords][0] != BUILDING_PURPOSE.RESIDENCE:
				continue
			not_serviced += 1

		if not_serviced > 0 and not_serviced >= total * settlement_manager.owner.personality_manager.get('AbstractVillageBuilding').fraction_of_assigned_residences_built:
			return True
		return False
Ejemplo n.º 8
0
	def _create_special_village_building_assignments(self):
		"""
		Create an assignment of residence spots to special village building spots.

		This is useful for deciding which of the special village buildings would be most useful.
		"""

		distance_rect_rect = distances.distance_rect_rect
		self.special_building_assignments = {} # {BUILDING_PURPOSE constant: {village producer coordinates: [residence coordinates, ...]}}
		residence_positions = self._get_sorted_building_positions(BUILDING_PURPOSE.RESIDENCE)

		building_types = []
		for purpose in [BUILDING_PURPOSE.PAVILION, BUILDING_PURPOSE.VILLAGE_SCHOOL, BUILDING_PURPOSE.TAVERN]:
			building_types.append((purpose, Entities.buildings[BUILDINGS.RESIDENTIAL].radius, self.personality.max_coverage_building_capacity))
		building_types.append((BUILDING_PURPOSE.FIRE_STATION, Entities.buildings[BUILDINGS.FIRE_STATION].radius, self.personality.max_fire_station_capacity))
		building_types.append((BUILDING_PURPOSE.DOCTOR, Entities.buildings[BUILDINGS.DOCTOR].radius, self.personality.max_doctor_capacity))

		for purpose, range, max_capacity in building_types:
			producer_positions = sorted(self._get_position(coords, BUILDING_PURPOSE.get_building(purpose)) for coords, (pos_purpose, _) in self.plan.iteritems() if pos_purpose == purpose)
			self.special_building_assignments[purpose] = {}
			for producer_position in producer_positions:
				self.special_building_assignments[purpose][producer_position.origin.to_tuple()] = []

			options = []
			for producer_position in producer_positions:
				for position in residence_positions:
					distance = distance_rect_rect(producer_position, position)
					if distance <= range:
						options.append((distance, producer_position.origin.to_tuple(), position.origin.to_tuple()))
			options.sort(reverse = True)

			assigned_residence_coords = set()
			for _, producer_coords, residence_coords in options:
				if residence_coords in assigned_residence_coords:
					continue
				if len(self.special_building_assignments[purpose][producer_coords]) >= max_capacity:
					continue
				assigned_residence_coords.add(residence_coords)
				self.special_building_assignments[purpose][producer_coords].append(residence_coords)
    def build(self, settlement_manager, resource_id):
        village_builder = settlement_manager.village_builder
        building_purpose = self.get_purpose(resource_id)
        building_id = BUILDING_PURPOSE.get_building(building_purpose)
        building_class = Entities.buildings[building_id]

        for coords, (purpose, (section,
                               _)) in village_builder.plan.iteritems():
            if section > village_builder.current_section or purpose != building_purpose:
                continue

            object = village_builder.land_manager.island.ground_map[
                coords].object
            if object is not None and object.id == self.id:
                continue

            if building_purpose != BUILDING_PURPOSE.MAIN_SQUARE:
                if not self._need_producer(settlement_manager, coords,
                                           resource_id):
                    continue

            if not village_builder.have_resources(building_id):
                return (BUILD_RESULT.NEED_RESOURCES, None)
            if coords not in village_builder.settlement.buildability_cache.cache[
                    building_class.size]:
                position = Rect.init_from_topleft_and_size_tuples(
                    coords, building_class.size)
                return (BUILD_RESULT.OUT_OF_SETTLEMENT, position)

            building = BasicBuilder(building_id, coords,
                                    0).execute(settlement_manager.land_manager)
            assert building
            if self.get_purpose(
                    resource_id
            ) == BUILDING_PURPOSE.MAIN_SQUARE and not village_builder.roads_built:
                village_builder.build_roads()
            return (BUILD_RESULT.OK, building)
        return (BUILD_RESULT.SKIP, None)
Ejemplo n.º 10
0
    def handle_lost_area(self, coords_list):
        """
		Handle losing the potential land in the given coordinates list.

		Take the following actions:
		* remove the lost area from the village and road areas
		* remove village sections with impossible main squares
		* remove all planned buildings that are now impossible
		* TODO: if the village area takes too much of the total area then remove / reduce the remaining sections
		"""

        # remove village sections with impossible main squares
        removed_sections = set()
        for coords, (purpose, (section, _)) in self.plan.iteritems():
            if purpose != BUILDING_PURPOSE.MAIN_SQUARE:
                continue
            possible = True
            for main_square_coords in self._get_position(
                    coords, BUILDINGS.MAIN_SQUARE).tuple_iter():
                if main_square_coords not in self.land_manager.village:
                    possible = False
                    break
            if not possible:
                # impossible to build the main square because a part of the area is owned by another player: remove the whole section
                removed_sections.add(section)

        removed_coords_list = []
        for coords, (purpose, (section, _)) in self.plan.iteritems():
            if purpose == BUILDING_PURPOSE.RESERVED or purpose == BUILDING_PURPOSE.NONE:
                continue
            position = self._get_position(
                coords, BUILDING_PURPOSE.get_building(purpose))
            building = self.settlement.ground_map[
                coords].object if coords in self.settlement.ground_map else None

            if section in removed_sections:
                if purpose == BUILDING_PURPOSE.ROAD:
                    if building is None or building.id != BUILDINGS.TRAIL:
                        removed_coords_list.append(coords)
                    continue  # leave existing roads behind
                elif building is not None and not building.buildable_upon:
                    # TODO: remove the actual building
                    pass

                for building_coords in position.tuple_iter():
                    removed_coords_list.append(building_coords)
            else:
                # remove the planned village buildings that are no longer possible
                if purpose == BUILDING_PURPOSE.ROAD:
                    if coords not in self.land_manager.village:
                        removed_coords_list.append(coords)
                    continue

                possible = True
                for building_coords in position.tuple_iter():
                    if building_coords not in self.land_manager.village:
                        possible = False
                if possible:
                    continue

                for building_coords in position.tuple_iter():
                    removed_coords_list.append(building_coords)

        for coords in removed_coords_list:
            del self.plan[coords]
        self._recreate_tent_queue()
        # TODO: renumber the sections
        # TODO: create a new plan with village producers
        self._return_unused_space()
        self._create_special_village_building_assignments()
        super(VillageBuilder, self).handle_lost_area(coords_list)
Ejemplo n.º 11
0
	def handle_lost_area(self, coords_list):
		"""
		Handle losing the potential land in the given coordinates list.

		Take the following actions:
		* remove the lost area from the village and road areas
		* remove village sections with impossible main squares
		* remove all planned buildings that are now impossible
		* TODO: if the village area takes too much of the total area then remove / reduce the remaining sections
		"""

		# remove village sections with impossible main squares
		removed_sections = set()
		for coords, (purpose, (section, _)) in self.plan.iteritems():
			if purpose != BUILDING_PURPOSE.MAIN_SQUARE:
				continue
			possible = True
			for main_square_coords in self._get_position(coords, BUILDINGS.MAIN_SQUARE_CLASS).tuple_iter():
				if main_square_coords not in self.land_manager.village:
					possible = False
					break
			if not possible:
				# impossible to build the main square because a part of the area is owned by another player: remove the whole section
				removed_sections.add(section)

		removed_coords_list = []
		for coords, (purpose, (section, _)) in self.plan.iteritems():
			if purpose == BUILDING_PURPOSE.RESERVED or purpose == BUILDING_PURPOSE.NONE:
				continue
			position = self._get_position(coords, BUILDING_PURPOSE.get_building(purpose))
			building = self.settlement.ground_map[coords].object if coords in self.settlement.ground_map else None

			if section in removed_sections:
				if purpose == BUILDING_PURPOSE.ROAD:
					if building is None or building.id != BUILDINGS.TRAIL_CLASS:
						removed_coords_list.append(coords)
					continue # leave existing roads behind
				elif building is not None and not building.buildable_upon:
					# TODO: remove the actual building
					pass

				for building_coords in position.tuple_iter():
					removed_coords_list.append(building_coords)
			else:
				# remove the planned village buildings that are no longer possible
				if purpose == BUILDING_PURPOSE.ROAD:
					if coords not in self.land_manager.village:
						removed_coords_list.append(coords)
					continue

				possible = True
				for building_coords in position.tuple_iter():
					if building_coords not in self.land_manager.village:
						possible = False
				if possible:
					continue

				for building_coords in position.tuple_iter():
					removed_coords_list.append(building_coords)

		for coords in removed_coords_list:
			del self.plan[coords]
		self._recreate_tent_queue()
		# TODO: renumber the sections
		# TODO: create a new plan with village producers
		self._return_unused_space()
		self._create_village_producer_assignments()
		super(VillageBuilder, self).handle_lost_area(coords_list)