Beispiel #1
0
    def apply(self, subject: Player):
        previous_position = subject.get_position()

        w, h = self.environment.get_tile_dimensions()

        start_x = w - 1 if self.direction == CardinalDirection.EAST else 0
        shift = -1 if self.direction == CardinalDirection.EAST else 1

        y = subject.get_position().y

        position = Position(start_x, y)
        while self.environment.contains(position):

            if (not self.to_vegetation
                    and self.environment.tile_at(position).is_walkable()):
                subject.set_position(position)
                subject.set_direction(
                    self.get_direction(subject, previous_position.x,
                                       position.x))
                return

            if (self.to_vegetation
                    and (self.environment.tile_at(position).is_grass()
                         or self.environment.tile_at(position).is_stone())):
                subject.set_position(position)
                subject.set_direction(
                    self.get_direction(subject, previous_position.x,
                                       position.x))
                return

            position = Position(position.x + shift, position.y)
        raise ActionException("ContourJump not possible")
Beispiel #2
0
    def test_bounds_of_the_environment(self):
        dummy_map = "S....\n" \
                    "....."

        e = Environment(self.settings, dummy_map)

        self.assertTrue(e.contains(Position(0, 0)))
        self.assertTrue(e.contains(Position(2, 2)))
        self.assertFalse(e.contains(Position(3, 3)))
        self.assertFalse(e.contains(Position(500, 300)))
        self.assertFalse(e.contains(Position(-2, 1)))
Beispiel #3
0
    def apply(self, subject: Player):
        w, h = self.environment.get_tile_dimensions()
        previous_position = subject.get_position()

        if self.steps >= 0:
            if self.direction == CardinalDirection.SOUTH:
                start_y = previous_position.y + self.steps
                if start_y > h - 1:
                    # if the jump goes out of boundaries, do reverse search
                    start_y = h - 1
                    shift = -1
                else:
                    # otherwise do standard search in that direction
                    shift = 1
            else:
                start_y = previous_position.y - self.steps
                if start_y < 0:
                    # if the jump goes out of boundaries, do reverse search
                    start_y = 0
                    shift = 1
                else:
                    # otherwise do standard search in that direction
                    shift = -1
        else:
            # for negative step values do reverse search to get to top/bottom
            if self.direction == CardinalDirection.SOUTH:
                start_y = h - 1
                shift = -1
            else:
                start_y = 0
                shift = 1

        position = Position(previous_position.x, start_y)

        while self.environment.contains(position):

            simulated_player = Player()
            simulated_player.set_position(position)

            try:
                simulated_player.apply_action(
                    ContourJumpAction(self.environment,
                                      CardinalDirection.WEST,
                                      to_vegetation=True))
                subject.set_position(simulated_player.get_position())
                subject.set_direction(simulated_player.direction)
                return
            except ActionException:
                position = Position(position.x, position.y + shift)

        raise ActionException("VerticalJump not possible")
Beispiel #4
0
    def _construct_tiles(self,
                         encoded_map: CharacterEncodedMap) -> List[List[Tile]]:
        """
        :param encoded_map: constructs the tiles from a character encoded map
        :return: matrix of tiles
        """
        character_matrix = [[char for char in line]
                            for line in encoded_map.split("\n")]

        if len(character_matrix) < 1:
            raise EnvironmentException("Not a valid map encoding - bad size")

        height = len(character_matrix) + 1

        width = len(character_matrix[0])
        for row in character_matrix:
            if len(row) != width:
                raise EnvironmentException(
                    "Not a valid map encoding - all rows must have the same size")

        tile_matrix = [[None for _ in range(width)] for _ in range(height)]
        tile_matrix = self._construct_bottom_row(tile_matrix)
        for y in range(height - 1):
            for x in range(width):
                tile_matrix[y][x] = self._construct_tile(Position(x, y),
                                                         character_matrix)
        return tile_matrix
Beispiel #5
0
 def create_shard_collected(scene: 'GameScene',
                            position: Position) -> 'ParticleSprite':
     return ParticleSprite(
         scene,
         scene.animation_manager.get_animation("particle-shard-collected"),
         position,
         px_offset=Position(0, -TILE_SIZE_PX)
     )
Beispiel #6
0
 def create_blink_in(scene: 'GameScene',
                     position: Position) -> 'ParticleSprite':
     return ParticleSprite(
         scene,
         scene.animation_manager.get_animation("particle-blink-in"),
         position,
         px_offset=Position(0, -TILE_SIZE_PX // 4)
     )
Beispiel #7
0
 def create_dash_right(scene: 'GameScene',
                       position: Position) -> 'ParticleSprite':
     return ParticleSprite(
         scene,
         scene.animation_manager.get_animation("particle-dash-right"),
         position,
         px_offset=Position(TILE_SIZE_PX // 2, 1)
     )
Beispiel #8
0
 def create_blink_out(scene: 'GameScene',
                      position: Position,
                      direction: CardinalDirection) -> 'ParticleSprite':
     return ParticleSprite(
         scene,
         scene.animation_manager.get_animation("particle-blink-out"),
         position,
         px_offset=Position(0, 0),
         flip_x=direction != CardinalDirection.EAST
     )
Beispiel #9
0
    def create_descent(scene: 'GameScene', position: Position,
                       direction: CardinalDirection):
        animation_name = "particle-descent-left" \
            if direction == CardinalDirection.WEST else "particle-descent-right"

        return ParticleSprite(
            scene,
            scene.animation_manager.get_animation(animation_name),
            position,
            px_offset=Position(0, -TILE_SIZE_PX // 2)
        )
Beispiel #10
0
    def _prepare_surfaces_for_tiles(self) -> List[List[List[Surface]]]:
        tile_matrix = self.environment.get_tile_matrix()
        surfaces = [[None for _ in row]
                    for row in tile_matrix]

        for y in range(len(tile_matrix)):
            for x in range(len(tile_matrix[y])):
                surfaces[y][x] = \
                    self._prepare_surfaces_for_tile(Position(x, y),
                                                    tile_matrix)

        return surfaces
Beispiel #11
0
    def _get_starting_position(self, encoded_map) -> Position:
        starting_positions = []

        for y, row in enumerate(encoded_map.split("\n")):
            for x, character in enumerate(row):
                if character == "S":
                    starting_positions.append(Position(x, y))

        if len(starting_positions) != 1:
            raise EnvironmentException(
                f"Wrong number of starting positions (expected 1, got {len(starting_positions)})")
        return starting_positions[0]
Beispiel #12
0
    def _increment_position_with_direction(self,
                                           position: Position) -> Position:
        x, y = position
        width = self.environment.get_tile_dimensions()[0]

        x = x + 1 if self.direction == CardinalDirection.EAST else x - 1
        # if x is out of bounds, jump to the next/previous row
        if x < 0:
            x = width - 1
            y -= 1
        if x > width - 1:
            x = 0
            y += 1
        return Position(x, y)
Beispiel #13
0
    def test_should_serialize_correctly(self):
        r = Recording()
        r.start(10_000)

        r.record_text_input(10_100, "kLhi")
        r.record_text_input(10_200, "k")
        r.record_shard_spawn(10_300, Position(1, 1))
        r.record_text_input(10_500, "I")

        output = r.serialize()

        self.assertEqual(5, len(output.split("\n")))
        self.assertEqual(
            f"V 0 {VERSION}\nI 100 kLhi\nI 200 k\nS 300 1 1\nI 500 I", output)
Beispiel #14
0
    def test_standard_environment_creation(self):
        dummy_map = "/o/..\n" \
                    "S.../"

        e = Environment(self.settings, dummy_map)
        self.assertEqual(15, len(e.get_all_tiles()))

        # First tile is walkable grass and not dirt
        first_tile = e.tile_at(Position(0, 0))
        self.assertTrue(first_tile.is_walkable())
        self.assertFalse(first_tile.is_dirt())
        self.assertTrue(first_tile.is_grass())

        # Second tile is walkable stone and not dirt
        second_tile = e.tile_at(Position(1, 0))
        self.assertTrue(second_tile.is_walkable())
        self.assertFalse(second_tile.is_dirt())
        self.assertTrue(second_tile.is_stone())

        # Last tile is walkable grass with dirt
        last_tile = e.tile_at(Position(4, 1))
        self.assertTrue(last_tile.is_walkable())
        self.assertTrue(last_tile.is_dirt())
        self.assertTrue(last_tile.is_grass())
Beispiel #15
0
    def spawn_shard(self, position: Position) -> None:
        """Spawns a shard at a given position.
        :param position: where to spawn a shard
        """
        shard = Shard(position)
        self.shard_group.add(ShardSprite(self, shard))
        self.recording.record_shard_spawn(pygame.time.get_ticks(), position)

        if shard.position.y > self.vertical_shift + HEIGHT_IN_TILES:
            # shard is below the screen
            particle = ParticleSprite.create_shard_pointer(
                self,
                Position(shard.position.x, self.vertical_shift + HEIGHT_IN_TILES - 2),
                CardinalDirection.SOUTH
            )
            self.particle_group.add(particle)
        elif shard.position.y < self.vertical_shift:
            # shard is above the screen
            particle = ParticleSprite.create_shard_pointer(
                self,
                Position(shard.position.x, self.vertical_shift + 1),
                CardinalDirection.NORTH
            )
            self.particle_group.add(particle)
Beispiel #16
0
    def apply(self, subject: Any):
        player: Player = subject

        current_position = player.get_position()
        current_y = current_position.y
        future_y = current_y + self.steps

        if 0 <= future_y < self.environment.get_tile_dimensions()[1] - 1:

            future_position = Position(player.get_position().x, future_y)

            if self.environment.tile_at(future_position).is_walkable():
                player.set_position(future_position)
            else:
                raise ActionException(f"Vertical move would end up on non-"
                                      f"walkable position {future_position}")
        else:
            raise ActionException(
                f"Vertical move outside of bounds: {future_y}")
Beispiel #17
0
    def test_should_record_correctly(self):
        r = Recording()
        r.start(10_000)

        r.record_text_input(10_100, "kLhi")
        r.record_text_input(10_200, "k")
        r.record_shard_spawn(10_300, Position(1, 1))
        r.record_text_input(10_500, "I")

        self.assertEqual(5, len(r.data))
        self.assertEqual(0, r.data[0].time)
        self.assertIsInstance(r.data[0], VersionInfo)
        self.assertEqual(100, r.data[1].time)
        self.assertIsInstance(r.data[1], TextInput)
        self.assertEqual(200, r.data[2].time)
        self.assertIsInstance(r.data[2], TextInput)
        self.assertEqual(300, r.data[3].time)
        self.assertIsInstance(r.data[3], ShardSpawn)
        self.assertEqual(500, r.data[4].time)
        self.assertIsInstance(r.data[4], TextInput)
Beispiel #18
0
    def __init__(self, scene: 'GameScene', animation: Animation,
                 position: Position, px_offset: Position = Position(0, 0),
                 flip_x: bool = False, flip_y: bool = False,
                 *groups: AbstractGroup):
        super().__init__(*groups)

        self.scene = scene
        self.animation = animation
        self.position = position
        self.px_offset = px_offset
        self.flip_x = flip_x
        self.flip_y = flip_y

        # automatically start the animation on creation
        self.animation.start(pygame.time.get_ticks())

        self._update_image()

        self.rect = self.image.get_rect()
        self._update_rectangle_based_on_vertical_shift()
Beispiel #19
0
    def apply(self, subject: Player):

        current_position = subject.get_position()
        current_x = current_position.x
        future_x = current_x + self.steps

        if 0 <= future_x < self.environment.get_tile_dimensions()[0]:

            future_position = Position(future_x, subject.get_position().y)

            if self.environment.tile_at(future_position).is_walkable():
                subject.set_position(future_position)

                future_direction = CardinalDirection.EAST \
                    if self.steps > 0 else CardinalDirection.WEST
                subject.set_direction(future_direction)
            else:
                raise ActionException(f"Horizontal move would end up on non-"
                                      f"walkable position {future_position}")

        else:
            raise ActionException(
                f"Horizontal move outside of bounds: {future_x}")
Beispiel #20
0
 def __init__(self):
     self.position = Position(0, 0)
     self.direction = CardinalDirection.EAST
Beispiel #21
0
 def parse(text: str) -> 'ShardSpawn':
     parts = text.split()
     if parts[0] != "S" or len(parts) != 4:
         raise ParsingException("Not a ShardSpawn event")
     return ShardSpawn(int(parts[1]), Position(int(parts[2]),
                                               int(parts[3])))
Beispiel #22
0
 def get_random_position(environment: 'Environment') -> Position:
     w, h = environment.get_tile_dimensions()
     x = random.randint(0, w - 1)
     y = random.randint(0, h - 2)
     return Position(x, y)