def testPoint(self): p1 = Point(0,0) p2 = Point(0,2) self.assertEqual(p1.distance(p2), 2) self.assertEqual(p1.distance((0,1)), 1) self.assertEqual(p1.get_coordinates(), [(0,0)]) self.assertEqual(p1, p1.copy())
def get_random_possible_ship_position(self): """Returns a position in water, that is not at the border of the world""" offset = 2 while True: x = self.session.random.randint(self.min_x + offset, self.max_x - offset) y = self.session.random.randint(self.min_y + offset, self.max_y - offset) if (x, y) in self.ship_map: continue # don't place ship where there is already a ship # check if there is an island nearby (check only important coords) position_possible = True for first_sign in (-1, 0, 1): for second_sign in (-1, 0, 1): point_to_check = Point(x + offset * first_sign, y + offset * second_sign) if self.get_island(point_to_check) is not None: position_possible = False break if not position_possible: # propagate break continue break # all checks successful return Point(x, y)
def get_next_step(self): """Returns the next step in the current movement @return: Point""" if self.cur is None: return None self.cur += 1 if not self.path or self.cur == len(self.path): self.cur = None # movement finished return None if self._check_for_obstacles(self.path[self.cur]): # path is suddenly blocked, find another path self.cur -= 1 # reset, since move is not possible # try to calculate another path if not self.calc_path(Point(*self.path[-1]), self.destination_in_building): self.log.info("tile suddenly %s %s blocked for %s %s", \ self.path[self.cur][0], self.path[self.cur][1], self.unit, self.unit.worldid) # no other path can be found. since the problem cannot be fixed here, # we raise an exception raise PathBlockedError # check if we have to change visibility because of entering or leaving a building if self.destination_in_building and self.cur == len(self.path) - 1: self.destination_in_building = False self.unit.hide() elif self.source_in_building and self.cur == 2: self.source_in_building = False self.unit.show() return Point(*self.path[self.cur])
def __init__(self, x, y, rotation, owner, island, level=None, **kwargs): super(BasicBuilding, self).__init__(x=x, y=y, rotation=rotation, owner=owner, \ island=island, **kwargs) self.__init(Point(x, y), rotation, owner, level) self.island = island self.settlement = self.island.get_settlement(Point(x, y)) or \ self.island.add_settlement(self.position, self.radius, owner) if \ owner is not None else None
def testCircle(self): c1 = Circle(Point(0,0), 1) c2 = Circle(Point(0,0), 2) c3 = Circle(Point(0,0), 0) self.assertFalse(c1 == c2) self.assertTrue(c1 != c2) self.assertNotEqual(c1, c2) self.assertEqual(c1.get_coordinates(), [(-1, 0), (0, -1), (0, 0), (0, 1), (1, 0)]) self.assertEqual(c3.get_coordinates(), [(0,0)])
def __init(self, origin, filename, preview=False): """ Load the actual island from a file @param origin: Point @param filename: String, filename of island db or random map id @param preview: flag, map preview mode """ self.file = filename self.origin = origin db = self._get_island_db() p_x, p_y, width, height = db( "SELECT (MIN(x) + ?), (MIN(y) + ?), (1 + MAX(x) - MIN(x)), (1 + MAX(y) - MIN(y)) FROM ground", self.origin.x, self.origin.y, )[0] # rect for quick checking if a tile isn't on this island # NOTE: it contains tiles, that are not on the island! self.rect = Rect(Point(p_x, p_y), width, height) self.ground_map = {} for (rel_x, rel_y, ground_id, action_id, rotation) in db( "SELECT x, y, ground_id, action_id, rotation FROM ground" ): # Load grounds if not preview: # actual game, need actual tiles ground = Entities.grounds[ground_id](self.session, self.origin.x + rel_x, self.origin.y + rel_y) ground.act(action_id, rotation) else: ground = Point(self.origin.x + rel_x, self.origin.y + rel_y) ground.classes = tuple() ground.settlement = None # These are important for pathfinding and building to check if the ground tile # is blocked in any way. self.ground_map[(ground.x, ground.y)] = ground self._init_cache() self.settlements = [] self.wild_animals = [] self.num_trees = 0 # define the rectangle with the smallest area that contains every island tile its position min_x = min(zip(*self.ground_map.keys())[0]) max_x = max(zip(*self.ground_map.keys())[0]) min_y = min(zip(*self.ground_map.keys())[1]) max_y = max(zip(*self.ground_map.keys())[1]) self.position = Rect.init_from_borders(min_x, min_y, max_x, max_y) if not preview: # this isn't needed for previews, but it is in actual games self.path_nodes = IslandPathNodes(self) # repopulate wild animals every 2 mins if they die out. Scheduler().add_new_object(self.check_wild_animal_population, self, Scheduler().get_ticks(120), -1) """TUTORIAL:
def __init(self, x, y): self.position = Point(x, y) self.last_position = Point(x, y) self._next_target = Point(x, y) self.move_callbacks = WeakMethodList() self._conditional_callbacks = {} self.__is_moving = False self.path = self.pather_class(self, session=self.session)
def testRect(self): r1 = Rect(Point(0,0), 1, 1) r2 = Rect(0, 0, 1 ,1) r3 = Rect(Point(2, 2), 1, 1) self.assertEqual(r1, r2) self.assertTrue(r1 == r2) self.assertFalse(r1.contains(Point(-1,-1))) self.assertTrue(r2.contains(Point(0,0))) self.assertTrue(r2.contains(Point(1,1))) self.assertTrue(r1.intersects(r2)) self.assertFalse(r1.intersects(r3))
def on_click(self, event): """Scrolls screen to the point, where the cursor points to on the minimap""" icon_pos = Point(*self.overlay_icon.getAbsolutePos()) mouse_position = Point(event.getX(), event.getY()) abs_mouse_position = icon_pos + mouse_position if not self.location.contains(abs_mouse_position): # mouse click was on icon but not acctually on minimap return abs_mouse_position = self._get_from_rotated_coords( abs_mouse_position.to_tuple()) map_coord = self._minimap_coord_to_world_coord(abs_mouse_position) self.session.view.center(*map_coord)
def _get_event_coord(self, event): """Returns position of event as uh map coordinate tuple or None""" mouse_position = Point(event.getX(), event.getY()) if not hasattr(self, "icon"): icon_pos = Point(*self.overlay_icon.getAbsolutePos()) abs_mouse_position = icon_pos + mouse_position if not self.location.contains(abs_mouse_position): # mouse click was on icon but not actually on minimap return abs_mouse_position = abs_mouse_position.to_tuple() else: abs_mouse_position = mouse_position.to_tuple() if self._get_rotation_setting(): abs_mouse_position = self._get_from_rotated_coords(abs_mouse_position) return self._minimap_coord_to_world_coord(abs_mouse_position)
def highlight_buildable(self, building_tool, tiles_to_check=None): """Highlights all buildable tiles. @param tiles_to_check: list of tiles to check for coloring.""" # resolved variables from inner loops is_tile_buildable = building_tool._class.is_tile_buildable session = building_tool.session player = session.world.player buildable_tiles_add = building_tool._buildable_tiles.add if tiles_to_check is not None: # only check these tiles for tile in tiles_to_check: if is_tile_buildable(session, tile, None): building_tool._color_buildable_tile(tile) else: #default build on island for settlement in session.world.settlements: if settlement.owner == player: island = session.world.get_island( Point(*settlement.ground_map.iterkeys().next())) for tile in settlement.ground_map.itervalues(): if is_tile_buildable(session, tile, None, island, check_settlement=False): building_tool._color_buildable_tile(tile)
def check_build_line(cls, session, point1, point2, rotation=45, ship=None): # Pathfinding currently only supports buildingsize 1x1, so don't use it in this case if cls.size != (1, 1): return [ cls.check_build(session, point2, rotation=rotation, ship=ship) ] # use pathfinding to get a path, then try to build along it island = session.world.get_island(point1) if island is None: return [] path = StaticPather.get_direct_path(island, point1, point2) if path is None: # can't find a path between these points return [] # TODO: maybe implement alternative strategy possible_builds = [] for i in path: action = '' for action_char, offset in \ sorted(BUILDINGS.ACTION.action_offset_dict.iteritems()): # order is important here if (offset[0] + i[0], offset[1] + i[1]) in path: action += action_char if action == '': action = 'ac' # default build = cls.check_build(session, Point(*i)) build.action = action possible_builds.append(build) return possible_builds
def _load(self, db, worldid): super(Pirate, self)._load(db, worldid) home = db("SELECT x, y FROM pirate_home_point")[0] self.home_point = Point(home[0], home[1]) self.log.debug( "Pirate: home at (%d, %d), radius %d" % (self.home_point.x, self.home_point.y, self.home_radius))
def __init__(self, db, islandid, session): """ @param db: db instance with island table @param islandid: id of island in that table @param session: reference to Session instance """ super(Island, self).__init__(worldid=islandid) self.session = session x, y, filename = db( "SELECT x, y, file FROM island WHERE rowid = ? - 1000", islandid)[0] self.__init(Point(x, y), filename) # create building indexers self.building_indexers = {} self.building_indexers[BUILDINGS.TREE_CLASS] = BuildingIndexer( WildAnimal.walking_range, self, self.session.random) # load settlements for (settlement_id, ) in db( "SELECT rowid FROM settlement WHERE island = ?", islandid): Settlement.load(db, settlement_id, self.session) # load buildings from horizons.world import load_building for (building_worldid, building_typeid) in \ db("SELECT rowid, type FROM building WHERE location = ?", islandid): load_building(self.session, db, building_typeid, building_worldid)
def find_warehouse_location(cls, ship, land_manager): """ Finds a location for the warehouse on the given island @param LandManager: the LandManager of the island @return _BuildPosition: a possible build location """ moves = [(-1, 0), (0, -1), (0, 1), (1, 0)] island = land_manager.island world = island.session.world personality = land_manager.owner.personality_manager.get('FoundSettlement') options = [] for (x, y), tile in sorted(island.ground_map.iteritems()): ok = False for x_offset, y_offset in moves: for d in xrange(2, 6): coords = (x + d * x_offset, y + d * y_offset) if coords in world.water_body and world.water_body[coords] == world.water_body[ship.position.to_tuple()]: # the planned warehouse should be reachable from the ship's water body ok = True if not ok: continue build_info = None point = Point(x, y) warehouse = Builder(BUILDINGS.WAREHOUSE, land_manager, point, ship = ship) if not warehouse: continue cost = 0 for coords in land_manager.village: distance = point.distance_to_tuple(coords) 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 += warehouse.position.distance(settlement_manager.settlement.warehouse.position) * personality.linear_warehouse_penalty options.append((cost, warehouse)) for _, build_info in sorted(options): (x, y) = build_info.position.get_coordinates()[4] if ship.check_move(Circle(Point(x, y), BUILDINGS.BUILD.MAX_BUILDING_SHIP_DISTANCE)): return build_info return None
def _get_world_location_from_event(self, evt): """Returns the coordinates of an event at the map. @return Point with int coordinates""" screenpoint = fife.ScreenPoint(evt.getX(), evt.getY()) mapcoord = self.session.view.cam.toMapCoordinates(screenpoint, False) # undocumented legacy formula to correct coords, probably return Point(int(round(math.floor(mapcoord.x + mapcoord.x) / 2.0 + 0.25)), \ int(round(math.floor(mapcoord.y + mapcoord.y) / 2.0 + 0.25)))
def __init__(self, consumerbuilding): super(ConsumerBuildingPathNodes, self).__init__() self.nodes = {} for coordinate in consumerbuilding.position.get_radius_coordinates( consumerbuilding.radius, include_self=False): tile = consumerbuilding.island.get_tile( Point(coordinate[0], coordinate[1])) if tile is not None and not 'coastline' in tile.classes: self.nodes[coordinate] = self.NODE_DEFAULT_SPEED
def __call__(self, issuer): """Execute the command @param issuer: the issuer of the command """ if self.position is None: AmbientSound.play_special(self.sound) else: AmbientSound.play_special( self.sound, Point(self.position[0], self.position[1]))
def handle_no_possible_job(self): """Walk around on field, search again, when we arrive""" for coord in self._get_random_positions_on_object(self.home_building): try: self.move(Point(*coord), callback=self.search_job) self.state = self.states.no_job_walking_randomly return except MoveNotPossible: pass # couldn't find location, so don't move super(FarmAnimal, self).handle_no_possible_job()
def calculate_visibility_points(self, pirate_ship): """Finds out the points from which the entire map will be accessible. Should be called only once either during initialization or loading""" rect = self.session.world.map_dimensions.get_corners() x_min, x_max, y_min, y_max = rect[0][0], rect[1][0], rect[0][0], rect[ 2][1] # Necessary points (with tolerable overlapping) which cover the entire map # Each element contains two values: it's co-ordinate, and frequency of player ship's visit self.visibility_points = [] y = y_min + self.sight_radius while y <= y_max: x = x_min + self.sight_radius while x <= x_max: self.visibility_points.append([Point(x, y), 0]) x += self.sight_radius # should be 2*self.sight_radius for no overlap y += self.sight_radius self.log.debug("Pirate %s: %s, visibility points" % (self.worldid, pirate_ship.name)) copy_points = list(self.visibility_points) for point in copy_points: if not self.session.world.get_tile(point[0]).is_water: # Make a position compromise to obtain a water tile on the point for x in (3, -3, 2, -2, 1, -1, 0): for y in (3, -3, 2, -2, 1, -1, 0): new_point = Point(point[0].x + x, point[0].y + y) if self.session.world.get_tile(new_point).is_water: self.visibility_points.remove( point) #remove old point point[0] = new_point self.visibility_points.append([point[0], 0]) #add new point break if self.session.world.get_tile(point[0]).is_water: break if not self.session.world.get_tile(point[0]).is_water: self.visibility_points.remove(point) continue self.log.debug("(%d, %d)" % (point[0].x, point[0].y)) # A list needed to reduce visibility frequencies of a point if player is not sighted on that point self.visible_player = []
def get_random_possible_coastal_ship_position(self): """Returns a position in water, that is not at the border of the world but on the coast of an island""" offset = 2 while True: x = self.session.random.randint(self.min_x + offset, self.max_x - offset) y = self.session.random.randint(self.min_y + offset, self.max_y - offset) if (x, y) in self.ship_map: continue # don't place ship where there is already a ship result = Point(x, y) if self.get_island(result) is not None: continue # don't choose a point on an island # check if there is an island nearby (check only important coords) for first_sign in (-1, 0, 1): for second_sign in (-1, 0, 1): point_to_check = Point(x + first_sign, y + second_sign) if self.get_island(point_to_check) is not None: return result
def get_random_location(self, in_range): """Returns a random location in walking_range, that we can find a path to @param in_range: int, max distance to returned point from current position @return: Instance of Point or None""" possible_walk_targets = Circle(self.position, in_range).get_coordinates() possible_walk_targets.remove(self.position.to_tuple()) self.session.random.shuffle(possible_walk_targets) for coord in possible_walk_targets: target = Point(*coord) if self.check_move(target): return target return None
def _make_surrounding_transparent(self, building_position): """Makes the surrounding of building_position transparent""" world_contains = self.session.world.map_dimensions.contains_without_border get_tile = self.session.world.get_tile for coord in building_position.get_radius_coordinates( self.nearby_objects_radius, include_self=True): p = Point(*coord) if not world_contains(p): continue tile = get_tile(p) if tile.object is not None and tile.object.buildable_upon: tile.object.fife_instance.get2dGfxVisual().setTransparency( \ self.nearby_objects_transparency ) self._modified_objects.add(tile.object)
def mouseMoved(self, evt): if not self.session.world.inited: return mousepoint = fife.ScreenPoint(evt.getX(), evt.getY()) # Status menu update current = self.session.view.cam.toMapCoordinates(mousepoint, False) if abs((current.x - self.lastmoved.x)**2 + (current.y - self.lastmoved.y)**2) >= 4**2: self.lastmoved = current island = self.session.world.get_island( Point(int(round(current.x)), int(round(current.y)))) if island: settlement = island.get_settlement( Point(int(round(current.x)), int(round(current.y)))) if settlement: self.session.ingame_gui.resourceinfo_set(settlement) else: self.session.ingame_gui.resourceinfo_set(None) else: self.session.ingame_gui.resourceinfo_set(None) # Mouse scrolling x, y = 0, 0 if mousepoint.x < 5: x -= 5 - mousepoint.x elif mousepoint.x >= (self.session.view.cam.getViewPort().right() - 5): x += 6 + mousepoint.x - self.session.view.cam.getViewPort().right() if mousepoint.y < 5: y -= 5 - mousepoint.y elif mousepoint.y >= (self.session.view.cam.getViewPort().bottom() - 5): y += 6 + mousepoint.y - self.session.view.cam.getViewPort().bottom( ) x *= 10 y *= 10 self.session.view.autoscroll(x, y)
def check_build_line(cls, session, point1, point2, rotation=45, ship=None): possible_builds = [] area = Rect.init_from_corners(point1, point2) # correct placement for large buildings (mouse should be at center of building) area.left -= (cls.size[0] - 1) / 2 area.right -= (cls.size[0] - 1) / 2 area.top -= (cls.size[1] - 1) / 2 area.bottom -= (cls.size[1] - 1) / 2 for x in xrange(area.left, area.right + 1, cls.size[0]): for y in xrange(area.top, area.bottom + 1, cls.size[1]): possible_builds.append( \ cls.check_build(session, Point(x, y), rotation=rotation, ship=ship) \ ) return possible_builds
def begin_current_job(self): # we can only move on 1 building; simulate this by choosing a random location with # the building coords = self._get_random_positions_on_object(self.job.object) # move to first walkable target coord we find for coord in coords: # job target is walkable, so at least one coord of it has to be # so we can safely assume, that we will find a walkable coord target_location = Point(*coord) if self.check_move(target_location): super(FarmAnimal, self).begin_current_job(job_location=target_location) return assert False
def go(self, x, y): """Moves the ship. This is called when a ship is selected and RMB is pressed outside the ship""" self.stop() #disable the trading route if hasattr(self, 'route'): self.route.disable() ship_id = self.worldid # this has to happen here, # cause a reference to self in a temporary function is implemented # as a hard reference, which causes a memory leak def tmp(): if self.session.world.player == self.owner: self.session.view.renderer['GenericRenderer'].removeAll( "buoy_" + str(ship_id)) tmp() move_target = Point(int(round(x)), int(round(y))) try: self.move(move_target, tmp) except MoveNotPossible: # find a near tile to move to target_found = False surrounding = Circle(move_target, radius=0) while not target_found and surrounding.radius < 4: surrounding.radius += 1 for move_target in surrounding: try: self.move(move_target, tmp) except MoveNotPossible: continue target_found = True break if self.session.world.player == self.owner: if self.position.x != move_target.x or self.position.y != move_target.y: move_target = self.get_move_target() if move_target is not None: loc = fife.Location(self.session.view.layers[LAYERS.OBJECTS]) loc.thisown = 0 coords = fife.ModelCoordinate(move_target.x, move_target.y) coords.thisown = 0 loc.setLayerCoordinates(coords) self.session.view.renderer['GenericRenderer'].addAnimation( "buoy_" + str(self.worldid), fife.GenericRendererNode(loc), horizons.main.fife.animationpool.addResourceFromFile( "as_buoy0-idle-45"))
def calc_path(self, destination, destination_in_building=False, check_only=False, source=None): """Calculates a path to destination @param destination: a destination supported by pathfinding @param destination_in_building: bool, whether destination is in a building. this makes the unit "enter the building" @param check_only: if True the path isn't saved @param source: use this as source of movement instead of self.unit.position @return: True iff movement is possible""" # calculate our source if source is None: source = self.unit.position if self.unit.is_moving() and self.path: # we are moving, use next step as source source = Point(*self.path[self.cur]) else: # check if we are in a building building = self.session.world.get_building(self.unit.position) if building is not None: source = building # call algorithm # to use a different pathfinding code, just change the following line path = FindPath()(source, destination, self._get_path_nodes(), self._get_blocked_coords(), self.move_diagonal, \ self.make_target_walkable) if path is None: return False if not check_only: # prepare movement self.path = path if self.unit.is_moving(): self.cur = 0 self.unit.show() # make sure unit is displayed else: self.cur = -1 self.source_in_building = hasattr( source, 'is_building') and source.is_building self.destination_in_building = destination_in_building return True
def __init(self, origin, filename): """ Load the actual island from a file @param origin: Point @param filename: String, filename of island db or random map id """ self.file = filename self.origin = origin # check if filename is a random map if random_map.is_random_island_id_string(filename): # it's a random map id, create this map and load it db = random_map.create_random_island(filename) else: db = DbReader( filename ) # Create a new DbReader instance to load the maps file. p_x, p_y, width, height = db( "SELECT (MIN(x) + ?), (MIN(y) + ?), (1 + MAX(x) - MIN(x)), (1 + MAX(y) - MIN(y)) FROM ground", self.origin.x, self.origin.y)[0] # rect for quick checking if a tile isn't on this island # NOTE: it contains tiles, that are not on the island! self.rect = Rect(Point(p_x, p_y), width, height) self.ground_map = {} for (rel_x, rel_y, ground_id ) in db("SELECT x, y, ground_id FROM ground"): # Load grounds ground = Entities.grounds[ground_id](self.session, self.origin.x + rel_x, self.origin.y + rel_y) # These are important for pathfinding and building to check if the ground tile # is blocked in any way. self.ground_map[(ground.x, ground.y)] = ground self.settlements = [] self.wild_animals = [] self.path_nodes = IslandPathNodes(self) # repopulate wild animals every 2 mins if they die out. Scheduler().add_new_object(self.check_wild_animal_population, self, Scheduler().get_ticks(120), -1) """TUTORIAL:
def load(self, db, worldid): super(BasicBuilding, self).load(db, worldid) x, y, self.health, location, rotation, level = db.get_building_row(worldid) owner_id = db.get_settlement_owner(location) owner = None if owner_id is None else WorldObject.get_object_by_id(owner_id) remaining_ticks_of_month = None if self.has_running_costs: remaining_ticks_of_month = db("SELECT ticks FROM remaining_ticks_of_month WHERE rowid=?", worldid)[0][0] self.__init(Point(x, y), rotation, owner, level=level, \ remaining_ticks_of_month=remaining_ticks_of_month) self.island, self.settlement = self.load_location(db, worldid) # island.add_building handles registration of building for island and settlement self.island.add_building(self, self.owner)
def is_walkable(self, coord): """Check if a unit may walk on the tile specified by coord on land NOTE: nature tiles (trees..) are considered to be walkable (or else they could be used as walls against enemies) @param coord: tuple: (x, y) """ tile_object = self.island.get_tile(Point(*coord)) if tile_object is None: # tile is water return False # if it's not constructable, it is usually also not walkable # NOTE: this isn't really a clean implementation, but it works for now # it eliminates e.g. water and beaches, that shouldn't be walked on if not "constructible" in tile_object.classes: return False if tile_object.blocked and not tile_object.object.walkable: return False # every test is passed, tile is walkable return True
def is_tile_buildable(cls, session, tile, ship, island=None, check_settlement=True): """Checks a tile for buildability. @param tile: Ground object @param ship: Ship instance if building from ship @param island: Island instance, if already known. If None, it will be calculated @param check_settlement: bool, whether to check for settlement @return bool, True for "is buildable" """ position = Point(tile.x, tile.y) try: cls._check_island(session, position, island) if check_settlement: cls._check_settlement(session, position, ship=ship) cls._check_buildings(session, position) except _NotBuildableError: return False return True
def _mark(self, *edges): """Highights building instances and keeps self.selected up to date.""" if len(edges) == 1: edges = (edges[0], edges[0]) elif len(edges) == 2: edges = ((min(edges[0][0], edges[1][0]), min(edges[0][1], edges[1][1])), \ (max(edges[0][0], edges[1][0]), max(edges[0][1], edges[1][1]))) else: edges = None if self.oldedges != edges or edges is None: for i in self.selected: self.session.view.renderer['InstanceRenderer'].removeColored(i._instance) self.selected = set() self.oldedges = edges if edges is not None: for x in xrange(edges[0][0], edges[1][0] + 1): for y in xrange(edges[0][1], edges[1][1] + 1): b = self.session.world.get_building(Point(x, y)) if b is not None and b.tearable and self.session.world.player == b.owner: self.selected.add(b) for i in self.selected: self.session.view.renderer['InstanceRenderer'].addColored(i._instance, \ *self.tear_selection_color)
def _recalculate(self, where = None, dump_data=False): """Calculate which pixel of the minimap should display what and draw it @param where: Rect of minimap coords. Defaults to self.location @param dump_data: Don't draw but return calculated data""" self.minimap_image.set_drawing_enabled() rt = self.minimap_image.rendertarget render_name = self._get_render_name("base") if where is None: where = self.location rt.removeAll(render_name) # calculate which area of the real map is mapped to which pixel on the minimap pixel_per_coord_x, pixel_per_coord_y = self._world_to_minimap_ratio # calculate values here so we don't have to do it in the loop pixel_per_coord_x_half_as_int = int(pixel_per_coord_x/2) pixel_per_coord_y_half_as_int = int(pixel_per_coord_y/2) real_map_point = Point(0, 0) world_min_x = self.world.min_x world_min_y = self.world.min_y get_island_tuple = self.world.get_island_tuple island_col = self.COLORS["island"] location_left = self.location.left location_top = self.location.top if dump_data: data = [] drawPoint = lambda name, fife_point, r, g, b : data.append( (fife_point.x, fife_point.y, r, g, b) ) else: drawPoint = rt.addPoint fife_point = fife.Point(0,0) use_rotation = self._get_rotation_setting() # loop through map coordinates, assuming (0, 0) is the origin of the minimap # this faciliates calculating the real world coords for x in xrange(where.left-self.location.left, where.left+where.width-self.location.left): # Optimisation: remember last island last_island = None island = None for y in xrange(where.top-self.location.top, where.top+where.height-self.location.top): """ This code should be here, but since python can't do inlining, we have to inline ourselves for performance reasons covered_area = Rect.init_from_topleft_and_size( int(x * pixel_per_coord_x)+world_min_x, \ int(y * pixel_per_coord_y)+world_min_y), \ int(pixel_per_coord_x), int(pixel_per_coord_y)) real_map_point = covered_area.center() """ # use center of the rect that the pixel covers real_map_point.x = int(x*pixel_per_coord_x)+world_min_x + \ pixel_per_coord_x_half_as_int real_map_point.y = int(y*pixel_per_coord_y)+world_min_y + \ pixel_per_coord_y_half_as_int real_map_point_tuple = (real_map_point.x, real_map_point.y) # check what's at the covered_area if last_island is not None and real_map_point_tuple in last_island.ground_map: island = last_island else: island = get_island_tuple(real_map_point_tuple) if island is not None: last_island = island # this pixel is an island settlement = island.get_settlement(real_map_point) if settlement is None: # island without settlement color = island_col else: # pixel belongs to a player color = settlement.owner.color.to_tuple() else: continue if use_rotation: # inlined _get_rotated_coords rot_x, rot_y = self._rotate( (location_left + x, location_top + y), self._rotations) fife_point.set(rot_x - location_left, rot_y - location_top) else: fife_point.set(x, y) drawPoint(render_name, fife_point, *color) if dump_data: return json.dumps( data )
def _recalculate(self, where=None): """Calculate which pixel of the minimap should display what and draw it @param where: Rect of minimap coords. Defaults to self.location""" if where is None: where = self.location # calculate which area of the real map is mapped to which pixel on the minimap pixel_per_coord_x, pixel_per_coord_y = self._get_world_to_minimap_ratio() # calculate values here so we don't have to do it in the loop pixel_per_coord_x_half_as_int = int(pixel_per_coord_x / 2) pixel_per_coord_y_half_as_int = int(pixel_per_coord_y / 2) real_map_point = Point(0, 0) location_left = self.location.left location_top = self.location.top world_min_x = self.world.min_x world_min_y = self.world.min_y get_island = self.world.get_island water_col, island_col = [self.colors[i] for i in [self.water_id, self.island_id]] color = None renderer_addPoint = self.renderer.addPoint # loop through map coordinates, assuming (0, 0) is the origin of the minimap # this faciliates calculating the real world coords for x in xrange(where.left - self.location.left, where.left + where.width - self.location.left): # Optimisation: remember last island last_island = None island = None for y in xrange(where.top - self.location.top, where.top + where.height - self.location.top): """ This code should be here, but since python can't do inlining, we have to inline ourselves for performance reasons covered_area = Rect.init_from_topleft_and_size( int(x * pixel_per_coord_x)+world_min_x, \ int(y * pixel_per_coord_y)+world_min_y), \ int(pixel_per_coord_x), int(pixel_per_coord_y)) real_map_point = covered_area.center() """ # use center of the rect that the pixel covers real_map_point.x = int(x * pixel_per_coord_x) + world_min_x + pixel_per_coord_x_half_as_int real_map_point.y = int(y * pixel_per_coord_y) + world_min_y + pixel_per_coord_y_half_as_int real_map_point_tuple = (real_map_point.x, real_map_point.y) # we changed the minimap coords, so change back here minimap_point = (location_left + x, location_top + y) # check what's at the covered_area if last_island is not None and real_map_point_tuple in last_island.ground_map: island = last_island else: island = get_island(real_map_point) if island is not None: last_island = island # this pixel is an island settlement = island.get_settlement(real_map_point) if settlement is None: # island without settlement color = island_col else: # pixel belongs to a player color = settlement.owner.color.to_tuple() else: color = water_col # _get_rotated_coords has been inlined here renderer_addPoint("minimap", self.renderernodes[self._rotate(minimap_point, self._rotations)], *color)