Beispiel #1
0
    def __init__(self, name=None):
        super(Sprite, self).__init__()

        # Signals
        self.moved = Signal()
        self.dead = Signal()

        # State
        self.quad_trees = set()
        self.layer = None
        self.name = name or self.NAME
        assert self.name

        self.started = False
        self.direction = Direction.SOUTH
        self.velocity = (0, 0)
        self.speed = self.MOVE_SPEED

        self.can_move = True
        self.use_quadtrees = True
        self.autoset_velocity = True

        self.frame_state = 'default'
        self.anim_frame = 0
        self.anim_timer = None
Beispiel #2
0
    def __init__(self, level):
        self.level = level
        self.rects = []
        self._moved_cnxs = []
        level.register_for_events(self)
        self.entered_objects = set()

        # Signals
        self.event_fired = Signal()
        self.object_moved = Signal()
        self.object_entered = Signal()
        self.object_exited = Signal()
Beispiel #3
0
    def __init__(self):
        super(Player, self).__init__('player')

        # Signals
        self.health_changed = Signal()
        self.lives_changed = Signal()

        # State
        self.human_kill_count = 0
        self.shoot_timer = Timer(ms=self.SHOOT_MS,
                                 cb=self.shoot,
                                 start_automatically=False)
        self.reset()
Beispiel #4
0
class Wife(ChaseMixin, Human, WalkingSprite):
    MOVE_SPEED = 1
    CHASE_SPEED = 1
    WANDER_KEY_NAME = 'walking'
    DEFAULT_HEALTH = 1
    CLEAN_NAME = 'wife'
    INFECTED_NAME = 'infectedwife'
    NAME = INFECTED_NAME
    TRANSITION_MS = 250
    MAX_TRANSITIONS = 6

    def __init__(self):
        super(Wife, self).__init__()

        self.transitioned = Signal()
        self.showed_exclamation = False

    def on_collision(self, dx, dy, obj, self_rect, obj_rect):
        if obj == get_engine().player and not self.showed_exclamation:
            get_engine().ui.close_monologues()
            self.show_exclamation('heart_exclamation',
                                  self._transition_clean)
            self.showed_exclamation = True

    def _transition_clean(self):
        self.transition_count = 0
        self.transition_timer = Timer(ms=self.TRANSITION_MS,
                                      cb=lambda: self._on_transition())

    def _on_transition(self):
        self.transition_count += 1

        if self.name == self.INFECTED_NAME:
            self.name = self.CLEAN_NAME
        else:
            self.name = self.INFECTED_NAME

        if self.transition_count == self.MAX_TRANSITIONS:
            self.name = self.CLEAN_NAME
            self.transition_timer.stop()
            self.transitioned.emit()
Beispiel #5
0
class EventBox(object):
    def __init__(self, level):
        self.level = level
        self.rects = []
        self._moved_cnxs = []
        level.register_for_events(self)
        self.entered_objects = set()

        # Signals
        self.event_fired = Signal()
        self.object_moved = Signal()
        self.object_entered = Signal()
        self.object_exited = Signal()

    def disconnect(self):
        self.level.unregister_for_events(self)

        for cnx in self._moved_cnxs:
            cnx.disconnect()

        self._moved_cnxs = []

    def watch_object_moves(self, obj):
        self._moved_cnxs.append(obj.moved.connect(lambda dx, dy: self.handle_object_move(obj)))

    def handle_event(self, event):
        return self.event_fired.emit(event)

    def handle_object_move(self, obj):
        if obj.layer.parent != self.level:
            return

        obj_rects = obj.get_absolute_collision_rects()

        for obj_rect in obj_rects:
            if obj_rect.collidelist(self.rects) != -1:
                if obj not in self.entered_objects:
                    self.entered_objects.add(obj)
                    self.object_entered.emit(obj)

                self.object_moved.emit(obj)
            elif obj in self.entered_objects:
                self.entered_objects.remove(obj)
                self.object_exited.emit(obj)
Beispiel #6
0
class Sprite(BaseSprite):
    NAME = None
    MOVE_SPEED = 4
    RUN_SPEED = 8
    ANIM_MS = 150
    DEATH_BLINK_MS = 250
    MAX_BLINKS = 4
    LETHAL = False

    SPRITESHEET_ROWS = 1
    SPRITESHEET_COLS = 1
    SPRITESHEET_FRAMES = {
        Direction.SOUTH: {
            'default': [(0, 0)],
        },
        Direction.WEST: {
            'default': [(0, 0)],
        },
        Direction.EAST: {
            'default': [(0, 0)],
        },
        Direction.NORTH: {
            'default': [(0, 0)],
        },
    }

    NEED_TICKS = True

    def __init__(self, name=None):
        super(Sprite, self).__init__()

        # Signals
        self.moved = Signal()
        self.dead = Signal()

        # State
        self.quad_trees = set()
        self.layer = None
        self.name = name or self.NAME
        assert self.name

        self.started = False
        self.direction = Direction.SOUTH
        self.velocity = (0, 0)
        self.speed = self.MOVE_SPEED

        self.can_move = True
        self.use_quadtrees = True
        self.autoset_velocity = True

        self.frame_state = 'default'
        self.anim_frame = 0
        self.anim_timer = None

    def start(self):
        self.anim_timer = Timer(ms=self.ANIM_MS,
                                cb=self._on_anim_tick,
                                start_automatically=False)
        self.started = True

    def stop(self):
        self.stop_moving()
        self.started = False

    def damage(self, damage_value):
        if self.health > 0:
            self.health -= damage_value

            if self.health <= 0:
                self.die()
                return True

        return False

    def die(self, on_done=None):
        self.stop()
        self.blink(self.DEATH_BLINK_MS, lambda: self._stop_and_die(on_done))

    def _stop_and_die(self, on_done):
        self.dead.emit()
        self.remove()

        if on_done:
            on_done()

    def blink(self, ms, on_done):
        self.blink_count = 0
        self.visible = 0
        self.blink_timer = Timer(ms=ms, cb=lambda: self._on_blinked(on_done))

    def _on_blinked(self, on_done):
        self.blink_count += 1

        if self.visible:
            self.visible = 0
        else:
            self.visible = 1

        if self.blink_count == self.MAX_BLINKS:
            self.visible = 1
            self.blink_timer.stop()

            if on_done:
                on_done()

    def remove(self):
        self.stop()
        self.collidable = False
        self.visible = 0
        self.dirty = 1
        self.layer.remove(self)
        self.layer = None

    def update_image(self):
        self.image = self.generate_image()
        assert self.image

        self.rect.size = self.image.get_size()
        self.update_collision_rects()

    def generate_image(self):
        return load_spritesheet_frame(
            self.name,
            self._get_spritesheet_frames()[self.anim_frame],
            self.SPRITESHEET_ROWS,
            self.SPRITESHEET_COLS)

    def _get_spritesheet_frames(self):
        return self.SPRITESHEET_FRAMES[self.direction][self.frame_state]

    def move_by(self, dx, dy, check_collisions=True):
        super(Sprite, self).move_by(dx, dy, check_collisions=check_collisions)
        self.moved.emit(dx, dy)

    def set_direction(self, direction):
        if self.direction != direction:
            self.direction = direction
            self.update_velocity()
            self.update_image()

    def start_animation(self, name):
        self.frame_state = name
        self.anim_frame = 0

        if self.anim_timer:
            self.anim_timer.stop()

        self.anim_timer = Timer(ms=self.ANIM_MS,
                                cb=self._on_anim_tick)

    def stop_moving(self):
        self.velocity = (0, 0)
        self.frame_state = 'default'
        self.anim_frame = 0

        if self.anim_timer:
            self.anim_timer.stop()

        self.anim_timer = None

    def recompute_direction(self):
        if abs(self.velocity[0]) > abs(self.velocity[1]):
            if self.velocity[0] > 0:
                self.set_direction(Direction.EAST)
            elif self.velocity[0] < 0:
                self.set_direction(Direction.WEST)
        elif abs(self.velocity[1]) >= abs(self.velocity[0]):
            if self.velocity[1] > 0:
                self.set_direction(Direction.SOUTH)
            elif self.velocity[1] < 0:
                self.set_direction(Direction.NORTH)

    def update_collision_rects(self):
        pass

    def update_velocity(self):
        if not self.started or not self.autoset_velocity:
            return

        x, y = {
            Direction.WEST: (-1, None),
            Direction.EAST: (1, None),
            Direction.NORTH: (None, -1),
            Direction.SOUTH: (None, 1),
        }[self.direction]

        if x:
            x *= self.speed
        else:
            x = self.velocity[0]

        if y:
            y *= self.speed
        else:
            y = self.velocity[1]

        self.velocity = (x, y)

    def tick(self):
        if self.started and self.velocity != (0, 0):
            self.move_by(*self.velocity)

    def _on_anim_tick(self):
        frames = self._get_spritesheet_frames()

        self.anim_frame += 1

        if self.anim_frame == len(frames):
            self.anim_frame = 0

        self.dirty = 2
        self.update_image()
Beispiel #7
0
class Player(WalkingSprite):
    MAX_LIVES = 3
    MAX_HEALTH = 8

    SHOOT_MS = 500
    FALL_SPEED = 10
    HURT_BLINK_MS = 250

    SPRITESHEET_COLS = 4
    SPRITESHEET_FRAMES = {
        Direction.SOUTH: dict(
            WalkingSprite.SPRITESHEET_FRAMES[Direction.SOUTH], **{
                'shooting': [(3, 0)],
                'falling': [(1, 0)],
            }),
        Direction.WEST: dict(
            WalkingSprite.SPRITESHEET_FRAMES[Direction.WEST], **{
                'shooting': [(3, 1)],
                'falling': [(1, 1)],
            }),
        Direction.EAST: dict(
            WalkingSprite.SPRITESHEET_FRAMES[Direction.EAST], **{
                'shooting': [(3, 2)],
                'falling': [(1, 2)],
            }),
        Direction.NORTH: dict(
            WalkingSprite.SPRITESHEET_FRAMES[Direction.NORTH], **{
                'shooting': [(3, 3)],
                'falling': [(1, 3)],
            }),
    }

    def __init__(self):
        super(Player, self).__init__('player')

        # Signals
        self.health_changed = Signal()
        self.lives_changed = Signal()

        # State
        self.human_kill_count = 0
        self.shoot_timer = Timer(ms=self.SHOOT_MS,
                                 cb=self.shoot,
                                 start_automatically=False)
        self.reset()

    def update_collision_rects(self):
        self.collision_rects = [
            pygame.Rect(0, self.rect.height / 2,
                        self.rect.width, self.rect.height / 2),
        ]

    def reset(self):
        self.health = self.MAX_HEALTH
        self.lives = self.MAX_LIVES
        self.invulnerable = False
        self.running = False
        self.falling = False
        self.shooting = False
        self.can_run = True
        self.collidable = True
        self.allow_player_control = True

        self.health_changed.emit()
        self.lives_changed.emit()

        self.set_running(True)
        self.stop_moving()
        self._update_animation()

    def handle_event(self, event):
        if not self.allow_player_control:
            return

        if event.type == KEYDOWN:
            if event.key == K_RIGHT:
                self.move_direction(Direction.EAST)
            elif event.key == K_LEFT:
                self.move_direction(Direction.WEST)
            elif event.key == K_UP:
                self.move_direction(Direction.NORTH)
            elif event.key == K_DOWN:
                self.move_direction(Direction.SOUTH)
            elif event.key == K_c:
                self.set_shooting(True)
            elif event.key == K_F4:
                self.collidable = not self.collidable
        elif event.type == KEYUP:
            if event.key == K_RIGHT:
                self.stop_moving_direction(Direction.EAST)
            elif event.key == K_LEFT:
                self.stop_moving_direction(Direction.WEST)
            elif event.key == K_UP:
                self.stop_moving_direction(Direction.NORTH)
            elif event.key == K_DOWN:
                self.stop_moving_direction(Direction.SOUTH)
            elif event.key == K_c:
                self.set_shooting(False)

    def move_direction(self, direction):
        self.direction = direction

        self.update_velocity()
        self._update_animation()

        self.update_image()

    def stop_moving_direction(self, direction):
        if direction in (Direction.WEST, Direction.EAST):
            self.velocity = (0, self.velocity[1])
        elif direction in (Direction.NORTH, Direction.SOUTH):
            self.velocity = (self.velocity[0], 0)

        # The direction may not make any sense anymore, so recompute it.
        self.recompute_direction()
        self._update_animation()

    def set_shooting(self, shooting):
        if self.shooting == shooting:
            return

        self.shooting = shooting

        if shooting:
            self.shoot_timer.start()
            self.shoot()
        else:
            self.shoot_timer.stop()

        self._update_animation()

    def shoot(self):
        bullet = Bullet(self)
        self.layer.add(bullet)

        bullet.move_beside(self, self.direction)
        bullet.start()
        bullet.set_direction(self.direction)
        bullet.update_velocity()

    def should_adjust_position_with(self, obj, dx, dy):
        return not isinstance(obj, Bullet) or obj.owner_sprite != self

    def set_running(self, running):
        self.running = running

        if running:
            self.speed = self.RUN_SPEED
        else:
            self.speed = self.MOVE_SPEED

        if self.velocity != (0, 0):
            self.update_velocity()

        self._update_animation()

    def stop_running(self):
        self.running = False
        self._update_animation()

    def fall(self):
        self.collidable = False
        self.stop_running()
        self.set_direction(Direction.SOUTH)
        self.velocity = (0, self.FALL_SPEED)
        self.falling = True
        self._update_animation()

    def _update_animation(self):
        if self.velocity == (0, 0):
            if self.shooting and self.frame_state != 'shooting':
                self.frame_state = 'shooting'
            elif not self.shooting and self.frame_state != 'default':
                self.frame_state = 'default'
            else:
                return

            self.anim_timer.stop()
        else:
            new_state = None

            if self.running and self.frame_state != 'running':
                new_state = 'running'
            elif self.falling:
                new_state = 'falling'
            elif self.frame_state != 'walking':
                new_state = 'walking'
            else:
                return

            if new_state:
                self.start_animation(new_state)

        self.anim_frame = 0
        self.update_image()

    def on_collision(self, dx, dy, obj, self_rect, obj_rect):
        if obj.LETHAL and self.health > 0:
            if not self.invulnerable:
                self.health -= 1
                self.health_changed.emit()

                if self.health == 0:
                    self.on_dead()
                else:
                    self.invulnerable = True
                    self.blink(self.HURT_BLINK_MS, self._on_hurt_blink_done)

            return True

    def _on_hurt_blink_done(self):
        self.invulnerable = False

    def on_dead(self):
        self.lives -= 1
        self.lives_changed.emit()
        self.stop_moving()

        engine = get_engine()

        if self.lives == 0:
            self.die(engine.game_over)
        else:
            self.health = self.MAX_HEALTH
            self.health_changed.emit()
            engine.dead()
Beispiel #8
0
    def __init__(self):
        super(Wife, self).__init__()

        self.transitioned = Signal()
        self.showed_exclamation = False