Пример #1
0
 def update(self, time_diff):
     """ Calls the super update function as well as check for if the package should be turned into a tile.
     """
     if self.target_coords == [int(self.x), int(self.y)]:
         self.next_target_tile()
     if self.target_tile is not None:
         if (g.get_img(*self.target_tile).collides or
                 (g.get_img(self.get_tile()[0], self.target_tile[1]).collides and
                  g.get_img(self.target_tile[0], self.get_tile()[1]).collides)):
             if len(self.path) > 0:
                 if self.deliver_tile:
                     if not self.pathfind(self.deliver_tile):
                         # If all else fails, destroy the robot
                         if self.home_tile:
                             self.come_home()
                             self.return_request()
                 else:
                     self.pathfind(self.path[-1])
             else:
                 self.paths_end_func()
                 self.path = []
     super(PathingEntity, self).update(time_diff)
Пример #2
0
    def paint(self):
        """ Paints the player and its aim indicator on the screen.
            Also paints the targets for the aimed at tile if it has any.
        """
        super(Player, self).paint()

        if self.removing_tile:
            if g.in_map(*self.get_aim_tile()) and g.get_img(*self.get_aim_tile()).destroy is not None:
                aim = "remove_aim"
            else:
                aim = "remove_aim_fail"
        else:
            aim = "aim"
        x = ((self.last_aim_tile[0]*c.TILE_SIZE) +
             (c.TILE_SIZE - g.images[aim].get_size()[0]) / 2)
        y = ((self.last_aim_tile[1]*c.TILE_SIZE) +
             (c.TILE_SIZE - g.images[aim].get_size()[1]) / 2)
        g.screen.blit(g.images[aim].get(), (x, y))

        # When you aim at a factory, display the set targets for that tile
        if g.in_map(*self.last_aim_tile) and g.get_img(*self.last_aim_tile).factory_output:
            x, y = self.last_aim_tile
            if g.map[x][y].good_targets:
                for good_target in list(g.map[x][y].good_targets.values()):
                    g.screen.blit(g.images["tile_target_aim"].get(),
                                  (good_target[0]*c.TILE_SIZE +
                                   (c.TILE_SIZE - g.images["tile_target_aim"].get_size()[0]) / 2,
                                   good_target[1]*c.TILE_SIZE +
                                   (c.TILE_SIZE - g.images["tile_target_aim"].get_size()[1]) / 2))
            # Show the direction the selected launcher tile is shooting
            if type(g.map[x][y]) == tiles.LauncherTile and g.map[x][y].shoot_direction != (0, 0):
                g.screen.blit(g.images["tile_target_aim"].get(),
                              ((g.map[x][y].shoot_direction[0]+x)*c.TILE_SIZE +
                               (c.TILE_SIZE - g.images["tile_target_aim"].get_size()[0]) / 2,
                              ((g.map[x][y].shoot_direction[1]+y)*c.TILE_SIZE +
                               (c.TILE_SIZE - g.images["tile_target_aim"].get_size()[1]) / 2)))
Пример #3
0
def _set_target_tile(good):
    """ Sets a custom target for a factory tile where it will try to send its goods first.
    """
    x, y = g.special_entity_list["player"].get_aim_tile()
    if g.get_img(x, y).factory_output:
        # If it's aiming at itself, disable it.
        if (x, y) == tuple(g.tile_target_selection):
            if good in g.map[x][y].good_targets:
                del g.map[x][y].good_targets[good]
                print("Removed target")
            else:
                print("No change")
        else:
            g.map[x][y].good_targets[good] = tuple(g.tile_target_selection)
        g.special_entity_list["player"].browsing_menu = False
        g.tile_target_selection = None
        del g.special_entity_list["tile_target"]
        return True
    else:
        return False
Пример #4
0
    def goods_pathfind(self, target_goods):
        """ Finds a path from the start tile, (the current tile of the entity) to the nearest factory tile that
            can recieve the passed-in goods type.
            "goods" should be a string with the type of goods that the entity will be carrying.

            returns True if a suitable tile was found and False if no suitable tile was found
        """

        start = self.get_tile()
        # The open_dict and closed_dict both follow the format:
        # (key_x, key_y): [g, (came_from_x, came_from_y)]
        # This is a simplified version of the pathfind function. It doesn't use heuristics because it doesn't
        # know where to go yet. It only uses the G value, which is the distance to the tile it came from.
        if type(start) != tuple:
            raise Exception("Value given by self.get_tile() to PathingEntity.goods_pathfind() is not tuple")

        # The open dictionary is a dictionary keeping the currently checkable tiles
        # The starting tile is identified as not having a came_from-tuple.
        open_dict = {start: [0]}
        # The closed dictionary is a dicionary keeping the currently checked tiles
        closed_dict = {}

        current = None
        while len(open_dict.keys()) > 0:
            lowest_value = None
            # Get the lowest value
            for key in open_dict.keys():
                value = open_dict[key][0]
                if lowest_value is None:
                    lowest_value = value
                    current = key
                elif value < lowest_value:
                    lowest_value = value
                    current = key
            # Move current from the open dictionary to the closed one
            closed_dict[current] = open_dict[current]
            del open_dict[current]

            # If we're done here
            done = False
            deliver_tiles = []
            # This code block makes sure the items are delivered to the tile next to the tile instead of diagonally

            if (g.in_map(current[0]+1, current[1]) and
                    g.get_img(current[0]+1, current[1]).factory_input):
                deliver_tiles.append((current[0]+1, current[1]))
            elif (g.in_map(current[0]-1, current[1]) and
                    g.get_img(current[0]-1, current[1]).factory_input):
                deliver_tiles.append((current[0]-1, current[1]))
            elif (g.in_map(current[0], current[1]+1) and
                    g.get_img(current[0], current[1]+1).factory_input):
                deliver_tiles.append((current[0], current[1]+1))
            elif (g.in_map(current[0], current[1]-1) and
                    g.get_img(current[0], current[1]-1).factory_input):
                deliver_tiles.append((current[0], current[1]-1))
            if deliver_tiles:
                for deliver_tile in deliver_tiles:
                    try:
                        for good_name in list(g.map[deliver_tile[0]][deliver_tile[1]].requests.keys()):
                            if good_name == target_goods:
                                if g.map[deliver_tile[0]][deliver_tile[1]].requests[target_goods] > 0:
                                    done = True
                                    g.map[deliver_tile[0]][deliver_tile[1]].requests[target_goods] -= 1
                                    break  # Break out of the goods for loop, not the entire while loop
                        if done:
                            break
                    except AttributeError:
                        pass

            if done is True:
                full_path = []
                self.deliver_tile = deliver_tile
                try:
                    while current != start:
                        full_path.append(current)
                        current = closed_dict[current][1]
                except:
                    print(closed_dict)
                    print(full_path)
                    # Trying to understand the heisenbug! D:
                    import pdb, sys
                    e, m, tb = sys.exc_info()
                    pdb.post_mortem(tb)

                full_path.reverse()
                self.path = full_path
                self.next_target_tile()
                self.home_tile = self.get_tile()
                return True

            # Move through all neighbours
            for i in range(current[0]-1, current[0]+2):
                for j in range(current[1]-1, current[1]+2):
                    neighbour = (i, j)
                    if 0 <= neighbour[0] < len(g.map) and 0 <= neighbour[1] < len(g.map[0]):

                        # Get the G score, the cost to go back to the start
                        if neighbour[0] == current[0]:
                            if neighbour[1] == current[1]:
                                continue
                            else:
                                g_score = closed_dict[current][0] + 10
                        else:
                            if neighbour[1] == current[1]:
                                g_score = closed_dict[current][0] + 10
                            else:
                                # Make sure the pathfinding doesn't try to go through blocks diagonally.
                                if (g.get_img(neighbour[0], current[1]).collides and
                                        g.get_img(current[0], neighbour[1]).collides):
                                    # If the blocks on either side of the diagonal walk is collidable, skip this one
                                    if neighbour not in closed_dict:
                                        closed_dict[neighbour] = None
                                    continue

                                # If it can travel diagonally, give it a cost of the square root of two.
                                g_score = closed_dict[current][0] + 14

                        if c.IMAGES[g.map[neighbour[0]][neighbour[1]].type].collides is False or neighbour == start:
                        # Check if this neighbour can be added the the open_dict and do so if so
                            if neighbour not in closed_dict.keys():
                                if neighbour not in open_dict.keys() or g_score < open_dict[neighbour][0]:
                                    open_dict[neighbour] = [g_score, current]
                        else:
                            if neighbour not in closed_dict.keys() and neighbour not in open_dict.keys():
                                closed_dict[neighbour] = None
        self.path = []
        self.stop_moving()
        return False
Пример #5
0
    def pathfind(self, end):
        """ Finds a path from start to end tiles using A* algorithm
            "start" and "end" are tuples with x and y coordinates of a tile

            returns True if it succeded and False if it couldn't find a path
        """
        start = self.get_tile()
        # The open_dict and closed_dict both follow the format:
        # (key_x, key_y): [f, g, h, (came_from_x, came_from_y)]
        # F, G and H. G is the length to the start tile, H is the Heuristics
        # estimate of the distance to the end tile and F = G + H
        if type(start) != tuple or type(end) != tuple:
            raise Exception("Value passed to PathingEntity.pathfind() is not tuple")

        # The open dictionary is a dictionary keeping the currently checkable tiles
        # The starting tile is identified as not having a came_from-tuple.
        open_dict = {start: [self._heuristic_cost_estimate(start, end), 0,
                             self._heuristic_cost_estimate(start, end)]}
        # The closed dictionary is a dicionary keeping the currently checked tiles
        closed_dict = {}

        current = None
        while len(open_dict.keys()) > 0:
            lowest_value = None
            # Get the lowest value
            for key in open_dict.keys():
                value = open_dict[key][0]
                if lowest_value is None:
                    lowest_value = value
                    current = key
                else:
                    if value < lowest_value:
                        lowest_value = value
                        current = key
            # Move current from the open dictionary to the closed one
            closed_dict[current] = open_dict[current]
            del open_dict[current]

            # If we're done here
            deliver_tile = None
            if g.get_img(*end).collides and current != end:
                # Find a tile next to the target tile to stand on if it collides
                if (g.in_map(current[0] + 1, current[1]) and
                        (current[0] + 1, current[1]) == end):
                    deliver_tile = (current[0] + 1, current[1])
                elif (g.in_map(current[0] - 1, current[1]) and
                        (current[0] - 1, current[1]) == end):
                    deliver_tile = (current[0] - 1, current[1])
                elif (g.in_map(current[0], current[1] + 1) and
                        (current[0], current[1] + 1) == end):
                    deliver_tile = (current[0], current[1] + 1)
                elif (g.in_map(current[0], current[1] - 1) and
                        (current[0], current[1] - 1) == end):
                    deliver_tile = (current[0], current[1] - 1)
            elif current == end:
                deliver_tile = current

            if deliver_tile is not None:
                # closed_dict[current]
                full_path = []
                while current != start:
                    full_path.append(current)
                    current = closed_dict[current][3]
                full_path.reverse()
                self.deliver_tile = deliver_tile
                self.path = full_path
                self.next_target_tile()
                return True

                # # Old version
                # if done is True:
                #     full_path = []
                #     self.deliver_tile = deliver_tile
                #     while len(closed_dict[current]) > 1:
                #         full_path.append(current)
                #         current = closed_dict[current][1]
                #     full_path.reverse()
                #     self.path = full_path
                #     self.next_target_tile()
                #     self.home_tile = self.get_tile()
                #     return

            # Move through all neighbours
            for i in range(current[0]-1, current[0]+2):
                for j in range(current[1]-1, current[1]+2):
                    neighbour = (i, j)
                    if 0 <= neighbour[0] < len(g.map) and 0 <= neighbour[1] < len(g.map[0]):

                        # Get the G score, the cost to go back to the start
                        if neighbour[0] == current[0]:
                            if neighbour[1] == current[1]:
                                continue
                            else:
                                g_score = closed_dict[current][1] + 10
                        else:
                            if neighbour[1] == current[1]:
                                g_score = closed_dict[current][1] + 10
                            else:
                                # Make sure the pathfinding doesn't try to go through blocks diagonally.
                                if (g.get_img(neighbour[0], current[1]).collides and
                                        g.get_img(current[0], neighbour[1]).collides):
                                    # If the blocks on either side of the diagonal walk is collidable, skip this one
                                    closed_dict[neighbour] = None
                                    continue

                                # If it can travel diagonally, give it a cost of the square root of two.
                                g_score = closed_dict[current][1] + 14

                        if c.IMAGES[g.map[neighbour[0]][neighbour[1]].type].collides is False:
                            # Check if this neighbour can be added the the open_dict and do so if so
                            if neighbour not in closed_dict.keys():
                                if neighbour not in open_dict.keys() or g_score < open_dict[neighbour][1]:
                                    h_score = self._heuristic_cost_estimate(neighbour, end)
                                    f_score = g_score + h_score
                                    open_dict[neighbour] = [f_score, g_score, h_score, current]
                        else:
                            closed_dict[neighbour] = None
        self.path = []
        self.stop_moving()
        return False
Пример #6
0
def event_check():
    global launcher_dir
    for event in pygame.event.get():
        # Quit code
        if event.type == pgl.QUIT:
            sys.exit()
        if event.type == pgl.KEYDOWN or event.type == pgl.KEYUP:
            # Create beetle with (default) a
            if event.type == pgl.KEYDOWN and event.key == g.key_dict["spawn_beetle"][0]:
                g.entity_list.append(units.Beetle(g.special_entity_list["player"].x,
                                                  g.special_entity_list["player"].y))
            # Duplicate all beetles with (default) D
            elif event.type == pgl.KEYDOWN and event.key == g.key_dict["duplicate_beetles"][0]:
                # Make an empty list to temporarily store the added beetles, so no infinite loop appears
                temp_entity_list = []
                for entity in g.entity_list:
                    if type(entity) == units.Beetle:
                        temp_entity_list.append(units.Beetle(entity.x, entity.y))
                g.entity_list.extend(temp_entity_list)
            # Remove all beetles
            elif event.type == pgl.KEYDOWN and event.key == g.key_dict["remove_beetles"][0]:
                # Loop backwards through the g.entity_list
                for i in range(len(g.entity_list) - 1, -1, -1):
                    if type(g.entity_list[i]) == units.Beetle:
                        del g.entity_list[i]
                g.force_update = True
            # Key configuration
            elif event.type == pgl.KEYDOWN and event.key == c.CONFIG_KEYS_KEY:
                skip_cycle = g.force_update = True
                interface.key_reconfig()

            elif event.key == g.key_dict["move_up"][0]:
                _move(event, (0, -1))

            elif event.key == g.key_dict["move_down"][0]:
                _move(event, (0, 1))

            elif event.key == g.key_dict["move_left"][0]:
                _move(event, (-1, 0))

            elif event.key == g.key_dict["move_right"][0]:
                _move(event, (1, 0))

            elif event.key == g.key_dict["place_tile"][0]:
                g.special_entity_list["player"].placing_tile = _if_down(event.type)
            elif event.key == g.key_dict["remove_tile"][0]:
                g.special_entity_list["player"].removing_tile = _if_down(event.type)
            elif (event.key == g.key_dict["pick_up_tile"][0] and
                    event.type == pgl.KEYDOWN):
                # This is handled in g.special_entity_list["player"].update()
                if not g.special_entity_list["player"].browsing_menu:
                    g.special_entity_list["player"].toggle_grab = True

            elif (event.key == g.key_dict["build_menu"][0] and
                    event.type == pgl.KEYUP):
                # Shows the build menu
                if g.tile_target_selection is None:
                    g.force_update = True
                    g.special_entity_list["player"].y_minus = g.special_entity_list["player"].y_plus =\
                        g.special_entity_list["player"].x_minus = g.special_entity_list["player"].x_plus = False
                    if "menu" not in g.non_entity_list.keys():
                        g.non_entity_list["menu"] = interface.BuildMenu()
                        g.special_entity_list["player"].browsing_menu = True
                    else:
                        del g.non_entity_list["menu"]
                        g.special_entity_list["player"].browsing_menu = False

            elif (event.key == g.key_dict["select"][0] or event.key == g.key_dict["select2"][0] and
                    event.type == pgl.KEYDOWN):
                # Selects the current menu item
                if "menu" in g.non_entity_list.keys():
                    if g.non_entity_list["menu"].select():
                        del g.non_entity_list["menu"]
                        g.special_entity_list["player"].browsing_menu = False
                elif "tile_target" in g.special_entity_list:
                    x, y = g.special_entity_list["player"].get_aim_tile()

                    if type(g.map[x][y]) == tiles.LauncherTile:
                        g.map[x][y].shoot_direction = launcher_dir
                        g.tile_target_selection = None
                        del g.special_entity_list["tile_target"]
                        g.special_entity_list["player"].browsing_menu = False

                    elif g.get_img(x, y).factory_output:
                        good_names = []
                        for good in g.get_img(x, y).factory_output:
                            good_names.append(good[0])
                        g.non_entity_list["menu"] = interface.TileTargetMenu(good_names)

                    else:
                        g.tile_target_selection = None
                        del g.special_entity_list["tile_target"]
                        g.special_entity_list["player"].browsing_menu = False
                    g.force_update = True

            elif (event.key == g.key_dict["change_target"][0] and
                    event.type == pgl.KEYDOWN):
                if not g.special_entity_list["player"].browsing_menu:
                    if g.get_img(*g.special_entity_list["player"].get_aim_tile()).factory_output:
                        g.special_entity_list["player"].browsing_menu = True
                        g.special_entity_list["player"].y_minus = g.special_entity_list["player"].y_plus = \
                            g.special_entity_list["player"].x_minus = g.special_entity_list["player"].x_plus = False
                        g.tile_target_selection = list(g.special_entity_list["player"].get_aim_tile())
                        x, y = g.special_entity_list["player"].get_aim_tile()
                        g.special_entity_list["tile_target"] =\
                            entities.Entity(x*c.TILE_SIZE, y*c.TILE_SIZE, "tile_target_aim",
                                            0, rotates=False, collides=False)
                        if type(g.map[x][y]) == tiles.LauncherTile:
                            launcher_dir = (0, 0)
                        else:
                            g.menu_selection = [0, 0]
                elif g.tile_target_selection is not None:
                    g.special_entity_list["player"].browsing_menu = False
                    g.tile_target_selection = None
                    del g.special_entity_list["tile_target"]
                    if "menu" in g.non_entity_list:
                        del g.non_entity_list["menu"]
                    g.force_update = True
Пример #7
0
def make_tile(tile_type, x, y, target=None):
    """ Function to create a tile of the appropriate type (Standard, Random, multi-tile and microtiles)
        Should be used instead of directly creating a specific tile unless it is certain which type
        is needed.
        
        "type" should be a string identifier from IMAGES.
            If it is a random tile, it should be the base form of the identifier
            (for example, "tree" and not "tree1"
        "x" and "y" are the indices of the tile in the "g.map" array
        "target" should be a tuple of coordinates in the tile array if the tile being created is
            a pointer. It should be left empty if the tile isn't a multi-tile pointer.
    """
    during_generation = False
    # Check if where you're placing the tile is subject to a special tile.
    if g.map[x][y]:
        if c.SPECIAL_PLACE_TILES.__contains__(tile_type + "+" + str(g.map[x][y].type)):
            return make_tile(c.SPECIAL_PLACE_TILES[tile_type + "+" + str(g.map[x][y].type)], x, y)
    else:
        # If the tile didn't exist before, the entire map is currently being generated
        during_generation = True

    # If it is a multi-tile
    if c.IMAGES[tile_type].multi_tile is not None:
        width, height = c.IMAGES[tile_type].multi_tile
        if not area_is_free(x, y, width, height):
            raise AreaNotFreeException("The area at x " + x + ", y " + y +
                                       ", with the width " + width + " and the height " +
                                       height + " was not placeable. Please check the area " +
                                       "before attempting to create a multi-tile.")
        # Create pointers
        for i in range(x, x + width):
            for j in range(y, y + height):
                # If it's the top-left tile, skip it
                if x == i and y == j:
                    continue
                # On all others, make pointers
                if c.IMAGES[tile_type].collides:
                    make_tile("collide_pointer", i, j, (x, y))
                else:
                    make_tile("pointer", i, j, (x, y))
        
        tile = MultiTileHead(tile_type, x, y, width, height)
    else:
        # Remove all robots if it's a robot sending factory tile.
        if g.map[x][y] is not None and g.get_img(x, y).factory_output and type(g.map[x][y]) is not LauncherTile:
            for robot in g.map[x][y].robots:
                if type(robot) is not int:
                    robot.delete = True
                    robot.return_request()

        # Check if target was specified. If so, this tile is a pointer.
        if target is not None:
            tile = MultiTilePointer(tile_type, x, y, *target)
        elif tile_type == "launcher":
            tile = LauncherTile(tile_type, x, y)
        elif c.IMAGES[tile_type].factory_input or c.IMAGES[tile_type].factory_output:
            tile = FactoryTile(tile_type, x, y)
        elif c.IMAGES[tile_type].microtiles:
            tile = MicroTile(tile_type, x, y)
        else:
            tile = Tile(tile_type, x, y)
    # Change and update the map
    g.map[x][y] = tile
    g.update_map = True
    # Make sure the player doesn't have to move to update to remove a newly placed package
    if "player" in g.special_entity_list:
        if g.special_entity_list["player"].get_aim_tile() == (x, y):
            g.special_entity_list["player"].update_aim_tile = True

    if not during_generation:
        # Make sure microtiles update
        for relative_x in range(-1, 2):
            for relative_y in range(-1, 2):
                if type(g.map[x + relative_x][y + relative_y]) == MicroTile:
                    g.map[x + relative_x][y + relative_y].update_microtile = True

    return tile
Пример #8
0
    def send_goods(self):
        """ Sends its goods with a pathfinding robot to the nearest applicable factory if the corresponding
            robot is "home", that is, not outside the building.
            Should be called about every tick
        """
        i = -1
        for good in c.IMAGES[self.type].factory_output:
            i += 1
            if good:
                good_name, good_amount = good
                if c.IMAGES[self.type].factory_input:
                    if not (good_name in self.inventory and self.inventory[good_name] > 0):
                        continue

                # Is the robot home?
                if len(self.robots) > i:
                    if type(self.robots[i]) is int and self.robots[i] >= 0:
                        self.robots[i] -= 1
                    # If it's zero, all the below code happens.
                    if self.robots[i] != 0:
                        continue
                else:
                    self.robots.append(c.ROBOT_RETRY_TIME)
                robot = units.Robot(self.x * c.TILE_SIZE, self.y * c.TILE_SIZE,
                                    c.GOODS[good_name][0],
                                    c.ROBOT_MOVEMENT_SPEED)

                # used_last_path = False
                # # Use last path
                # if i in self.last_delivery_tiles and g.get_img(*self.last_delivery_tiles[i]).factory_input:
                #     if (good_name in self.good_targets and
                #             self.good_targets[good_name] == self.last_delivery_tiles[i]):
                #         # Check last path
                #         for tile in self.last_paths[i]:
                #             if g.get_img(*tile).collides:
                #                 used_last_path = True
                #                 break
                #         # Valid path
                #         else:
                #             robot.path = self.last_paths[i]
                #             robot.deliver_tile = self.last_delivery_tiles[i]
                #             robot.next_target_tile()
                #             print("Used last path")

                # if used_last_path is False:
                # Straight pathfind
                can_recieve = False
                if good_name in self.good_targets:
                    for reciever_good in g.get_img(*self.good_targets[good_name]).factory_input:
                        if reciever_good[0] == good_name:
                            can_recieve = True
                    if can_recieve:
                        if robot.pathfind(self.good_targets[good_name], good_name):
                            robot.home_tile = (self.x, self.y)
                        else:
                            can_recieve = False

                # Circular pathfind
                if not can_recieve and not robot.goods_pathfind(good_name):
                    robot.delete = True
                    self.robots[i] = c.ROBOT_RETRY_TIME
                    continue

                # Save the path
                self.last_paths[i] = robot.path
                self.last_delivery_tiles[i] = robot.deliver_tile

                # If any of the pathfindings work
                self.robots[i] = robot
                robot.number = i
                robot.goods = good_name
                if c.IMAGES[self.type].factory_input:
                    self.inventory[good_name] -= 1