Example #1
0
def create_player_tank(dispatcher, atlas, x, y):
    # Creating the actual entity, which currently has only a name
    player = Entity(id='player')
    # Adding all necessary components, in our case input (which also spawns
    # bullets), two collision-related ones, position, health and a destructor
    # for orderly entity removal.
    player.add_component(InputComponent(dispatcher))
    player.add_component(WalkerCollisionComponent(dispatcher))
    player.add_component(PassingComponent(dispatcher))
    player.add_component(PositionComponent(dispatcher, x, y))
    player.add_component(DestructorHealthComponent(dispatcher, hitpoints=5))
    player.add_component(DestructorComponent(dispatcher))
    # Also a WidgetComponent, which requires a Widget
    images_dict = {
        'player_r': atlas.get_element('player_r'),
        'player_l': atlas.get_element('player_l'),
        'player_d': atlas.get_element('player_d'),
        'player_u': atlas.get_element('player_u')
    }
    player.add_component(
        SwitchWidgetComponent(
            dispatcher,
            SwitchingWidget(images_dict=images_dict,
                            initial_image='player_r')))
    dispatcher.add_event(BearEvent('ecs_create', player))
    dispatcher.add_event(
        BearEvent('ecs_add',
                  (player.id, player.position.x, player.position.y)))
    return player
Example #2
0
 def on_event(self, event):
     if event.event_type == 'tick':
         self.x_waited += event.event_value
         self.y_waited += event.event_value
         xpos, ypos = self.parent.widget_locations[self].pos
         self.vx += self.field[xpos][ypos].ax * event.event_value
         self.vy += self.field[xpos][ypos].ay * event.event_value
         if self.vx != 0:
             self.x_delay = abs(1 / self.vx)
         if self.vy != 0:
             self.y_delay = abs(1 / self.vy)
         if self.x_waited >= self.x_delay and self.vx != 0:
             new_x = xpos + round(self.vx/abs(self.vx))
             self.x_waited = 0
         else:
             new_x = xpos
         if self.y_waited >= self.y_delay and self.vy != 0:
             new_y = ypos + round(self.vy/abs(self.vy))
             self.y_waited = 0
         else:
             new_y = ypos
         if new_x != xpos or new_y != ypos:
             t = self.tetris.check_move((new_x, new_y), self.chars)
             if t == 0:
                 self.parent.move_widget(self, (new_x, new_y))
             elif t == 1:
                 return [BearEvent(event_type='request_installation',
                                   event_value=self),
                         BearEvent(event_type='play_sound',
                                   event_value='connect')]
             elif t == 2:
                 return [BearEvent(event_type='request_destruction',
                                  event_value=self),
                         BearEvent(event_type='play_sound',
                                   event_value='fly_away')]
Example #3
0
def create_enemy_tank(dispatcher, atlas, entity_id, x, y):
    # ControllerComponent
    # DestructorHealthComponent
    # WalkerCollisionComponent
    # SwitchWidgetComponent
    enemy = Entity(id=entity_id)
    # Adding all necessary components, in our case input (which also spawns
    # bullets), two collision-related ones, position, health and a destructor
    # for orderly entity removal.
    enemy.add_component(WalkerCollisionComponent(dispatcher))
    enemy.add_component(PassingComponent(dispatcher))
    enemy.add_component(PositionComponent(dispatcher, x, y))
    enemy.add_component(DestructorHealthComponent(dispatcher, hitpoints=1))
    enemy.add_component(DestructorComponent(dispatcher))
    enemy.add_component(ControllerComponent(dispatcher))
    # Also a WidgetComponent, which requires a Widget
    images_dict = {
        'enemy_r': atlas.get_element('enemy_r'),
        'enemy_l': atlas.get_element('enemy_l'),
        'enemy_d': atlas.get_element('enemy_d'),
        'enemy_u': atlas.get_element('enemy_u')
    }
    enemy.add_component(
        SwitchWidgetComponent(
            dispatcher,
            SwitchingWidget(images_dict=images_dict, initial_image='enemy_r')))
    dispatcher.add_event(BearEvent('ecs_create', enemy))
    dispatcher.add_event(
        BearEvent('ecs_add', (enemy.id, enemy.position.x, enemy.position.y)))
    return enemy
Example #4
0
def create_wall(dispatcher, atlas, entity_id, x, y):
    wall = Entity(entity_id)
    wall.add_component(PositionComponent(dispatcher, x, y))
    wall.add_component(CollisionComponent(dispatcher))
    wall.add_component(PassingComponent(dispatcher))
    wall.add_component(DestructorComponent(dispatcher))
    images_dict = {
        'wall_3': atlas.get_element('wall_3'),
        'wall_2': atlas.get_element('wall_2'),
        'wall_1': atlas.get_element('wall_1')
    }
    wall.add_component(
        SwitchWidgetComponent(
            dispatcher,
            SwitchingWidget(images_dict=images_dict, initial_image='wall_3')))
    wall.add_component(
        VisualDamageHealthComponent(dispatcher,
                                    hitpoints=3,
                                    widgets_dict={
                                        3: 'wall_3',
                                        2: 'wall_2',
                                        1: 'wall_1'
                                    }))

    dispatcher.add_event(BearEvent('ecs_create', wall))
    dispatcher.add_event(
        BearEvent('ecs_add', (wall.id, wall.position.x, wall.position.y)))
    pass
Example #5
0
    def on_event(self, event):
        """
        See class documentation

        :param event: BearEvent instance
        """
        r = []
        if event.event_type == 'ecs_move':
            entity_id, x, y = event.event_value
            # Checking if collision events need to be emitted
            # Check for collisions with border
            if x < 0 or x + self.entities[entity_id].widget.size[0]\
                 > len(self.chars[0]) or y < 0 or \
                 y + self.entities[entity_id].widget.size[1] > len(self.chars):
                r.append(
                    BearEvent(event_type='ecs_collision',
                              event_value=(entity_id, None)))
            else:
                # Apparently no collision with a border, can safely move
                self.move_child(self.widgets[entity_id], (x, y))
                self.need_redraw = True
                collided = set()
                for y_offset in range(self.entities[entity_id].widget.size[1]):
                    for x_offset in range(
                            self.entities[entity_id].widget.size[0]):
                        for other_widget in self._child_pointers[y+y_offset] \
                            [x+x_offset]:
                            # Child_pointers is ECS-agnostic and stores pointers
                            # to the actual widgets
                            collided.add(other_widget)
                collided_ent_ids = set()
                for child in self.entities:
                    if child != entity_id and \
                            self.entities[child].widget.widget in collided:
                        collided_ent_ids.add(child)
                for child in collided_ent_ids:
                    r.append(BearEvent('ecs_collision', (entity_id, child)))
        elif event.event_type == 'ecs_create':
            self.add_entity(event.event_value)
            self.need_redraw = True
        elif event.event_type == 'ecs_destroy':
            self.remove_entity(event.event_value)
            self.need_redraw = True
        elif event.event_type == 'ecs_remove':
            self.remove_child(self.entities[event.event_value].widget.widget)
            self.need_redraw = True
        elif event.event_type == 'ecs_add':
            entity_id, x, y = event.event_value
            self.add_child(self.widgets[entity_id], (x, y))
            self.need_redraw = True
        elif event.event_type == 'ecs_update':
            # Some widget has decided it's time to redraw itself
            self.need_redraw = True
        elif event.event_type == 'service' and event.event_value == 'tick_over'\
                and self.need_redraw:
            self._rebuild_self()
            self.terminal.update_widget(self)
            self.need_redraw = False
        if r:
            return r
Example #6
0
 def on_event(self, event):
     r = []
     if event.event_type == 'key_down':
         moved = False
         if event.event_value in ('TK_D', 'TK_RIGHT'):
             self.last_move = (1, 0)
             moved = True
         elif event.event_value in ('TK_A', 'TK_LEFT'):
             self.last_move = (-1, 0)
             moved = True
         elif event.event_value in ('TK_S', 'TK_DOWN'):
             self.last_move = (0, 1)
             moved = True
         elif event.event_value in ('TK_W', 'TK_UP'):
             self.last_move = (0, -1)
             moved = True
         if moved:
             # events
             self.relative_move(*self.last_move, emit_event=False)
             r.append(
                 BearEvent(event_type='ecs_move',
                           event_value=(self.owner.id, self.x, self.y)))
             r.append(BearEvent(event_type='play_sound',
                                event_value='step'))
     x = super().on_event(event)
     if x:
         if isinstance(x, BearEvent):
             r.append(x)
         else:
             #multiple return
             r += x
     return r
Example #7
0
def create_spawner_house(dispatcher, atlas, x, y):
    house = Entity('house')
    house.add_component(
        WidgetComponent(dispatcher, Widget(*atlas.get_element('spawner'))))
    house.add_component(DestructorComponent(dispatcher))
    house.add_component(PositionComponent(dispatcher, x, y))
    dispatcher.add_event(BearEvent('ecs_create', house))
    dispatcher.add_event(
        BearEvent('ecs_add', (house.id, house.position.x, house.position.y)))
Example #8
0
 def on_event(self, event):
     super().on_event(event)
     if event.event_type == 'tick':
         self.have_waited += event.event_value
         if self.have_waited >= self.delay:
             pos = self.terminal.widget_locations[self].pos
             if self.vx != 0:
                 new_x = pos[0]+round(abs(self.vx)/self.vx)
             else:
                 new_x = pos[0]
             if self.vy != 0:
                 new_y = pos[1]+round(abs(self.vy)/self.vy)
             else:
                 new_y = pos[1]
             self.terminal.move_widget(self, (new_x, new_y))
             # The emitter always moves clockwise
             # So some stuff is hardcoded
             if new_x == 0 and self.vx < 0:
                 #Lower left
                 self.vx = 0
                 self.vy = -1 * self.abs_vy
                 self.delay = 1/self.abs_vy
             elif new_y == 0 and self.vy < 0:
                 # Upper left
                 self.vy = 0
                 self.vx = self.abs_vx
                 self.delay = 1/self.abs_vx
             elif new_x + self.width == 60 and self.vx > 0:
                 #Upper right
                 self.vx = 0
                 self.vy = self.abs_vy
                 self.delay = 1/self.abs_vy
             elif new_y + self.height == 45 and self.vy > 0:
                 # Lower right
                 self.vx = -1 * self.abs_vx
                 self.vy = 0
                 self.delay = 1/self.abs_vx
             self.have_waited = 0
             for x_offset in range(5):
                 for y_offset in range(5):
                     if self.tetris[pos[0]+x_offset][pos[1]+y_offset] == 1:
                         return [BearEvent(event_type='game_lost',
                                           event_value=None),
                                 BearEvent(event_type='play_sound',
                                           event_value='fail')]
     elif event.event_type == 'request_installation' or \
             event.event_type == 'request_destruction':
         pos = self.terminal.widget_locations[self].pos
         self.fig = self.children[1]
         # The number 7 is empirical; maybe I'll change it later
         self.fig.vx = (30 - pos[0])/7
         self.fig.vy = (23-pos[1])/7
         self.remove_child(self.fig, remove_completely=True)
         self.dispatcher.register_listener(self.fig, 'tick')
         self.terminal.add_widget(self.fig, (pos[0]+1, pos[1]+1), layer=6)
         self.add_child(self.manager.create_figure(), (1, 1))
Example #9
0
def test_tick_events(event_dispatcher, listener):
    # Check that event_dispatcher does indeed emit test events
    event_dispatcher.register_listener(listener, event_types=['tick', 'input'])
    event_dispatcher.start_queue()
    event_dispatcher.add_event(BearEvent(event_type='tick'))
    event_dispatcher.add_event(BearEvent(event_type='input', event_value='A'))
    event_dispatcher.dispatch_events()
    assert 'tick' in listener.accepted_types
    assert 'service' not in listener.accepted_types
    assert 'input' in listener.accepted_types
Example #10
0
 def _run_iteration(self, time_since_last_tick):
     # Get input events, if any
     for event in self.terminal.check_input():
         self.queue.add_event(event)
     self.queue.add_event(BearEvent(event_type='tick',
                                    event_value=time_since_last_tick))
     self.queue.dispatch_events()
     # Sending "Tick over" event, reminding widgets to update themselves
     self.queue.add_event(BearEvent(event_type='service',
                                    event_value='tick_over'))
     self.queue.dispatch_events()
     self.terminal.refresh()
Example #11
0
def create_bullet(dispatcher, entity_id, x, y, vx, vy):
    bullet = Entity(entity_id)
    bullet.add_component(
        WidgetComponent(dispatcher, Widget([['*']], [['red']])))
    bullet.add_component(PositionComponent(dispatcher, x, y, vx, vy))
    bullet.add_component(ProjectileCollisionComponent(dispatcher, damage=1))
    bullet.add_component(DestructorComponent(dispatcher))
    dispatcher.add_event(BearEvent('ecs_create', bullet))
    dispatcher.add_event(
        BearEvent('ecs_add',
                  (bullet.id, bullet.position.x, bullet.position.y)))
    return bullet
Example #12
0
def create_barrel(atlas, dispatcher, x, y):
    barrel_entity = Entity(id='Barrel')
    widget = SimpleAnimationWidget(Animation(
        (atlas.get_element('barrel_1'), atlas.get_element('barrel_2')), 2),
                                   emit_ecs=True)
    widget_component = WidgetComponent(dispatcher, widget, owner=barrel_entity)
    position_component = PositionComponent(dispatcher,
                                           x=x,
                                           y=y,
                                           owner=barrel_entity)
    collision = CollisionComponent(dispatcher, owner=barrel_entity)
    dispatcher.add_event(
        BearEvent(event_type='ecs_create', event_value=barrel_entity))
    dispatcher.add_event(
        BearEvent(event_type='ecs_add', event_value=('Barrel', x, y)))
Example #13
0
 def on_event(self, event):
     if event.event_type == 'tick':
         self.rotated_this_tick = False
         self.move_cd -= event.event_value
         self.shoot_cd -= event.event_value
         if self.move_cd <= 0:
             try:
                 player_x = EntityTracker().entities['player'].position.x
                 player_y = EntityTracker().entities['player'].position.y
             except KeyError:
                 # DO NOTHING AFTER THE PLAYER IS DEAD
                 return
             dx = player_x - self.owner.position.x
             dy = player_y - self.owner.position.y
             # Turn towards player if has direct line of fire
             if abs(dx) < 3:
                 self.direction = (0, 1 if dy > 0 else -1)
                 self.owner.widget.switch_to_image(
                     self.images[self.direction])
             if abs(dy) < 3:
                 self.direction = (1 if dx > 0 else -1, 0)
                 self.owner.widget.switch_to_image(
                     self.images[self.direction])
             if self.direction is not None:
                 self.owner.position.relative_move(*self.direction)
                 # Shoot if necessary
                 if self.shoot_cd <= 0 and (abs(dx) < 3 or abs(dy) < 3):
                     offset = self.bullet_offsets[self.direction]
                     create_bullet(
                         self.dispatcher,
                         f'{self.owner.id}_bullet{self.bullet_count}',
                         self.owner.position.x + offset[0],
                         self.owner.position.y + offset[1],
                         self.direction[0] * 20, self.direction[1] * 20)
                     self.bullet_count += 1
                     self.shoot_cd = self.shoot_delay
                     self.dispatcher.add_event(
                         BearEvent('play_sound', 'shot'))
             else:
                 directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
                 if dx > 0:
                     directions.extend([(1, 0)] * int(dx / 10))
                 elif dx < 0:
                     directions.extend([(-1, 0)] * int(dx / -10))
                 if dy > 0:
                     directions.extend([(0, 1)] * int(dy / 10))
                 elif dy < 0:
                     directions.extend([(0, -1)] * int(dy / -10))
                 self.direction = choice(directions)
                 self.owner.widget.switch_to_image(
                     self.images[self.direction])
             self.move_cd = self.move_delay
     elif event.event_type == 'ecs_collision'\
             and event.event_value[0] == self.owner.id \
             and not self.rotated_this_tick:
         if event.event_value[1] is None or hasattr(
                 EntityTracker().entities[event.event_value[1]],
                 'collision'):
             self.direction = None
             self.rotated_this_tick = True
Example #14
0
 def collided_into(self, entity):
     if not entity:
         self.owner.destructor.destroy()
     elif hasattr(EntityTracker().entities[entity], 'collision'):
         self.dispatcher.add_event(
             BearEvent(event_type='ac_damage',
                       event_value=(entity, self.damage)))
         self.owner.destructor.destroy()
Example #15
0
    def check_input(self):
        """
        Check if terminal has input. If so, yield corresponding ``BearEvent``.

        This method returns an iterator because it's possible there would be
        more than one event in a single tick, eg when two buttons are pressed
        simultaneously.

        This method mostly just wraps bearlibterminal's input behaviour in
        `events<foo.wyrd.name/en:bearlibterminal:reference:input>`_, with
        a single exception: in bearlibterminal, when a key is pressed and held
        for more than a single tick, it first emits key_down, then waits for
        0.5 seconds. Then, if the key is not released, it assumes the key is
        indeed held and starts spamming events every tick. This makes sense to
        avoid messing up the typing (where a slow typist would get char
        sequences like tthiisss).

        Bearlibterminal, on the other hand, is meant mostly for games that
        require more precise input timing. Therefore, it starts spamming
        ``key_down`` events immediately after the button is pressed and expects
        widgets and listeners to mind their input cooldowns themselves.

        :yields: BearEvent instances with ``event_type`` set to ``misc_input``, ``key_up`` or ``key_down``.
        """
        while terminal.has_input():
            # Process the input event
            in_event = terminal.read()
            if in_event in self.misc_input:
                yield BearEvent('misc_input', self.misc_input[in_event])
            elif in_event in self._down_codes:
                self.currently_pressed.add(self._down_codes[in_event])
            elif in_event in self._up_codes:
                try:
                    self.currently_pressed.remove(self._up_codes[in_event])
                except KeyError:
                    # It's possible that the button was pressed before launching
                    # the bear_hug app, and released now. Then it obviously
                    # couldn't be in self.currently_pressed, causing exception
                    pass
                yield BearEvent('key_up', self._up_codes[in_event])
            else:
                raise BearException('Unknown input code {}'.format(in_event))
        for key in self.currently_pressed:
            yield BearEvent('key_down', key)
Example #16
0
    def check_input(self):
        """
        Check if terminal has input. If so, yield corresponding ``BearEvent``.

        This method returns an iterator because it's possible there would be
        more than one event in a single tick, eg when two buttons are pressed
        simultaneously.

        :yields: BearEvent instances with ``event_type`` set to ``misc_input``, ``key_up`` or ``key_down``.
        """
        while terminal.has_input():
            # Process the input event
            in_event = terminal.read()
            if in_event in self.misc_input:
                yield BearEvent('misc_input', self.misc_input[in_event])
            elif in_event in self._down_codes:
                yield BearEvent('key_down', self._down_codes[in_event])
            elif in_event in self._up_codes:
                yield BearEvent('key_up', self._up_codes[in_event])
            else:
                raise BearException('Unknown input code {}'.format(in_event))
Example #17
0
def create_cop(atlas, dispatcher, x, y):
    """
    Create a cop entity
    :param dispatcher:
    :return:
    """
    cop_entity = Entity(id='cop')
    t = Widget(*atlas.get_element('cop_r'))
    widget = deserialize_widget(repr(t))
    widget_component = WidgetComponent(dispatcher, widget, owner=cop_entity)
    position_component = WalkerComponent(dispatcher,
                                         x=x,
                                         y=y,
                                         owner=cop_entity)
    collision = WalkerCollisionComponent(dispatcher, owner=cop_entity)
    passing = PassingComponent(dispatcher,
                               shadow_pos=(0, 15),
                               shadow_size=(13, 3),
                               owner=cop_entity)
    dispatcher.add_event(
        BearEvent(event_type='ecs_create', event_value=cop_entity))
    dispatcher.add_event(
        BearEvent(event_type='ecs_add', event_value=('cop', x, y)))
Example #18
0
 def check_for_removal(self):
     """
     Check if something is to be removed
     :param pos:
     :return:
     """
     # Return events, so this is expected to be called by FigureManager's
     # on_event. Later BuildingWidget will catch the event and update itself
     # accordingly. Maybe also some sound emission or animation or something
     r = []
     for x in range(len(self.cells)-3):
         for y in range(len(self.cells[0])-3):
             # Check whether a given cell is a top-left corner of something
             if self[x][y] == 1:
                 if x <= len(self.cells) - 7:
                     #Check whether this cell is left side of horizontal 7
                     h7 = True
                     for x_1 in range(1, 7):
                         if self[x + x_1][y] != 1:
                             h7 = False
                     if h7:
                         for x_1 in range(7):
                             self[x+x_1][y] = 0
                         r += [BearEvent(event_type='h7',
                                        event_value=(x, y)),
                               BearEvent(event_type='play_sound',
                                         event_value='explosion')]
                 if y <= len(self.cells[0]) - 7:
                     # Or a vertical 7
                     v7 = True
                     for y_1 in range(1, 7):
                         if self[x][y+y_1] != 1:
                             v7 = False
                     if v7:
                         for y_1 in range(1, 7):
                             self[x][y+y_1] = 0
                         r += [(BearEvent(event_type='v7',
                                            event_value=(x, y))),
                               BearEvent(event_type='play_sound',
                                         event_value='explosion')]
                 if x <= len(self.cells)-3 and y <= len(self.cells[0])-3:
                     sq = True
                     for x_1 in range(3):
                         for y_1 in range(3):
                             if self[x+x_1][y+y_1] != 1:
                                 sq = False
                     if sq:
                         for x_1 in range(3):
                             for y_1 in range(3):
                                 self[x+x_1][y+y_1] = 0
                         r += [BearEvent(event_type='square',
                                            event_value=(x, y)),
                              BearEvent(event_type='play_sound',
                                        event_value='explosion')]
     return r
Example #19
0
    def destroy(self):
        """
        Destroy this component's owner.

        Unsubscribes owner and all its components from the queue and sends
        'ecs_remove'. Then all components are deleted. Entity itself is left at
        the mercy of garbage collector.
        """
        self.dispatcher.add_event(BearEvent('ecs_destroy', self.owner.id))
        self.is_destroying = True
        # Destroys item on the 'tick_over', so that all
        # existing events involving owner (including 'ecs_remove)' are processed
        # normally, but unsubscribes it right now to prevent new ones from forming
        for component in self.owner.components:
            if component != self.name:
                self.dispatcher.unregister_listener(
                    self.owner.__dict__[component])
Example #20
0
    def move(self, x, y, emit_event=True):
        """
        Move the Entity to a specified position.

        :param x: x

        :param y: y

        :param emit_event: If True, emit an 'esc_move' event. There are a few cases (ie setting the coordinates after the component is created, but before the entity is added to the terminal) where this is undesirable.
        """
        # This attr is set so that the turn could be undone (for example, that's
        # what WalkerCollision uses to avoid impossible steps).
        self.last_move = (x - self._x, y - self._y)
        self._x = x
        self._y = y
        if emit_event:
            self.dispatcher.add_event(BearEvent(event_type='ecs_move',
                                                event_value=(self.owner.id,
                                                             self._x,
                                                             self._y)))
Example #21
0
 def on_event(self, event):
     x = super().on_event(event)
     if isinstance(x, BearEvent):
         r = [x]
     elif isinstance(x, list):
         r = x
     else:
         r = []
     if event.event_type == 'key_down':
         moved = False
         if event.event_value == 'TK_SPACE':
             bullet_offset = self.bullet_offsets[
                 self.owner.position.last_move]
             create_bullet(self.dispatcher, f'bullet_{self.bullet_count}',
                           self.owner.position.x + bullet_offset[0],
                           self.owner.position.y + bullet_offset[1],
                           self.owner.position.last_move[0] * 20,
                           self.owner.position.last_move[1] * 20)
             self.bullet_count += 1
             self.dispatcher.add_event(BearEvent('play_sound', 'shot'))
         elif event.event_value in ('TK_D', 'TK_RIGHT'):
             move = (1, 0)
             self.owner.widget.switch_to_image('player_r')
             moved = True
         elif event.event_value in ('TK_A', 'TK_LEFT'):
             move = (-1, 0)
             self.owner.widget.switch_to_image('player_l')
             moved = True
         elif event.event_value in ('TK_S', 'TK_DOWN'):
             move = (0, 1)
             self.owner.widget.switch_to_image('player_d')
             moved = True
         elif event.event_value in ('TK_W', 'TK_UP'):
             move = (0, -1)
             self.owner.widget.switch_to_image('player_u')
             moved = True
         if moved:
             # Remembered for shots
             self.direction = move
             self.owner.position.relative_move(*move)
     return r
Example #22
0
    def on_event(self, event):
        """
        See class documentation.

        :param event: BearEvent instance.
        """
        # React to the events
        r = []
        if event.event_type == 'ecs_move':
            entity_id, x, y = event.event_value
            if entity_id not in self.entities or entity_id not in self.widgets:
                # Silently ignore attempts to move nonexistent children
                # Some entities may not be shown right now, but still have a
                # PositionComponent that moves and emits events
                return
            # Checking if collision events need to be emitted
            # Check for collisions with border
            try:
                if x < 0 or x + self.widgets[entity_id].width \
                        > len(self._child_pointers[0]) or y < 0 or \
                        y + self.widgets[entity_id].height > len(
                        self._child_pointers):
                    r.append(
                        BearEvent(event_type='ecs_collision',
                                  event_value=(entity_id, None)))
                else:
                    # Apparently no collision with a border, can safely move
                    try:
                        self.move_child(self.widgets[entity_id], (x, y))
                    except:
                        pass
                    self.need_redraw = True
            except KeyError:
                # In some weird cases 'ecs_move' events can be emitted after the
                # entity got destroyed
                return
        elif event.event_type == 'ecs_create':
            self.add_entity(event.event_value)
        elif event.event_type == 'ecs_destroy':
            self.remove_entity(event.event_value)
            self.need_redraw = True
        elif event.event_type == 'ecs_remove':
            self.remove_child(self.entities[event.event_value].widget.widget)
            self.need_redraw = True
        elif event.event_type == 'ecs_add':
            entity_id, x, y = event.event_value
            self.add_child(self.widgets[entity_id], (x, y))
            self.need_redraw = True
        elif event.event_type == 'ecs_scroll_to':
            try:
                self.scroll_to(event.event_value)
                self.need_redraw = True
            except BearLayoutException:
                pass
        elif event.event_type == 'ecs_scroll_by':
            try:
                self.scroll_by(event.event_value)
                self.need_redraw = True
            except BearLayoutException:
                pass
        elif event.event_type == 'ecs_update':
            # Some widget has decided it's time to redraw itself
            self.need_redraw = True
        elif event.event_type == 'service' and event.event_value == 'tick_over' \
                and self.need_redraw:
            self._rebuild_self()
            self.terminal.update_widget(self)
            self.need_redraw = False

        if r:
            return r
Example #23
0
 def process_hitpoint_update(self):
     if self.hitpoints == 0 and hasattr(self.owner, 'destructor'):
         # self.dispatcher.add_event(BearEvent('play_sound', 'explosion'))
         self.dispatcher.add_event(BearEvent('play_sound', 'explosion'))
         self.owner.destructor.destroy()
Example #24
0
def init_game():
    """
    Initalize all game variables and objects.
    :return:
    """
    global atlas
    global field
    global building
    global tetris
    global figures
    global t
    global attractor
    global attractor2
    global emitter
    global initial_figure
    global score
    global loop
    global dispatcher
    field = GravityField((60, 45))
    building = BuildingWidget((60, 45))
    tetris = TetrisSystem((60, 45))
    figures = FigureManager(field=field,
                            tetris=tetris,
                            dispatcher=dispatcher,
                            building=building,
                            atlas=atlas)
    figures.register_terminal(t)
    dispatcher.register_listener(
        figures, ['request_destruction', 'request_installation'])
    dispatcher.register_listener(building, ['square', 'h7', 'v7'])
    sound = SoundListener({
        'fly_away': 'Fly.wav',
        'explosion': 'Explosion.wav',
        'connect': 'Connect.wav',
        'fail': 'Fail.wav'
    })
    dispatcher.register_listener(sound, 'play_sound')
    # The construction's start
    building.add_figure(
        Widget([[' ', '*', ' '], ['*', '*', '*'], [' ', '*', ' ']],
               [['blue', 'blue', 'blue'], ['blue', 'blue', 'blue'],
                ['blue', 'blue', 'blue']]),
        pos=(29, 20))
    tetris[30][20] = 1
    tetris[29][21] = 1
    tetris[30][21] = 1
    tetris[31][21] = 1
    tetris[30][22] = 1

    # Emitter and attractors
    attractor = Attractor(*atlas.get_element('attractor'),
                          field=field,
                          mass=150)
    field.add_attractor(attractor, (10, 25))
    attractor2 = Attractor(*atlas.get_element('attractor'),
                           field=field,
                           mass=150)
    field.add_attractor(attractor2, (50, 25))
    dispatcher.register_listener(attractor,
                                 ['misc_input', 'key_up', 'key_down'])
    dispatcher.register_listener(attractor2,
                                 ['misc_input', 'key_up', 'key_down'])
    emitter = EmitterWidget(*atlas.get_element('emitter'),
                            manager=figures,
                            dispatcher=dispatcher,
                            tetris=tetris)
    dispatcher.register_listener(
        emitter,
        ['tick', 'service', 'request_installation', 'request_destruction'])
    initial_figure = figures.create_figure()
    dispatcher.register_listener(initial_figure, 'tick')
    score = ScoreCounter()
    dispatcher.register_listener(score, ['h7', 'v7', 'square'])
    # Adding stuff
    t.add_widget(score, pos=(39, 47), layer=1)
    t.add_widget(building, pos=(0, 0), layer=0)
    t.add_widget(attractor, pos=(10, 25), layer=1)
    t.add_widget(attractor2, pos=(50, 25), layer=3)
    t.add_widget(emitter, pos=(40, 40), layer=4)
    t.add_widget(initial_figure, pos=(25, 40), layer=6)
    dispatcher.add_event(
        BearEvent(event_type='request_destruction',
                  event_value=initial_figure))
Example #25
0
 def on_event(self, event):
     if event.event_type == 'ecs_create':
         entity = event.event_value
         # if hasattr(entity, 'position') and hasattr(entity, 'collision'):
         self.entities[entity.id] = entity
     elif event.event_type == 'ecs_destroy':
         del (self.entities[event.event_value])
         if event.event_value in self.currently_tracked:
             self.currently_tracked.remove(event.event_value)
     elif event.event_type == 'ecs_remove':
         if event.event_value in self.currently_tracked:
             self.currently_tracked.remove(event.event_value)
     elif event.event_type == 'ecs_add':
         # Anything added to the screen should have position and widget
         # But if it doesn't have CollisionComponent, it's not our problem
         if hasattr(self.entities[event.event_value[0]], 'collision'):
             self.currently_tracked.add(event.event_value[0])
     elif event.event_type == 'ecs_move' \
             and event.event_value[0] in self.currently_tracked:
         # Only process collisions between entities; if a collision into the
         # screen edge happens, it's the ECSLayout job to detect it
         moved_id, x, y = event.event_value
         moved_z = self.entities[moved_id].widget.z_level
         moved_depth = self.entities[moved_id].collision.depth
         moved_face = self.entities[moved_id].collision.face_position
         moved_face_size = self.entities[moved_id].collision.face_size
         moved_shift = self.entities[moved_id].collision.z_shift
         if moved_face_size == (0, 0):
             moved_face_size = self.entities[moved_id].widget.size
         r = []
         for other_id in self.currently_tracked:
             other = self.entities[other_id]
             if other_id == moved_id or not hasattr(other, 'position') \
                     or not hasattr(other, 'collision'):
                 continue
             other_z = other.widget.z_level
             other_depth = other.collision.depth
             other_shift = other.collision.z_shift
             if moved_z - moved_depth <= other_z and \
                     other_z - other_depth <= moved_z:
                 # Only check if two entities are within collidable z-levels
                 other_face = other.collision.face_position
                 other_face_size = other.collision.face_size
                 if other_face_size in ((0, 0), [0, 0]):
                     # The interaction is unclean, but it prevents running
                     # through this check every time something moves
                     other.collision.face_size = other.widget.size
                 z_range = (max(moved_z - moved_depth,
                                other_z - other_depth),
                            min(moved_z, other_z))
                 for z_level in range(z_range[0], z_range[1] + 1):
                     moved_pos = (x + moved_face[0] + moved_shift[0] *
                                  (moved_z - z_level), y + moved_face[1] +
                                  moved_shift[1] * (moved_z - z_level))
                     other_pos = (other.position.x + other_face[0] +
                                  other_shift[0] * (other_z - z_level),
                                  other.position.y + other_face[1] +
                                  other_shift[1] * (other_z - z_level))
                     if rectangles_collide(moved_pos, moved_face_size,
                                           other_pos, other_face_size):
                         r.append(
                             BearEvent('ecs_collision',
                                       (moved_id, other_id)))
                         continue
         return r
Example #26
0
    def on_event(self, event):
        """
        See class documentation.

        :param event: BearEvent instance.
        """
        # React to the events
        r = []
        if event.event_type == 'ecs_move':
            entity_id, x, y = event.event_value
            # Checking if collision events need to be emitted
            # Check for collisions with border
            try:
                if x < 0 or x + self.entities[entity_id].widget.size[0] \
                        > len(self._child_pointers[0]) or y < 0 or \
                        y + self.entities[entity_id].widget.size[1] > len(
                        self._child_pointers):
                    r.append(
                        BearEvent(event_type='ecs_collision',
                                  event_value=(entity_id, None)))
                else:
                    # Apparently no collision with a border, can safely move
                    self.move_child(self.widgets[entity_id], (x, y))
                    self.need_redraw = True
                    collided = set()
                    for y_offset in range(
                            self.entities[entity_id].widget.size[1]):
                        for x_offset in range(
                                self.entities[entity_id].widget.size[0]):
                            for other_widget in \
                            self._child_pointers[y + y_offset] \
                                    [x + x_offset]:
                                # Child_pointers is ECS-agnostic and stores pointers
                                # to the actual widgets
                                collided.add(other_widget)
                    # TODO: optimize to avoid checking all entities in collision detector
                    # Probably just storing all entity ids along with child pointers
                    collided_ent_ids = set()
                    for child in self.entities:
                        if child != entity_id and \
                                self.entities[child].widget.widget in collided:
                            collided_ent_ids.add(child)
                    for child in collided_ent_ids:
                        r.append(BearEvent('ecs_collision',
                                           (entity_id, child)))
            except KeyError:
                # In some weird cases 'ecs_move' events can be emitted after the
                # entity got destroyed
                return
        elif event.event_type == 'ecs_create':
            self.add_entity(event.event_value)
            self.need_redraw = True
        elif event.event_type == 'ecs_destroy':
            self.remove_entity(event.event_value)
            self.need_redraw = True
        elif event.event_type == 'ecs_remove':
            self.remove_child(self.entities[event.event_value].widget.widget)
            self.need_redraw = True
        elif event.event_type == 'ecs_add':
            entity_id, x, y = event.event_value
            self.add_child(self.widgets[entity_id], (x, y))
            self.need_redraw = True
        elif event.event_type == 'ecs_scroll_to':
            try:
                self.scroll_to(event.event_value)
                self.need_redraw = True
            except BearLayoutException:
                pass
        elif event.event_type == 'ecs_scroll_by':
            try:
                self.scroll_by(event.event_value)
                self.need_redraw = True
            except BearLayoutException:
                pass
        elif event.event_type == 'ecs_update':
            # Some widget has decided it's time to redraw itself
            self.need_redraw = True
        elif event.event_type == 'service' and event.event_value == 'tick_over' \
                and self.need_redraw:
            self._rebuild_self()
            self.terminal.update_widget(self)
            self.need_redraw = False

        if r:
            return r