예제 #1
0
    def handle_nearby_entities(self, player_entity: WorldEntity,
                               game_state: GameState, game_engine: GameEngine):
        self.entity_to_interact_with = None
        player_position = player_entity.get_position()
        distance_to_closest_entity = sys.maxsize

        for npc in game_state.non_player_characters:
            if has_npc_dialog(npc.npc_type):
                close_to_player = is_x_and_y_within_distance(
                    player_position, npc.world_entity.get_position(), 75)
                distance = get_manhattan_distance_between_rects(
                    player_entity.rect(), npc.world_entity.rect())
                if close_to_player and distance < distance_to_closest_entity:
                    self.entity_to_interact_with = npc
                    distance_to_closest_entity = distance

        lootables_on_ground: List[LootableOnGround] = list(
            game_state.items_on_ground)
        lootables_on_ground += game_state.consumables_on_ground
        for lootable in lootables_on_ground:
            if boxes_intersect(player_entity.rect(),
                               lootable.world_entity.rect()):
                self.entity_to_interact_with = lootable
                distance_to_closest_entity = 0

        for portal in game_state.portals:
            close_to_player = is_x_and_y_within_distance(
                player_position, portal.world_entity.get_position(), 75)
            distance = get_manhattan_distance_between_rects(
                player_entity.rect(), portal.world_entity.rect())
            if close_to_player:
                game_engine.handle_being_close_to_portal(portal)
            if close_to_player and distance < distance_to_closest_entity:
                self.entity_to_interact_with = portal
                distance_to_closest_entity = distance

        for warp_point in game_state.warp_points:
            close_to_player = is_x_and_y_within_distance(
                player_position, warp_point.world_entity.get_position(), 75)
            distance = get_manhattan_distance_between_rects(
                player_entity.rect(), warp_point.world_entity.rect())
            if close_to_player and distance < distance_to_closest_entity:
                self.entity_to_interact_with = warp_point
                distance_to_closest_entity = distance

        for chest in game_state.chests:
            close_to_player = is_x_and_y_within_distance(
                player_position, chest.world_entity.get_position(), 75)
            distance = get_manhattan_distance_between_rects(
                player_entity.rect(), chest.world_entity.rect())
            if close_to_player and distance < distance_to_closest_entity:
                self.entity_to_interact_with = chest
                distance_to_closest_entity = distance
예제 #2
0
    def run_one_frame(self, time_passed: Millis) -> List[EngineEvent]:

        events = []

        for npc in self.game_state.non_player_characters:
            # NonPlayerCharacter AI shouldn't run if enemy is too far out of sight
            if self._is_npc_close_to_camera(
                    npc) and not npc.stun_status.is_stunned():
                npc.npc_mind.control_npc(
                    self.game_state, npc, self.game_state.player_entity,
                    self.game_state.player_state.is_invisible, time_passed)

        for projectile in self.game_state.projectile_entities:
            projectile.projectile_controller.notify_time_passed(
                self.game_state, projectile, time_passed)

        for visual_effect in self.game_state.visual_effects:
            visual_effect.notify_time_passed(time_passed)

        self.game_state.handle_camera_shake(time_passed)

        npcs_that_died = self.game_state.remove_dead_npcs()
        enemies_that_died = [e for e in npcs_that_died if e.is_enemy]
        if enemies_that_died:
            exp_gained = sum([
                NON_PLAYER_CHARACTERS[e.npc_type].exp_reward
                for e in enemies_that_died
            ])
            self.game_state.visual_effects.append(
                create_visual_exp_text(self.game_state.player_entity,
                                       exp_gained))
            gain_exp_events = self.game_state.player_state.gain_exp(exp_gained)
            self._handle_gain_exp_events(gain_exp_events)

            for enemy_that_died in enemies_that_died:
                if enemy_that_died.death_sound_id:
                    play_sound(enemy_that_died.death_sound_id)
                else:
                    play_sound(SoundId.EVENT_ENEMY_DIED)
                loot = enemy_that_died.enemy_loot_table.generate_loot()
                enemy_death_position = enemy_that_died.world_entity.get_position(
                )
                self._put_loot_on_ground(enemy_death_position, loot)
                self.game_state.player_state.notify_about_event(
                    EnemyDiedEvent(), self.game_state)
            events.append(EngineEvent.ENEMY_DIED)

        self.game_state.remove_expired_projectiles()
        self.game_state.remove_expired_visual_effects()
        self.game_state.remove_opened_chests()

        player_buffs_update = self.game_state.player_state.handle_buffs(
            time_passed)
        for buff in player_buffs_update.buffs_that_started:
            buff.buff_effect.apply_start_effect(self.game_state,
                                                self.game_state.player_entity,
                                                None)
        for buff in player_buffs_update.buffs_that_were_active:
            buff_should_end = buff.buff_effect.apply_middle_effect(
                self.game_state, self.game_state.player_entity, None,
                time_passed)
            if buff_should_end:
                buff.force_cancel()

        for buff in player_buffs_update.buffs_that_ended:
            buff.buff_effect.apply_end_effect(self.game_state,
                                              self.game_state.player_entity,
                                              None)

        for enemy in self.game_state.non_player_characters:
            enemy.health_resource.regenerate(time_passed)
            buffs_update = handle_buffs(enemy.active_buffs, time_passed)
            for buff in buffs_update.buffs_that_started:
                buff.buff_effect.apply_start_effect(self.game_state,
                                                    enemy.world_entity, enemy)
            for buff in buffs_update.buffs_that_were_active:
                buff.buff_effect.apply_middle_effect(self.game_state,
                                                     enemy.world_entity, enemy,
                                                     time_passed)
            for buff in buffs_update.buffs_that_ended:
                buff.buff_effect.apply_end_effect(self.game_state,
                                                  enemy.world_entity, enemy)

        for item_effect in self.game_state.player_state.item_inventory.get_all_active_item_effects(
        ):
            item_effect.apply_middle_effect(self.game_state, time_passed)

        self.game_state.player_state.health_resource.regenerate(time_passed)
        self.game_state.player_state.mana_resource.regenerate(time_passed)
        self.game_state.player_state.recharge_ability_cooldowns(time_passed)

        self.game_state.player_entity.update_movement_animation(time_passed)
        for npc in self.game_state.non_player_characters:
            npc.world_entity.update_movement_animation(time_passed)
        for projectile in self.game_state.projectile_entities:
            projectile.world_entity.update_movement_animation(time_passed)
        for warp_point in self.game_state.warp_points:
            warp_point.world_entity.update_animation(time_passed)

        for npc in self.game_state.non_player_characters:
            # Enemies shouldn't move towards player when they are out of sight
            if self._is_npc_close_to_camera(
                    npc) and not npc.stun_status.is_stunned():
                self.game_state.update_npc_position_within_game_world(
                    npc, time_passed)
        # player can still move when stunned (could be charging)
        self.game_state.update_world_entity_position_within_game_world(
            self.game_state.player_entity, time_passed)
        for projectile in self.game_state.projectile_entities:
            new_pos = projectile.world_entity.get_new_position_according_to_dir_and_speed(
                time_passed)
            projectile.world_entity.set_position(new_pos)

        for visual_effect in self.game_state.visual_effects:
            visual_effect.update_position_if_attached_to_entity()
            if visual_effect.attached_to_entity:
                npcs = [
                    e.world_entity
                    for e in self.game_state.non_player_characters
                ]
                projectiles = [
                    p.world_entity for p in self.game_state.projectile_entities
                ]
                if not visual_effect.attached_to_entity in npcs + projectiles + [
                        self.game_state.player_entity
                ]:
                    visual_effect.has_expired = True

        # ------------------------------------
        #          HANDLE COLLISIONS
        # ------------------------------------

        for money_pile in self.game_state.money_piles_on_ground:
            if boxes_intersect(self.game_state.player_entity.rect(),
                               money_pile.world_entity.rect()):
                play_sound(SoundId.EVENT_PICKED_UP_MONEY)
                money_pile.has_been_picked_up_and_should_be_removed = True
                self.game_state.player_state.modify_money(money_pile.amount)

        for enemy in [
                e for e in self.game_state.non_player_characters if e.is_enemy
        ]:
            for projectile in self.game_state.get_projectiles_intersecting_with(
                    enemy.world_entity):
                if not projectile.has_collided_and_should_be_removed:
                    projectile.projectile_controller.apply_enemy_collision(
                        enemy, self.game_state, projectile)

        for player_summon in [
                npc for npc in self.game_state.non_player_characters
                if npc.npc_category == NpcCategory.PLAYER_SUMMON
        ]:
            for projectile in self.game_state.get_projectiles_intersecting_with(
                    player_summon.world_entity):
                if not projectile.has_collided_and_should_be_removed:
                    projectile.projectile_controller.apply_player_summon_collision(
                        player_summon, self.game_state, projectile)

        for projectile in self.game_state.get_projectiles_intersecting_with(
                self.game_state.player_entity):
            if not projectile.has_collided_and_should_be_removed:
                projectile.projectile_controller.apply_player_collision(
                    self.game_state, projectile)

        for projectile in self.game_state.projectile_entities:
            if not projectile.has_collided_and_should_be_removed:
                if self.game_state.walls_state.does_entity_intersect_with_wall(
                        projectile.world_entity):
                    projectile.projectile_controller.apply_wall_collision(
                        self.game_state, projectile)

        self.game_state.remove_money_piles_that_have_been_picked_up()
        self.game_state.remove_projectiles_that_have_been_destroyed()

        # ------------------------------------
        #       UPDATE CAMERA POSITION
        # ------------------------------------

        self.game_state.center_camera_on_player()

        if self.game_state.player_state.health_resource.is_at_or_below_zero():
            events.append(EngineEvent.PLAYER_DIED)

        return events
예제 #3
0
 def get_projectiles_intersecting_with(
         self, entity: WorldEntity) -> List[Projectile]:
     return [
         p for p in self.projectile_entities
         if boxes_intersect(entity.rect(), p.world_entity.rect())
     ]
예제 #4
0
 def get_enemy_intersecting_with(
         self, entity: WorldEntity) -> List[NonPlayerCharacter]:
     return [
         e for e in self.non_player_characters if e.is_enemy
         and boxes_intersect(e.world_entity.rect(), entity.rect())
     ]
예제 #5
0
 def does_entity_intersect_with_wall(self, entity: WorldEntity):
     nearby_walls = self.get_walls_close_to_position(entity.get_position())
     return any([
         w for w in nearby_walls if boxes_intersect(w.rect(), entity.rect())
     ])