예제 #1
0
class QuestGiverNpcMind(AbstractNpcMind):
    def __init__(self, global_path_finder: GlobalPathFinder, quest_id: QuestId, quest_item_id: ItemId,
                 quest_min_level: int):
        super().__init__(global_path_finder)
        self.timer = PeriodicTimer(Millis(500))
        self.quest_timer = PeriodicTimer(Millis(1000))
        self.quest_id = quest_id
        self.quest_item_id = quest_item_id
        self.quest_min_level = quest_min_level

    def control_npc(self, game_state: GameState, npc: NonPlayerCharacter, player_entity: WorldEntity,
                    is_player_invisible: bool, time_passed: Millis):

        if self.quest_timer.update_and_check_if_ready(time_passed):
            player_state = game_state.player_state
            if player_state.has_quest(self.quest_id):
                if player_state.item_inventory.has_item_in_inventory(self.quest_item_id):
                    npc.quest_giver_state = QuestGiverState.CAN_COMPLETE_QUEST
                else:
                    npc.quest_giver_state = QuestGiverState.WAITING_FOR_PLAYER
            elif player_state.has_completed_quest(self.quest_id):
                npc.quest_giver_state = None
            elif player_state.level >= self.quest_min_level:
                npc.quest_giver_state = QuestGiverState.CAN_GIVE_NEW_QUEST
            else:
                npc.quest_giver_state = None

        if self.timer.update_and_check_if_ready(time_passed):
            if random.random() < 0.8:
                npc.world_entity.set_not_moving()
            else:
                direction = random.choice(get_all_directions())
                npc.world_entity.set_moving_in_dir(direction)
예제 #2
0
class DebuffedByGoatsRing(AbstractBuffEffect):
    def __init__(self):
        self.dmg_timer = PeriodicTimer(Millis(1000))
        self.graphics_timer = PeriodicTimer(Millis(400))

    def apply_middle_effect(self, game_state: GameState,
                            buffed_entity: WorldEntity,
                            buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.dmg_timer.update_and_check_if_ready(time_passed):
            deal_player_damage_to_enemy(game_state,
                                        buffed_npc,
                                        1,
                                        DamageType.MAGIC,
                                        damage_source=DAMAGE_SOURCE)
        if self.graphics_timer.update_and_check_if_ready(time_passed):
            position = buffed_entity.get_center_position()
            visual_effect1 = VisualCircle((0, 100, 40), position, 9, 16,
                                          Millis(400), 2, buffed_entity)
            visual_effect2 = VisualCircle((0, 180, 90), position, 9, 16,
                                          Millis(500), 2, buffed_entity)
            game_state.visual_effects.append(visual_effect1)
            game_state.visual_effects.append(visual_effect2)

    def get_buff_type(self):
        return BUFF_TYPE
예제 #3
0
class Channeling(AbstractBuffEffect):
    def __init__(self):
        self.timer = PeriodicTimer(CHANNEL_PROJECTILE_INTERVAL)

    def apply_start_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter):
        game_state.player_state.stun_status.add_one()
        game_state.player_entity.set_not_moving()
        game_state.camera_shake = CameraShake(Millis(50), CHANNEL_DURATION, 5)

    def apply_middle_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            player_center_position = game_state.player_entity.get_center_position()
            projectile_pos = get_position_from_center_position(player_center_position, PROJECTILE_SIZE)
            entity = WorldEntity(projectile_pos, PROJECTILE_SIZE, Sprite.PROJECTILE_PLAYER_ARCANE_FIRE,
                                 game_state.player_entity.direction, PROJECTILE_SPEED)
            projectile = Projectile(entity, create_projectile_controller(ProjectileType.PLAYER_ARCANE_FIRE))
            game_state.projectile_entities.append(projectile)
            game_state.visual_effects.append(VisualRect((250, 0, 250), player_center_position, 45, 60, Millis(250), 1))

    def apply_end_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter):
        game_state.player_state.stun_status.remove_one()

    def get_buff_type(self):
        return BuffType.CHANNELING_ARCANE_FIRE
예제 #4
0
class DamagedByInfusedDagger(AbstractBuffEffect):
    def __init__(self, should_stun: bool):
        self.timer = PeriodicTimer(DAMAGE_TICK_INTERVAL)
        self.should_stun = should_stun

    def apply_start_effect(self, game_state: GameState,
                           buffed_entity: WorldEntity,
                           buffed_npc: NonPlayerCharacter):
        if self.should_stun:
            buffed_npc.stun_status.add_one()
            buffed_entity.set_not_moving()
            game_state.game_world.visual_effects.append(
                create_visual_stun_text(buffed_entity))

    def apply_middle_effect(self, game_state: GameState,
                            buffed_entity: WorldEntity,
                            buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            deal_player_damage_to_enemy(game_state, buffed_npc,
                                        DAMAGE_PER_TICK, DamageType.PHYSICAL)
            if self.should_stun:
                effect_position = buffed_entity.get_center_position()
                game_state.game_world.visual_effects.append(
                    VisualRect((250, 250, 50), effect_position, 30, 40,
                               Millis(100), 1, buffed_entity))

    def apply_end_effect(self, game_state: GameState,
                         buffed_entity: WorldEntity,
                         buffed_npc: NonPlayerCharacter):
        if self.should_stun:
            buffed_npc.stun_status.remove_one()

    def get_buff_type(self):
        return DEBUFF
예제 #5
0
class Rooted(AbstractBuffEffect):
    def __init__(self):
        self.timer = PeriodicTimer(DEBUFF_DAMAGE_INTERVAL)

    def apply_start_effect(self, game_state: GameState,
                           buffed_entity: WorldEntity,
                           buffed_npc: NonPlayerCharacter):
        buffed_npc.stun_status.add_one()
        game_state.visual_effects.append(
            create_visual_stun_text(buffed_entity))

    def apply_middle_effect(self, game_state: GameState,
                            buffed_entity: WorldEntity,
                            buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            deal_player_damage_to_enemy(game_state, buffed_npc, 1,
                                        DamageType.MAGIC)
            game_state.visual_effects.append(
                VisualCircle((0, 150, 0), buffed_entity.get_center_position(),
                             30, 55, Millis(150), 2, buffed_entity))

    def apply_end_effect(self, game_state: GameState,
                         buffed_entity: WorldEntity,
                         buffed_npc: NonPlayerCharacter):
        buffed_npc.stun_status.remove_one()

    def get_buff_type(self):
        return BUFF_TYPE
예제 #6
0
class BloodLust(StatModifyingBuffEffect):

    def __init__(self):
        super().__init__(BUFF_TYPE, {HeroStat.LIFE_STEAL: LIFE_STEAL_BONUS_RATIO, HeroStat.MOVEMENT_SPEED: SPEED_BONUS})
        self.timer = PeriodicTimer(Millis(250))

    def apply_start_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter):
        super().apply_start_effect(game_state, buffed_entity, buffed_npc)
        sword_slash_data = ABILITIES[AbilityType.SWORD_SLASH]
        sword_slash_data.cooldown -= SWORD_SLASH_CD_BONUS

    def apply_middle_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            visual_effect = VisualCircle(
                (250, 0, 0,), buffed_entity.get_center_position(), 25, 30, Millis(350), 1, buffed_entity)
            game_state.visual_effects.append(visual_effect)

    def apply_end_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter):
        super().apply_end_effect(game_state, buffed_entity, buffed_npc)
        sword_slash_data = ABILITIES[AbilityType.SWORD_SLASH]
        sword_slash_data.cooldown += SWORD_SLASH_CD_BONUS

    def buff_handle_event(self, event: Event) -> Optional[BuffEventOutcome]:
        if isinstance(event, EnemyDiedEvent):
            if has_blood_lust_duration_increase_upgrade:
                duration_increase = BLOODLUST_UPGRADED_INCREASED_DURATION_FROM_KILL
            else:
                duration_increase = BLOODLUST_INCREASED_DURATION_FROM_KILL
            return BuffEventOutcome.change_remaining_duration(duration_increase)
class ProjectileController(AbstractProjectileController):
    def __init__(self):
        super().__init__(2000)
        self._color = (50, 180, 50)
        self._timer = PeriodicTimer(Millis(100))
        self._min_damage = 8
        self._max_damage = 12

    def notify_time_passed(self, game_state: GameState, projectile: Projectile, time_passed: Millis):
        super().notify_time_passed(game_state, projectile, time_passed)
        if self._timer.update_and_check_if_ready(time_passed):
            head = VisualCircle(self._color, projectile.world_entity.get_center_position(), 15, 15,
                                Millis(150), 0, projectile.world_entity)
            tail = VisualCircle(self._color, projectile.world_entity.get_center_position(), 15, 1,
                                Millis(400), 0)
            game_state.visual_effects += [head, tail]

    def apply_player_collision(self, game_state: GameState, projectile: Projectile):
        damage = random.randint(self._min_damage, self._max_damage)
        deal_damage_to_player(game_state, damage, DamageType.MAGIC, None)
        game_state.visual_effects.append(VisualCircle(self._color, game_state.player_entity.get_center_position(),
                                                      25, 50, Millis(100), 0))
        projectile.has_collided_and_should_be_removed = True

    def apply_player_summon_collision(self, npc: NonPlayerCharacter, game_state: GameState, projectile: Projectile):
        damage = random.randint(self._min_damage, self._max_damage)
        deal_npc_damage_to_npc(game_state, npc, damage)
        game_state.visual_effects.append(
            VisualCircle(self._color, npc.world_entity.get_center_position(), 25, 50, Millis(100), 0))
        projectile.has_collided_and_should_be_removed = True

    def apply_wall_collision(self, game_state: GameState, projectile: Projectile):
        game_state.visual_effects.append(
            VisualCircle(self._color, projectile.world_entity.get_center_position(), 13, 26, Millis(100), 0))
        projectile.has_collided_and_should_be_removed = True
예제 #8
0
class Invisibility(AbstractBuffEffect):
    def __init__(self):
        self.timer = PeriodicTimer(Millis(320))

    def apply_start_effect(self, game_state: GameState,
                           buffed_entity: WorldEntity,
                           buffed_npc: NonPlayerCharacter):
        game_state.player_state.is_invisible = True

    def apply_middle_effect(self, game_state: GameState,
                            buffed_entity: WorldEntity,
                            buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            game_state.visual_effects.append(
                VisualRect((0, 0, 250),
                           game_state.player_entity.get_center_position(), 45,
                           60, Millis(400), 1, game_state.player_entity))

    def apply_end_effect(self, game_state: GameState,
                         buffed_entity: WorldEntity,
                         buffed_npc: NonPlayerCharacter):
        game_state.player_state.is_invisible = False

    def get_buff_type(self):
        return BUFF_TYPE
예제 #9
0
class BuffEffect(AbstractBuffEffect):
    def __init__(self):
        self.graphics_timer = PeriodicTimer(Millis(500))

    def apply_start_effect(self, game_state: GameState,
                           buffed_entity: WorldEntity,
                           buffed_npc: NonPlayerCharacter):
        buffed_entity.add_to_speed_multiplier(SPRINT_SPEED_BONUS)
        self.create_sprint_visual_effect(buffed_entity, game_state)

    def apply_middle_effect(self, game_state: GameState,
                            buffed_entity: WorldEntity,
                            buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.graphics_timer.update_and_check_if_ready(time_passed):
            self.create_sprint_visual_effect(buffed_entity, game_state)

    def apply_end_effect(self, game_state: GameState,
                         buffed_entity: WorldEntity,
                         buffed_npc: NonPlayerCharacter):
        buffed_entity.add_to_speed_multiplier(-SPRINT_SPEED_BONUS)

    def get_buff_type(self):
        return BUFF_SPRINT

    @staticmethod
    def create_sprint_visual_effect(buffed_entity: WorldEntity,
                                    game_state: GameState):
        game_state.game_world.visual_effects.append(
            VisualCircle((150, 50, 0), buffed_entity.get_center_position(), 20,
                         22, Millis(250), 2, buffed_entity))
예제 #10
0
class DebuffedByFreezingGauntlet(AbstractBuffEffect):
    def __init__(self):
        self.graphics_timer = PeriodicTimer(Millis(400))

    def apply_start_effect(self, game_state: GameState,
                           buffed_entity: WorldEntity,
                           buffed_npc: NonPlayerCharacter):
        buffed_entity.add_to_speed_multiplier(-SLOW_AMOUNT)

    def apply_end_effect(self, game_state: GameState,
                         buffed_entity: WorldEntity,
                         buffed_npc: NonPlayerCharacter):
        buffed_entity.add_to_speed_multiplier(SLOW_AMOUNT)

    def apply_middle_effect(self, game_state: GameState,
                            buffed_entity: WorldEntity,
                            buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.graphics_timer.update_and_check_if_ready(time_passed):
            position = buffed_entity.get_center_position()
            visual_effect1 = VisualCircle((0, 40, 100), position, 9, 16,
                                          Millis(400), 2, buffed_entity)
            visual_effect2 = VisualCircle((0, 90, 180), position, 9, 16,
                                          Millis(500), 2, buffed_entity)
            game_state.visual_effects.append(visual_effect1)
            game_state.visual_effects.append(visual_effect2)

    def get_buff_type(self):
        return BUFF_TYPE
예제 #11
0
class ItemEffect(AbstractItemEffect):
    def __init__(self):
        self.timer = PeriodicTimer(Millis(5000))

    def apply_middle_effect(self, game_state: GameState, time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            strike_enemies(game_state, 1)
class ItemEffect(AbstractItemEffect):
    def __init__(self, item_type: ItemType):
        super().__init__(item_type)
        self.timer = PeriodicTimer(Millis(5000))
        self.min_dmg = 1
        self.max_dmg = 3

    def apply_middle_effect(self, game_state: GameState, time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            player_entity = game_state.player_entity
            player_center_position = player_entity.get_center_position()
            close_enemies = game_state.get_enemies_within_x_y_distance_of(
                140, player_center_position)
            if close_enemies:
                damage_amount: float = self.min_dmg + random.random() * (
                    self.max_dmg - self.min_dmg)
                deal_player_damage_to_enemy(game_state, close_enemies[0],
                                            damage_amount, DamageType.MAGIC)
                enemy_center_position = close_enemies[
                    0].world_entity.get_center_position()
                game_state.visual_effects.append(
                    VisualCircle((250, 250, 0), player_center_position, 50,
                                 140, Millis(100), 1, player_entity))
                game_state.visual_effects.append(
                    VisualLine((250, 250, 0), player_center_position,
                               enemy_center_position, Millis(80), 3))

    def get_description(self):
        return [
            "Periodically deals " + str(self.min_dmg) + "-" +
            str(self.max_dmg) + " magic damage to nearby enemies"
        ]
예제 #13
0
class ProjectileController(AbstractProjectileController):
    def __init__(self):
        super().__init__(PROJECTILE_DURATION)
        self.damage_timer = PeriodicTimer(PROJECTILE_DAMAGE_INTERVAL)
        self.direction_change_timer = PeriodicTimer(Millis(250))
        self._relative_direction = 0
        self._rotation_motion = random.choice([-1, 1])

    def notify_time_passed(self, game_state: GameState, projectile: Projectile,
                           time_passed: Millis):
        super().notify_time_passed(game_state, projectile, time_passed)
        projectile_entity = projectile.world_entity

        if self.damage_timer.update_and_check_if_ready(time_passed):
            for enemy in game_state.game_world.get_enemy_intersecting_with(
                    projectile_entity):
                damage_amount = 1
                damage_was_dealt = deal_player_damage_to_enemy(
                    game_state, enemy, damage_amount, DamageType.MAGIC)
                if damage_was_dealt:
                    has_stun_upgrade = game_state.player_state.has_upgrade(
                        HeroUpgradeId.ABILITY_WHIRLWIND_STUN)
                    if has_stun_upgrade and random.random() < 0.2:
                        enemy.gain_buff_effect(get_buff_effect(BUFF_TYPE),
                                               WHIRLWIND_TALENT_STUN_DURATION)

        if self.direction_change_timer.update_and_check_if_ready(time_passed):
            should_rotate = True
            # keep going straight ahead sometimes
            if self._relative_direction == 0 and random.random() < 0.5:
                should_rotate = False

            if should_rotate:
                if self._rotation_motion == 1:
                    projectile_entity.rotate_right()
                    self._relative_direction += 90
                elif self._rotation_motion == -1:
                    projectile_entity.rotate_left()
                    self._relative_direction -= 90

                if self._relative_direction == 90:
                    self._rotation_motion = -1
                elif self._relative_direction == -90:
                    self._rotation_motion = 1
예제 #14
0
class BuffedFromElixirOfPower(StatModifyingBuffEffect):
    def __init__(self):
        super().__init__(BUFF_TYPE, {HeroStat.DAMAGE: DAMAGE_MODIFIER_INCREASE})
        self.timer = PeriodicTimer(Millis(300))

    def apply_middle_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            game_state.game_world.visual_effects.append(
                VisualRect((0, 0, 0), game_state.game_world.player_entity.get_center_position(), 6, 18, Millis(200), 3))
예제 #15
0
class IncreasedSpeedAfterDash(StatModifyingBuffEffect):
    def __init__(self):
        super().__init__(BUFF_SPEED, {HeroStat.MOVEMENT_SPEED: 0.4})
        self.timer = PeriodicTimer(Millis(100))

    def apply_middle_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            game_state.visual_effects.append(
                VisualCircle((150, 200, 250), game_state.player_entity.get_center_position(), 5, 10, Millis(200), 0))
예제 #16
0
class ChannelingStomp(AbstractBuffEffect):
    def __init__(self):
        self.timer = PeriodicTimer(Millis(80))
        self.graphics_size = 40

    def apply_start_effect(self, game_state: GameState,
                           buffed_entity: WorldEntity,
                           buffed_npc: NonPlayerCharacter):
        game_state.player_state.stun_status.add_one()
        game_state.game_world.player_entity.set_not_moving()

    def apply_middle_effect(self, game_state: GameState,
                            buffed_entity: WorldEntity,
                            buffed_npc: NonPlayerCharacter,
                            time_passed: Millis) -> bool:
        if self.timer.update_and_check_if_ready(time_passed):
            visual_effect = VisualCircle(
                (250, 250, 250), buffed_entity.get_center_position(),
                self.graphics_size, self.graphics_size + 10, Millis(70), 2,
                None)
            self.graphics_size -= 7
            game_state.game_world.visual_effects.append(visual_effect)
        return False

    def apply_end_effect(self, game_state: GameState,
                         buffed_entity: WorldEntity,
                         buffed_npc: NonPlayerCharacter):
        game_state.player_state.stun_status.remove_one()
        hero_center_pos = game_state.game_world.player_entity.get_center_position(
        )
        distance = 80
        affected_enemies = game_state.game_world.get_enemies_within_x_y_distance_of(
            distance, hero_center_pos)
        game_state.game_world.visual_effects.append(
            VisualRect((50, 50, 50), hero_center_pos, distance * 2,
                       int(distance * 2.1), Millis(200), 2, None))
        game_state.game_world.visual_effects.append(
            VisualRect((150, 150, 0), hero_center_pos, distance, distance * 2,
                       Millis(150), 3, None))
        game_state.game_world.visual_effects.append(
            VisualRect((250, 250, 0), hero_center_pos, distance, distance * 2,
                       Millis(100), 4, None))
        for enemy in affected_enemies:
            damage: float = MIN_DMG + random.random() * (MAX_DMG - MIN_DMG)
            deal_player_damage_to_enemy(game_state, enemy, damage,
                                        DamageType.PHYSICAL)
            enemy.gain_buff_effect(get_buff_effect(STUNNED_BY_STOMP),
                                   STUN_DURATION)
        game_state.player_state.gain_buff_effect(
            get_buff_effect(BuffType.RECOVERING_AFTER_ABILITY), Millis(300))
        play_sound(SoundId.ABILITY_STOMP_HIT)
        game_state.camera_shake = CameraShake(Millis(50), Millis(200), 12)

    def get_buff_type(self):
        return CHANNELING_STOMP
예제 #17
0
class ProtectedByStoneAmulet(StatModifyingBuffEffect):

    def __init__(self):
        super().__init__(BUFF_TYPE, {HeroStat.ARMOR: ARMOR_BONUS})
        self.timer = PeriodicTimer(Millis(300))

    def apply_middle_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            game_state.visual_effects.append(
                VisualCircle((130, 100, 60), buffed_entity.get_center_position(), 20, 40, Millis(100), 1,
                             buffed_entity))
예제 #18
0
class NpcMind(AbstractNpcMind):
    def __init__(self, global_path_finder: GlobalPathFinder):
        super().__init__(global_path_finder)
        self.timer = PeriodicTimer(Millis(500))

    def control_npc(self, game_state: GameState, npc: NonPlayerCharacter, player_entity: WorldEntity,
                    is_player_invisible: bool, time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            if random.random() < 0.8:
                npc.world_entity.set_not_moving()
            else:
                direction = random.choice(get_all_directions())
                npc.world_entity.set_moving_in_dir(direction)
예제 #19
0
class RestoringHealthFromBrew(AbstractBuffEffect):
    def __init__(self):
        self.timer = PeriodicTimer(Millis(600))

    def apply_middle_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            player_receive_healing(3, game_state)
            player_receive_mana(3, game_state)

    def get_buff_type(self):
        return BUFF_TYPE

    def buff_handle_event(self, event: Event) -> Optional[BuffEventOutcome]:
        if isinstance(event, PlayerLostHealthEvent):
            return BuffEventOutcome.cancel_effect()
예제 #20
0
class BuffEffect(AbstractBuffEffect):
    def __init__(self):
        self._timer = PeriodicTimer(DEBUFF_DAMAGE_INTERVAL)

    def apply_middle_effect(self, game_state: GameState,
                            buffed_entity: WorldEntity,
                            buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self._timer.update_and_check_if_ready(time_passed):
            deal_player_damage_to_enemy(game_state, buffed_npc, DAMAGE,
                                        DamageType.MAGIC)
            pos = buffed_entity.get_center_position()
            effect = VisualCircle((100, 150, 100), pos, 40, 50, Millis(500), 1)
            game_state.game_world.visual_effects += [effect]

    def get_buff_type(self):
        return BUFF_TYPE
예제 #21
0
class BuffEffect(AbstractBuffEffect):
    def __init__(self):
        self.timer = PeriodicTimer(DAMAGE_INTERVAL)

    def apply_middle_effect(self, game_state: GameState,
                            buffed_entity: WorldEntity,
                            buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            deal_player_damage_to_enemy(game_state,
                                        buffed_npc,
                                        DAMAGE,
                                        DamageType.PHYSICAL,
                                        damage_source=DAMAGE_SOURCE)

    def get_buff_type(self):
        return BUFF_TYPE
예제 #22
0
class BurntByFireball(AbstractBuffEffect):
    def __init__(self):
        self.timer = PeriodicTimer(FIREBALL_TALENT_BURN_INTERVAL)

    def apply_middle_effect(self, game_state: GameState,
                            buffed_entity: WorldEntity,
                            buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            deal_player_damage_to_enemy(game_state, buffed_npc, 1,
                                        DamageType.MAGIC)
            game_state.visual_effects.append(
                VisualCircle((180, 50, 50),
                             buffed_npc.world_entity.get_center_position(), 10,
                             20, Millis(50), 0, buffed_entity))

    def get_buff_type(self):
        return BUFF_TYPE
예제 #23
0
class AfterStealthing(AbstractBuffEffect):
    def __init__(self):
        self.timer = PeriodicTimer(Millis(160))

    def apply_middle_effect(self, game_state: GameState,
                            buffed_entity: WorldEntity,
                            buffed_npc: NonPlayerCharacter,
                            time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            visual_effect = VisualCircle((250, 150, 250),
                                         buffed_entity.get_center_position(),
                                         18, 25, Millis(220), 1, buffed_entity)
            game_state.visual_effects.append(visual_effect)

    def apply_end_effect(self, game_state: GameState,
                         buffed_entity: WorldEntity,
                         buffed_npc: NonPlayerCharacter):
        game_state.player_state.modify_stat(HeroStat.DODGE_CHANCE,
                                            -DODGE_CHANCE_BONUS)

    def get_buff_type(self):
        return BUFF_POST_STEALTH
예제 #24
0
class ItemEffect(AbstractItemEffect):
    def __init__(self):
        self.timer = PeriodicTimer(Millis(5000))

    def apply_middle_effect(self, game_state: GameState, time_passed: Millis):
        if self.timer.update_and_check_if_ready(time_passed):
            player_entity = game_state.player_entity
            player_center_position = player_entity.get_center_position()
            close_enemies = game_state.get_enemies_within_x_y_distance_of(
                140, player_center_position)
            if close_enemies:
                damage_amount: float = MIN_DMG + random.random() * (MAX_DMG -
                                                                    MIN_DMG)
                deal_player_damage_to_enemy(game_state, close_enemies[0],
                                            damage_amount, DamageType.MAGIC)
                enemy_center_position = close_enemies[
                    0].world_entity.get_center_position()
                game_state.visual_effects.append(
                    VisualCircle((250, 250, 0), player_center_position, 50,
                                 140, Millis(100), 1, player_entity))
                game_state.visual_effects.append(
                    VisualLine((250, 250, 0), player_center_position,
                               enemy_center_position, Millis(80), 3))
예제 #25
0
def main(map_file_name: Optional[str]):
    map_file_path = MAP_DIR + (map_file_name or "map1.json")

    if Path(map_file_path).exists():
        game_state = create_game_state_from_json_file(CAMERA_SIZE,
                                                      map_file_path, HERO_ID)
    else:
        player_entity = create_hero_world_entity(HERO_ID, (0, 0))
        player_state = create_player_state(HERO_ID)
        game_state = GameState(player_entity, [], [], [], [], [], CAMERA_SIZE,
                               Rect(-250, -250, 500, 500), player_state, [],
                               [], [])

    pygame.init()

    pygame_screen = pygame.display.set_mode(SCREEN_SIZE)
    images_by_sprite = load_images_by_sprite(ENTITY_SPRITE_INITIALIZERS)
    images_by_ui_sprite = load_images_by_ui_sprite(UI_ICON_SPRITE_PATHS,
                                                   MAP_EDITOR_UI_ICON_SIZE)
    images_by_portrait_sprite = load_images_by_portrait_sprite(
        PORTRAIT_ICON_SPRITE_PATHS, PORTRAIT_ICON_SIZE)
    world_view = GameWorldView(pygame_screen, CAMERA_SIZE, SCREEN_SIZE,
                               images_by_sprite)
    ui_view = MapEditorView(pygame_screen, CAMERA_SIZE, SCREEN_SIZE,
                            images_by_sprite, images_by_ui_sprite,
                            images_by_portrait_sprite)

    user_state = UserState.deleting_entities()

    is_mouse_button_down = False

    possible_grid_cell_sizes = [25, 50]
    grid_cell_size_index = 0
    grid_cell_size = possible_grid_cell_sizes[grid_cell_size_index]

    camera_move_distance = 75  # must be a multiple of the grid size
    snapped_mouse_screen_position = (0, 0)
    snapped_mouse_world_position = (0, 0)
    exact_mouse_screen_position = (0, 0)
    is_snapped_mouse_within_world = True
    is_snapped_mouse_over_ui = False

    game_state.center_camera_on_player()
    game_state.camera_world_area.topleft = (
        (game_state.camera_world_area.x // grid_cell_size) * grid_cell_size,
        (game_state.camera_world_area.y // grid_cell_size) * grid_cell_size)

    held_down_arrow_keys = set([])
    clock = pygame.time.Clock()
    camera_pan_timer = PeriodicTimer(Millis(50))

    shown_tab = EntityTab.ITEMS

    while True:

        for event in pygame.event.get():
            if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN
                                             and event.key == pygame.K_ESCAPE):
                pygame.quit()
                sys.exit()

            if event.type == pygame.MOUSEMOTION:
                exact_mouse_screen_position: Tuple[int, int] = event.pos
                ui_view.handle_mouse_movement(exact_mouse_screen_position)
                snapped_mouse_screen_position = (
                    (exact_mouse_screen_position[0] // grid_cell_size) *
                    grid_cell_size,
                    (exact_mouse_screen_position[1] // grid_cell_size) *
                    grid_cell_size)
                snapped_mouse_world_position = sum_of_vectors(
                    snapped_mouse_screen_position,
                    game_state.camera_world_area.topleft)
                is_snapped_mouse_within_world = game_state.is_position_within_game_world(
                    snapped_mouse_world_position)
                is_snapped_mouse_over_ui = ui_view.is_screen_position_within_ui(
                    snapped_mouse_screen_position)
                if is_mouse_button_down and is_snapped_mouse_within_world and not is_snapped_mouse_over_ui:
                    if user_state.placing_entity:
                        if user_state.placing_entity.wall_type:
                            _add_wall(game_state, snapped_mouse_world_position,
                                      user_state.placing_entity.wall_type)
                        elif user_state.placing_entity.decoration_sprite:
                            _add_decoration(
                                user_state.placing_entity.decoration_sprite,
                                game_state, snapped_mouse_world_position)
                    elif user_state.deleting_entities:
                        _delete_map_entities_from_position(
                            game_state, snapped_mouse_world_position)
                    else:
                        _delete_map_decorations_from_position(
                            game_state, snapped_mouse_world_position)

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_s:
                    save_file = map_file_path
                    save_game_state_to_json_file(game_state, save_file)
                    print("Saved state to " + save_file)
                elif event.key in [
                        pygame.K_RIGHT, pygame.K_DOWN, pygame.K_LEFT,
                        pygame.K_UP
                ]:
                    held_down_arrow_keys.add(event.key)
                elif event.key == pygame.K_q:
                    user_state = UserState.deleting_entities()
                elif event.key == pygame.K_z:
                    user_state = UserState.deleting_decorations()
                elif event.key == pygame.K_PLUS:
                    grid_cell_size_index = (grid_cell_size_index +
                                            1) % len(possible_grid_cell_sizes)
                    grid_cell_size = possible_grid_cell_sizes[
                        grid_cell_size_index]
                elif event.key == pygame.K_v:
                    shown_tab = EntityTab.ITEMS
                elif event.key == pygame.K_b:
                    shown_tab = EntityTab.NPCS
                elif event.key == pygame.K_n:
                    shown_tab = EntityTab.WALLS
                elif event.key == pygame.K_m:
                    shown_tab = EntityTab.MISC

            if event.type == pygame.KEYUP:
                if event.key in held_down_arrow_keys:
                    held_down_arrow_keys.remove(event.key)

            if event.type == pygame.MOUSEBUTTONDOWN:
                ui_view.handle_mouse_click()
                is_mouse_button_down = True
                if user_state.placing_entity:
                    entity_being_placed = user_state.placing_entity
                    if is_snapped_mouse_within_world and not is_snapped_mouse_over_ui:
                        if entity_being_placed.is_player:
                            game_state.player_entity.set_position(
                                snapped_mouse_world_position)
                        elif entity_being_placed.npc_type:
                            _add_npc(entity_being_placed.npc_type, game_state,
                                     snapped_mouse_world_position)
                        elif entity_being_placed.wall_type:
                            _add_wall(game_state, snapped_mouse_world_position,
                                      entity_being_placed.wall_type)
                        elif entity_being_placed.consumable_type:
                            _add_consumable(
                                entity_being_placed.consumable_type,
                                game_state, snapped_mouse_world_position)
                        elif entity_being_placed.item_type:
                            _add_item(entity_being_placed.item_type,
                                      game_state, snapped_mouse_world_position)
                        elif entity_being_placed.decoration_sprite:
                            _add_decoration(
                                entity_being_placed.decoration_sprite,
                                game_state, snapped_mouse_world_position)
                        elif entity_being_placed.money_amount:
                            _add_money(entity_being_placed.money_amount,
                                       game_state,
                                       snapped_mouse_world_position)
                        elif entity_being_placed.portal_id:
                            _add_portal(entity_being_placed.portal_id,
                                        game_state,
                                        snapped_mouse_world_position)
                        elif entity_being_placed.is_chest:
                            _add_chest(game_state,
                                       snapped_mouse_world_position)
                        else:
                            raise Exception("Unknown entity: " +
                                            str(entity_being_placed))
                elif user_state.deleting_entities:
                    _delete_map_entities_from_position(
                        game_state, snapped_mouse_world_position)
                else:
                    _delete_map_decorations_from_position(
                        game_state, snapped_mouse_world_position)

            if event.type == pygame.MOUSEBUTTONUP:
                is_mouse_button_down = False

        clock.tick()
        time_passed = clock.get_time()

        if camera_pan_timer.update_and_check_if_ready(time_passed):
            if pygame.K_RIGHT in held_down_arrow_keys:
                game_state.translate_camera_position((camera_move_distance, 0))
            if pygame.K_LEFT in held_down_arrow_keys:
                game_state.translate_camera_position(
                    (-camera_move_distance, 0))
            if pygame.K_DOWN in held_down_arrow_keys:
                game_state.translate_camera_position((0, camera_move_distance))
            if pygame.K_UP in held_down_arrow_keys:
                game_state.translate_camera_position(
                    (0, -camera_move_distance))

        entities_to_render = game_state.get_all_entities_to_render()
        decorations_to_render = game_state.get_decorations_to_render()
        world_view.render_world(
            all_entities_to_render=entities_to_render,
            decorations_to_render=decorations_to_render,
            player_entity=game_state.player_entity,
            is_player_invisible=game_state.player_state.is_invisible,
            player_active_buffs=game_state.player_state.active_buffs,
            camera_world_area=game_state.camera_world_area,
            non_player_characters=game_state.non_player_characters,
            visual_effects=game_state.visual_effects,
            render_hit_and_collision_boxes=ui_view.
            checkbox_show_entity_outlines.checked,
            player_health=game_state.player_state.health_resource.value,
            player_max_health=game_state.player_state.health_resource.
            max_value,
            entire_world_area=game_state.entire_world_area,
            entity_action_text=None)

        camera_world_area = game_state.camera_world_area
        world_area = game_state.entire_world_area
        camera_rect_ratio = ((camera_world_area.x - world_area.x) /
                             world_area.w,
                             (camera_world_area.y - world_area.y) /
                             world_area.h, camera_world_area.w / world_area.w,
                             camera_world_area.h / world_area.h)

        npc_positions_ratio = [
            ((npc.world_entity.x - world_area.x) / world_area.w,
             (npc.world_entity.y - world_area.y) / world_area.h)
            for npc in game_state.non_player_characters
        ]
        wall_positions_ratio = [
            ((wall.world_entity.x - world_area.x) / world_area.w,
             (wall.world_entity.y - world_area.y) / world_area.h)
            for wall in game_state.walls_state.walls
        ]

        if shown_tab == EntityTab.ITEMS:
            shown_entities = ITEM_ENTITIES
        elif shown_tab == EntityTab.NPCS:
            shown_entities = NPC_ENTITIES
        elif shown_tab == EntityTab.WALLS:
            shown_entities = WALL_ENTITIES
        elif shown_tab == EntityTab.MISC:
            shown_entities = MISC_ENTITIES
        else:
            raise Exception("Unknown entity tab: " + str(shown_tab))

        ui_view.set_shown_tab(shown_tab)

        entity_icon_hovered_by_mouse = ui_view.render(
            entities=shown_entities,
            placing_entity=user_state.placing_entity,
            deleting_entities=user_state.deleting_entities,
            deleting_decorations=user_state.deleting_decorations,
            num_enemies=len(game_state.non_player_characters),
            num_walls=len(game_state.walls_state.walls),
            num_decorations=len(
                game_state.decorations_state.decoration_entities),
            grid_cell_size=grid_cell_size,
            mouse_screen_position=exact_mouse_screen_position,
            camera_rect_ratio=camera_rect_ratio,
            npc_positions_ratio=npc_positions_ratio,
            wall_positions_ratio=wall_positions_ratio)

        if is_mouse_button_down and entity_icon_hovered_by_mouse:
            user_state = UserState.placing_entity(entity_icon_hovered_by_mouse)

        if is_snapped_mouse_over_ui:
            pass
            # render nothing over UI
        elif not is_snapped_mouse_within_world:
            snapped_mouse_rect = Rect(snapped_mouse_screen_position[0],
                                      snapped_mouse_screen_position[1],
                                      grid_cell_size, grid_cell_size)
            ui_view.render_map_editor_mouse_rect((250, 50, 0),
                                                 snapped_mouse_rect)
        elif user_state.placing_entity:
            entity_being_placed = user_state.placing_entity
            ui_view.render_map_editor_world_entity_at_position(
                entity_being_placed.sprite, entity_being_placed.entity_size,
                snapped_mouse_screen_position)
        elif user_state.deleting_entities:
            snapped_mouse_rect = Rect(snapped_mouse_screen_position[0],
                                      snapped_mouse_screen_position[1],
                                      grid_cell_size, grid_cell_size)
            ui_view.render_map_editor_mouse_rect((250, 250, 0),
                                                 snapped_mouse_rect)
        elif user_state.deleting_decorations:
            snapped_mouse_rect = Rect(snapped_mouse_screen_position[0],
                                      snapped_mouse_screen_position[1],
                                      grid_cell_size, grid_cell_size)
            ui_view.render_map_editor_mouse_rect((0, 250, 250),
                                                 snapped_mouse_rect)
        else:
            raise Exception("Unhandled user_state: " + str(user_state))

        pygame.display.update()
예제 #26
0
class Charging(AbstractBuffEffect):

    def __init__(self):
        self.graphics_timer = PeriodicTimer(Millis(40))
        self.time_since_start = 0

    def apply_start_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter):
        game_state.player_state.stun_status.add_one()
        game_state.modify_hero_stat(HeroStat.MOVEMENT_SPEED, BONUS_SPEED_MULTIPLIER)
        game_state.player_entity.set_moving_in_dir(game_state.player_entity.direction)

    def apply_middle_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter,
                            time_passed: Millis) -> Optional[bool]:

        self.time_since_start += time_passed

        charger_center_pos = buffed_entity.get_center_position()

        if self.graphics_timer.update_and_check_if_ready(time_passed):
            visual_circle = VisualCircle((250, 250, 250), charger_center_pos, 15, 25, Millis(120), 2, None)
            game_state.visual_effects.append(visual_circle)

        rect_w = 32
        # NOTE: We assume that this ability is used by this specific hero
        hero_entity_size = HEROES[HeroId.WARRIOR].entity_size
        impact_pos = translate_in_direction(
            charger_center_pos, buffed_entity.direction, rect_w / 2 + hero_entity_size[0] / 2)

        impact_rect = Rect(int(impact_pos[0] - rect_w / 2), int(impact_pos[1] - rect_w / 2), rect_w, rect_w)
        affected_enemies = game_state.get_enemy_intersecting_rect(impact_rect)
        for enemy in affected_enemies:
            visual_impact_pos = get_middle_point(charger_center_pos, enemy.world_entity.get_center_position())
            damage = MIN_DMG
            # Talent: Apply damage bonus even if using charge in melee range
            has_melee_upgrade = game_state.player_state.has_upgrade(HeroUpgradeId.ABILITY_CHARGE_MELEE)
            damage_increased = self.time_since_start > float(CHARGE_DURATION) * 0.3 or has_melee_upgrade
            if damage_increased:
                # TODO Stun target as a bonus here
                damage = MAX_DMG
            deal_player_damage_to_enemy(game_state, enemy, damage, DamageType.PHYSICAL,
                                        visual_emphasis=damage_increased)
            game_state.visual_effects.append(
                VisualRect((250, 170, 0), visual_impact_pos, 45, 25, IMPACT_STUN_DURATION, 2, None))
            game_state.visual_effects.append(
                VisualRect((150, 0, 0), visual_impact_pos, 35, 20, IMPACT_STUN_DURATION, 2, None))
            game_state.player_state.gain_buff_effect(get_buff_effect(BUFF_TYPE_STUNNED), IMPACT_STUN_DURATION)
            enemy.gain_buff_effect(get_buff_effect(BUFF_TYPE_STUNNED), IMPACT_STUN_DURATION)
            game_state.camera_shake = CameraShake(Millis(50), Millis(150), 12)
            play_sound(SoundId.ABILITY_CHARGE_HIT)
            has_stomp_cooldown_upgrade = game_state.player_state.has_upgrade(
                HeroUpgradeId.ABILITY_CHARGE_RESET_STOMP_COOLDOWN)
            if has_stomp_cooldown_upgrade:
                game_state.player_state.set_ability_cooldown_to_zero(AbilityType.STOMP)
            # The buff should end upon impact
            return True
        return False

    def apply_end_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter):
        game_state.player_state.stun_status.remove_one()
        game_state.modify_hero_stat(HeroStat.MOVEMENT_SPEED, -BONUS_SPEED_MULTIPLIER)

    def get_buff_type(self):
        return BUFF_TYPE_CHARGING
예제 #27
0
    def __init__(self, map_file_name: Optional[str]):
        self.map_file_path = MAP_DIR + (map_file_name or "map1.json")

        possible_grid_cell_sizes = [GRID_CELL_SIZE, GRID_CELL_SIZE * 2]
        grid_cell_size_index = 0

        self.grid_cell_size = possible_grid_cell_sizes[grid_cell_size_index]
        self.grid: Grid = None
        self.ui_view: MapEditorView = None
        self.game_state: GameState = None

        if Path(self.map_file_path).exists():
            print("Loading map '%s' from file." % self.map_file_path)
            map_data = load_map_from_json_file(self.map_file_path)
            player_position = map_data.player_position
            self._set_game_world(map_data.game_world, player_position)
            self.config = map_data.map_editor_config
            if map_data.grid_string:
                print("Initializing grid from existing map data.")
                self.grid = Grid.deserialize(map_data.grid_string)
            else:
                if not self.config.disable_smart_grid:
                    print(
                        "Grid missing from existing map data. Generating one from world state ..."
                    )
                    self.build_grid_from_game_state()
                else:
                    print(
                        "Grid disabled for this map. Using smart floor tiles will not work."
                    )
        else:
            print("Map file '%s' not found! New map is created." %
                  self.map_file_path)
            player_position = (0, 0)
            game_world = GameWorldState(
                player_entity=None,
                consumables_on_ground=[],
                items_on_ground=[],
                money_piles_on_ground=[],
                non_player_characters=[],
                walls=[],
                entire_world_area=Rect(-250, -250, 1500, 1000),
                decoration_entities=[],
                portals=[],
                chests=[],
                shrines=[],
                dungeon_entrances=[],
            )
            self._set_game_world(game_world, player_position)
            self.config = MapEditorConfig(disable_smart_grid=False)
            grid_size = (self.game_state.game_world.entire_world_area.w //
                         GRID_CELL_SIZE,
                         self.game_state.game_world.entire_world_area.h //
                         GRID_CELL_SIZE)
            self.grid = Grid.create_from_rects(grid_size, [])

        pygame.init()

        pygame_screen = pygame.display.set_mode(SCREEN_SIZE)
        images_by_sprite = load_images_by_sprite(ENTITY_SPRITE_INITIALIZERS)
        images_by_ui_sprite = load_images_by_ui_sprite(
            UI_ICON_SPRITE_PATHS, MAP_EDITOR_UI_ICON_SIZE)
        images_by_portrait_sprite = load_images_by_portrait_sprite(
            PORTRAIT_ICON_SPRITE_PATHS, PORTRAIT_ICON_SIZE)
        world_view = GameWorldView(pygame_screen, CAMERA_SIZE, SCREEN_SIZE,
                                   images_by_sprite)

        self.render_outlines = False

        self.ui_view = MapEditorView(
            pygame_screen, self.game_state.camera_world_area, SCREEN_SIZE,
            images_by_sprite, images_by_ui_sprite, images_by_portrait_sprite,
            self.game_state.game_world.entire_world_area,
            self.game_state.game_world.player_entity.get_center_position(),
            ENTITIES_BY_TYPE, self.grid_cell_size, self.map_file_path)
        self._notify_ui_of_new_wall_positions()

        camera_move_distance = 75  # must be a multiple of the grid size

        held_down_arrow_keys = set([])
        clock = pygame.time.Clock()
        camera_pan_timer = PeriodicTimer(Millis(50))

        while True:

            # HANDLE USER INPUT

            for event in pygame.event.get():
                if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN
                                                 and event.key
                                                 == pygame.K_ESCAPE):
                    pygame.quit()
                    sys.exit()

                if event.type == pygame.MOUSEMOTION:
                    action = self.ui_view.handle_mouse_movement(event.pos)
                    if action:
                        self._handle_action(action, self.grid_cell_size)

                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_s:
                        self.save()
                    elif event.key in [
                            pygame.K_RIGHT, pygame.K_DOWN, pygame.K_LEFT,
                            pygame.K_UP
                    ]:
                        held_down_arrow_keys.add(event.key)
                    elif event.key == pygame.K_PLUS:
                        grid_cell_size_index = (
                            grid_cell_size_index +
                            1) % len(possible_grid_cell_sizes)
                        grid_cell_size = possible_grid_cell_sizes[
                            grid_cell_size_index]
                        self.ui_view.grid_cell_size = grid_cell_size
                    else:
                        self.ui_view.handle_key_down(event.key)

                if event.type == pygame.KEYUP:
                    if event.key in held_down_arrow_keys:
                        held_down_arrow_keys.remove(event.key)

                if event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == PYGAME_MOUSE_LEFT_BUTTON:
                        action = self.ui_view.handle_mouse_left_click()
                    elif event.button == PYGAME_MOUSE_RIGHT_BUTTON:
                        action = self.ui_view.handle_mouse_right_click()
                    else:
                        action = None
                    if action:
                        self._handle_action(action, self.grid_cell_size)

                elif event.type == pygame.MOUSEBUTTONUP:
                    if event.button == PYGAME_MOUSE_LEFT_BUTTON:
                        action = self.ui_view.handle_mouse_left_release()
                    elif event.button == PYGAME_MOUSE_RIGHT_BUTTON:
                        action = self.ui_view.handle_mouse_right_release()
                    else:
                        action = None
                    if action:
                        self._handle_action(action, self.grid_cell_size)

            # HANDLE TIME

            clock.tick()
            time_passed = clock.get_time()

            if camera_pan_timer.update_and_check_if_ready(time_passed):
                if pygame.K_RIGHT in held_down_arrow_keys:
                    self.game_state.translate_camera_position(
                        (camera_move_distance, 0))
                if pygame.K_LEFT in held_down_arrow_keys:
                    self.game_state.translate_camera_position(
                        (-camera_move_distance, 0))
                if pygame.K_DOWN in held_down_arrow_keys:
                    self.game_state.translate_camera_position(
                        (0, camera_move_distance))
                if pygame.K_UP in held_down_arrow_keys:
                    self.game_state.translate_camera_position(
                        (0, -camera_move_distance))

            self.ui_view.camera_world_area = self.game_state.camera_world_area
            self.ui_view.world_area = self.game_state.game_world.entire_world_area

            # RENDER

            world_view.render_world(
                all_entities_to_render=self.game_state.
                get_all_entities_to_render(),
                decorations_to_render=self.game_state.
                get_decorations_to_render(),
                player_entity=self.game_state.game_world.player_entity,
                is_player_invisible=self.game_state.player_state.is_invisible,
                player_active_buffs=self.game_state.player_state.active_buffs,
                camera_world_area=self.game_state.camera_world_area,
                non_player_characters=self.game_state.game_world.
                non_player_characters,
                visual_effects=self.game_state.game_world.visual_effects,
                render_hit_and_collision_boxes=self.render_outlines,
                player_health=self.game_state.player_state.health_resource.
                value,
                player_max_health=self.game_state.player_state.health_resource.
                max_value,
                entire_world_area=self.game_state.game_world.entire_world_area,
                entity_action_text=None)

            npc_positions = [
                npc.world_entity.get_position()
                for npc in self.game_state.game_world.non_player_characters
            ]

            named_portal_positions = {
                p.world_entity.get_position(): p.portal_id.name
                for p in self.game_state.game_world.portals
            }
            named_npc_positions = {
                npc.world_entity.get_position(): npc.npc_type.name
                for npc in self.game_state.game_world.non_player_characters
            }
            named_world_positions = {
                **named_portal_positions,
                **named_npc_positions
            }

            fps_string = str(int(clock.get_fps()))
            self.ui_view.render(
                num_enemies=len(
                    self.game_state.game_world.non_player_characters),
                num_walls=len(self.game_state.game_world.walls_state.walls),
                num_decorations=len(self.game_state.game_world.
                                    decorations_state.decoration_entities),
                npc_positions=npc_positions,
                player_position=self.game_state.game_world.player_entity.
                get_center_position(),
                grid=self.grid,
                named_world_positions=named_world_positions,
                fps_string=fps_string)

            pygame.display.flip()