"""Create the produced unit now.""" productions = self._productions.values() for production in productions: assert isinstance(production, UnitProduction) self.on_production_finished(production.get_produced_units()) for unit, amount in production.get_produced_units().iteritems(): for i in xrange(0, amount): radius = 1 found_tile = False # search for free water tile, and increase search radius if none is found while not found_tile: for coord in Circle(self.instance.position.center(), radius).tuple_iter(): point = Point(coord[0], coord[1]) if self.instance.island.get_tile(point) is None: tile = self.session.world.get_tile(point) if tile is not None and tile.is_water and coord not in self.session.world.ship_map: # execute bypassing the manager, it's simulated on every machine u = CreateUnit(self.instance.owner.worldid, unit, point.x, point.y)(issuer=self.instance.owner) # Fire a message indicating that the ship has been created name = u.get_component(NamedComponent).name self.session.ingame_gui.message_widget.add(string_id='NEW_UNIT', point=point, message_dict={'name' : name}) found_tile = True break radius += 1 decorators.bind_all(Producer) decorators.bind_all(MineProducer) decorators.bind_all(QueueProducer) decorators.bind_all(UnitProducer)
for i in xrange(tries): # choose x-difference, then y-difference so that the distance is in the range. x_diff = randint(1, in_range) # always go at least 1 field y_max_diff = int( math.sqrt(range_squared - x_diff*x_diff) ) y_diff = randint(0, y_max_diff) # use randomness of x/y_diff below, randint calls are expensive # this results in a higher chance for x > y than y < x, so equalize if (x_diff + y_diff) % 2 == 0: x_diff, y_diff = y_diff, x_diff # direction if x_diff % 2 == 0: y_diff = -y_diff if y_diff % 2 == 0: x_diff = -x_diff # check this target possible_target = Point(self.position.x + x_diff, self.position.y + y_diff) path = self.check_move(possible_target) if path: return (possible_target, path) return (None, None) @property def classname(self): return self.session.db.get_unit_type_name(self.id) def __str__(self): # debug return '%s(id=%s;worldid=%s)' % (self.name, self.id, self.worldid if hasattr(self, 'worldid') else 'none') decorators.bind_all(Unit)
return smallest_fisher 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)
class BuildableSingleOnDeposit(BuildableSingle): """For mines; those buildings are only buildable upon other buildings (clay pit on clay deposit, e.g.) For now, mines can only be built on a single type of deposit. This is specified in game.sqlite in the table "mine", and saved in cls.buildable_on_deposit in the buildingclass. """ irregular_conditions = True @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]) decorators.bind_all(Buildable) decorators.bind_all(BuildableSingle) decorators.bind_all(BuildableRect) decorators.bind_all(BuildableSingleFromShip) decorators.bind_all(BuildableSingleOnCoast) decorators.bind_all(BuildableSingleOnDeposit)
path_length = 0 # length in ticks to travel the distance speed = self.get_unit_velocity() for i in xrange(1, len(path)): dx = abs(path[i - 1][0] - path[i][0]) dy = abs(path[i - 1][1] - path[i][1]) if dx and dy: path_length += speed[1] else: path_length += speed[0] return path_length def get_move_target(self): return self.path.get_move_target() def save(self, db): super(MovingObject, self).save(db) # NOTE: _move_action is currently not yet saved and neither is blocked_callback. self.path.save(db, self.worldid) def load(self, db, worldid): super(MovingObject, self).load(db, worldid) x, y = db("SELECT x, y FROM unit WHERE rowid = ?", worldid)[0] self.__init(x, y) path_loaded = self.path.load(db, worldid) if path_loaded: self.__is_moving = True self._setup_move() Scheduler().add_new_object(self._move_tick, self, run_in=0) decorators.bind_all(MovingObject)
def toggle_owner_highlight(self): renderer = self.session.view.renderer['InstanceRenderer'] self.owner_highlight_active = not self.owner_highlight_active if self.owner_highlight_active: #show for player in self.players: red = player.color.r green = player.color.g 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) decorators.bind_all(World) decorators.bind_all(load_building)
"""Runs necessary steps to deselect the ship.""" if self._selected: super(SelectableShipComponent, self).deselect() self.instance._update_buoy(remove_only=True) class SelectableFisherComponent(SelectableBuildingComponent): """Class used to highlight the radius of a fisher. Highlights only the fishing grounds.""" @classmethod def _do_select(cls, renderer, position, world, settlement, radius, range_applies_only_on_island): # No super, we don't want to color the ground cls._init_fake_tile() layer = world.session.view.layers[LAYERS.FIELDS] for fish_deposit in world.get_providers_in_range(RadiusRect(position, radius), res=RES.FISH): #renderer.addColored(fish_deposit._instance, *cls.selection_color) #cls._selected_tiles.l.append(fish_deposit) for pos in fish_deposit.position: cls._add_fake_tile(pos.x, pos.y, layer, renderer) """@classmethod def get_instance(cls, arguments): arguments = copy.copy(arguments) return SelectableFisherComponent( **arguments )""" decorators.bind_all(SelectableFisherComponent) decorators.bind_all(SelectableBuildingComponent) decorators.bind_all(SelectableShipComponent) decorators.bind_all(SelectableUnitComponent)
if shuffle_first: self.collector.session.random.shuffle(self) inventory = self.collector.get_home_inventory() self.sort(key=lambda job: min(inventory[res] for res in job.resources) , reverse=False) def _sort_jobs_fewest_available_and_distance(self): """Sort jobs by fewest available, but secondaryly also consider distance""" # python sort is stable, so two sequenced sorts work. self._sort_jobs_distance() self._sort_jobs_fewest_available(shuffle_first=False) def _sort_jobs_for_storage_collector(self): """Special sophisticated sorting routing for storage collectors. Same as fewest_available_and_distance_, but also considers whether target inv is full.""" self._sort_jobs_fewest_available_and_distance() self._sort_target_inventory_full() def _sort_jobs_distance(self): """Prefer targets that are nearer""" self.sort(key=lambda job: self.collector.position.distance(job.object.loading_area)) def _sort_target_inventory_full(self): """Prefer targets with full inventory""" self.sort(key=operator.attrgetter('target_inventory_full_num'), reverse=True) def __str__(self): return str([ str(i) for i in self ]) decorators.bind_all(Collector)
super(BuildRelatedBuildingToolLogic, self).__init__(building_tool) # instance must be weakref self.instance = instance def _reshow_tab(self): from horizons.gui.tabs import BuildRelatedTab self.instance().get_component(SelectableComponent).show_menu(jump_to_tabclass=BuildRelatedTab) def on_escape(self, session): super(BuildRelatedBuildingToolLogic, self).on_escape(session) self._reshow_tab() def continue_build(self): self._reshow_tab() def add_change_listener(self, instance, building_tool): pass # using messages now def remove_change_listener(self, instance, building_tool): pass def remove(self, session): super(BuildRelatedBuildingToolLogic, self).remove(session) decorators.bind_all(BuildingTool) decorators.bind_all(SettlementBuildingToolLogic) decorators.bind_all(ShipBuildingToolLogic) decorators.bind_all(BuildRelatedBuildingToolLogic)
if not self.kill_animal: self.log.debug("%s releasing animal %s",self, self.job.object) Scheduler().add_new_object(self.job.object.search_job, self.job.object, \ GAME_SPEED.TICKS_PER_SECOND) class FarmAnimalCollector(AnimalCollector): def get_animals_in_range(self, reslist=None): """Returns animals from buildings in range""" reach = RadiusRect(self.home_building.position, self.home_building.radius) # don't consider res when searching for buildings, since only their animals are # the acctual providers buildings = self.home_building.island.get_providers_in_range(reach) animal_lists = (building.animals for building in buildings if hasattr(building, 'animals')) # use overloaded + for lists here in sum return sum(animal_lists, []) class HunterCollector(AnimalCollector): kill_animal = True def get_animals_in_range(self, res=None): dist = self.home_building.position.distance_to_point radius = self.home_building.radius return [ animal for animal in self.home_building.island.wild_animals if \ dist(animal.position) <= radius ] decorators.bind_all(AnimalCollector) decorators.bind_all(FarmAnimalCollector) decorators.bind_all(HunterCollector)
class BuildableSingleOnDeposit(BuildableSingle): """For mines; those buildings are only buildable upon other buildings (clay pit on clay deposit, e.g.) For now, mines can only be built on a single type of deposit. This is specified in game.sqlite in the table "mine", and saved in cls.buildable_on_deposit in the buildingclass. """ @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() deposit = tile.object return set([deposit.worldid]) # apply make_constant to classes decorators.bind_all(Buildable) decorators.bind_all(BuildableSingle) decorators.bind_all(BuildableRect) decorators.bind_all(BuildableSingleFromShip) decorators.bind_all(BuildableSingleOnCoast) decorators.bind_all(BuildableSingleOnDeposit)
# set first action action = action_sets[action_set_id].keys()[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 #@decorators.relese_mode(ret="Building") 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)
return self.session.world.ground_unit_map def _check_for_obstacles(self, point): # retrieve island, island of soldier may change at any time island = self.session.world.get_island(self.unit.position) path_blocked = not island.path_nodes.is_walkable(self.path[self.cur]) if path_blocked: # update list in island, so that new path calculations consider this obstacle island.path_nodes.reset_tile_walkability(point) self.log.debug("tile %s %s blocked for %s %s on island", point[0], point[1], \ self.unit, self.unit.worldid); return path_blocked else: # also check in super class return super(SoldierPather, self)._check_for_obstacles(point) class StaticPather(object): """Misc pathing routines not depending on units. Does not use AbstractPather Interface""" @classmethod def get_path_on_roads(cls, island, source, destination): """Returns a path that runs only on roads. @param island: island to search path on @param source, destination: Point or anything supported by FindPath @return: list of tuples or None in case no path is found""" return FindPath()(source, destination, island.path_nodes.road_nodes) decorators.bind_all(AbstractPather)