示例#1
0
 def apply_start_effect(self, game_state: GameState,
                        buffed_entity: WorldEntity,
                        buffed_npc: NonPlayerCharacter):
     buffed_npc.stun_status.add_one()
     buffed_entity.set_not_moving()
     game_state.game_world.visual_effects.append(
         create_visual_stun_text(buffed_entity))
示例#2
0
def create_item_on_ground(item_id: ItemId, pos: Tuple[int,
                                                      int]) -> ItemOnGround:
    item_type = item_id.item_type
    entity = WorldEntity(pos, ITEM_ENTITY_SIZE,
                         get_item_data_by_type(item_type).entity_sprite)
    entity.view_z = 1  # It should be rendered below all other entities
    return ItemOnGround(entity, item_id)
示例#3
0
 def apply_start_effect(self, game_state: GameState,
                        buffed_entity: WorldEntity,
                        buffed_npc: NonPlayerCharacter):
     if buffed_npc:
         buffed_npc.stun_status.add_one()
     else:
         game_state.player_state.stun_status.add_one()
     buffed_entity.set_not_moving()
示例#4
0
 def apply_start_effect(self, game_state: GameState,
                        buffed_entity: WorldEntity,
                        buffed_npc: NonPlayerCharacter):
     buffed_npc.stun_status.add_one()
     buffed_entity.set_not_moving()
     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))
     game_state.game_world.visual_effects.append(
         create_visual_stun_text(buffed_entity))
示例#5
0
    def control_npc(self, game_state: GameState, npc: NonPlayerCharacter,
                    player_entity: WorldEntity, _is_player_invisible: bool,
                    time_passed: Millis):
        if npc.stun_status.is_stunned():
            return

        self._summon_trait.update(npc, game_state, time_passed)
        self._random_walk_trait.update(npc, game_state, time_passed)

        self._time_since_healing += time_passed
        self._time_since_shoot += time_passed

        if self._time_since_healing > self._healing_cooldown:
            self._time_since_healing = 0
            self._healing_cooldown = self._random_healing_cooldown()
            necro_center_pos = npc.world_entity.get_center_position()
            nearby_hurt_enemies = [
                e for e in game_state.game_world.non_player_characters
                if e.is_enemy and is_x_and_y_within_distance(
                    necro_center_pos, e.world_entity.get_center_position(),
                    200) and e != npc and not e.health_resource.is_at_max()
            ]
            if nearby_hurt_enemies:
                healing_target = nearby_hurt_enemies[0]
                healing_target.health_resource.gain(5)
                healing_target_pos = healing_target.world_entity.get_center_position(
                )
                visual_line = VisualLine((80, 200, 150), necro_center_pos,
                                         healing_target_pos, Millis(350), 3)
                game_state.game_world.visual_effects.append(visual_line)
                play_sound(SoundId.ENEMY_NECROMANCER_HEAL)

        if self._time_since_shoot > self._shoot_cooldown:
            self._time_since_shoot = 0
            self._shoot_cooldown = self._random_shoot_cooldown()
            npc.world_entity.direction = get_directions_to_position(
                npc.world_entity, player_entity.get_position())[0]
            npc.world_entity.set_not_moving()
            center_position = npc.world_entity.get_center_position()
            distance_from_enemy = 35
            projectile_pos = translate_in_direction(
                get_position_from_center_position(center_position,
                                                  PROJECTILE_SIZE),
                npc.world_entity.direction, distance_from_enemy)
            projectile_speed = 0.2
            projectile_entity = WorldEntity(projectile_pos, PROJECTILE_SIZE,
                                            Sprite.NONE,
                                            npc.world_entity.direction,
                                            projectile_speed)
            projectile = Projectile(
                projectile_entity,
                create_projectile_controller(PROJECTILE_TYPE))
            game_state.game_world.projectile_entities.append(projectile)
            play_sound(SoundId.ENEMY_ATTACK_NECRO)
示例#6
0
 def apply_start_effect(self, game_state: GameState,
                        buffed_entity: WorldEntity,
                        buffed_npc: NonPlayerCharacter):
     visual_effect = VisualCircle((220, 220, 50),
                                  buffed_entity.get_center_position(), 9,
                                  16, Millis(250), 2)
     game_state.game_world.visual_effects.append(visual_effect)
     game_state.game_world.visual_effects.append(
         create_visual_stun_text(buffed_entity))
     buffed_npc.stun_status.add_one()
     buffed_entity.set_not_moving()
示例#7
0
 def update_world_entity_position_within_game_world(self,
                                                    entity: WorldEntity,
                                                    time_passed: Millis):
     new_position = entity.get_new_position_according_to_dir_and_speed(
         time_passed)
     if new_position:
         new_pos_within_world = self.get_within_world(
             new_position, (entity.pygame_collision_rect.w,
                            entity.pygame_collision_rect.h))
         if not self.would_entity_collide_if_new_pos(
                 entity, new_pos_within_world):
             entity.set_position(new_pos_within_world)
 def apply_middle_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter,
                         time_passed: Millis):
     self._time_since_graphics += time_passed
     if self._time_since_graphics > 800:
         game_state.game_world.visual_effects.append(
             VisualRect((0, 100, 200), buffed_entity.get_center_position(), 50, 50, Millis(400), 1, buffed_entity))
         self._time_since_graphics = 0
示例#9
0
 def apply_middle_effect(self, game_state: GameState, buffed_entity: WorldEntity, buffed_npc: NonPlayerCharacter,
                         time_passed: Millis):
     self.time_since_start += time_passed
     if not self.has_spawn_happened and self.time_since_start > DELAY / 2:
         self.has_spawn_happened = True
         game_state.game_world.visual_effects += create_teleport_effects(buffed_entity.get_center_position())
         play_sound(SoundId.ABILITY_TELEPORT)
示例#10
0
 def __init__(self,
              npc_type: NpcType,
              world_entity: WorldEntity,
              health_resource: HealthOrManaResource,
              npc_mind,
              npc_category: NpcCategory,
              enemy_loot_table: Optional[LootTableId],
              death_sound_id: Optional[SoundId],
              max_distance_allowed_from_start_position: Optional[int],
              is_boss: bool = False):
     self.npc_type = npc_type
     self.world_entity = world_entity
     self.health_resource = health_resource
     self.npc_mind = npc_mind
     self.active_buffs: List[BuffWithDuration] = []
     self.invulnerable: bool = False
     self.stun_status = StunStatus()
     self.npc_category = npc_category
     self.is_enemy = npc_category == NpcCategory.ENEMY
     self.is_neutral = npc_category == NpcCategory.NEUTRAL
     self.enemy_loot_table = enemy_loot_table
     self.death_sound_id = death_sound_id
     self.start_position = world_entity.get_position(
     )  # Only for neutral NPC
     self.max_distance_allowed_from_start_position = max_distance_allowed_from_start_position  # Only for neutral NPC
     self.is_boss: bool = is_boss
     self.quest_giver_state: Optional[
         QuestGiverState] = None  # Only for neutral NPC
示例#11
0
    def get_next_waypoint_along_path(self, agent_entity: WorldEntity) -> Optional[Tuple[int, int]]:
        if self.path:
            # -----------------------------------------------
            # 1: Remove first waypoint if close enough to it
            # -----------------------------------------------
            # TODO: Does this cause problems for specific entity sizes / movement speeds?
            closeness_margin = 50
            if is_x_and_y_within_distance(agent_entity.get_position(), self.path[0], closeness_margin):
                # print("Popping " + str(self.path[0]) + " as I'm so close to it.")
                self.path.pop(0)
                if self.path:
                    # print("After popping, returning " + str(self.path[0]))
                    return self.path[0]
                else:
                    # print("no path after popping. stopping.")
                    return None

            # -----------------------------------------------
            # 2: Remove first waypoint if it's opposite direction of second waypoint
            # -----------------------------------------------
            if len(self.path) >= 2:
                dir_to_waypoint_0 = get_directions_to_position(agent_entity, self.path[0])[0]
                dir_to_waypoint_1 = get_directions_to_position(agent_entity, self.path[1])[0]
                if dir_to_waypoint_0 == get_opposite_direction(dir_to_waypoint_1):
                    # print("Not gonna go back. Popping " + str(self.path[0]))
                    self.path.pop(0)
                    # print("Popped first position. Next waypoint: " + str(self.path[0]))
                    return self.path[0]
                if self.path:
                    return self.path[0]
        else:
            # print("no path found. stopping.")
            return None
        # print("Leaked through. returning none")
        return None
示例#12
0
def _would_collide_with_dir(direction: Direction, agent_entity: WorldEntity, game_state: GameState):
    # TODO Is this too naive to work?
    future_time = Millis(100)
    future_pos = agent_entity.get_new_position_according_to_other_dir_and_speed(direction, future_time)
    future_pos_within_world = game_state.game_world.get_within_world(
        future_pos, (agent_entity.pygame_collision_rect.w, agent_entity.pygame_collision_rect.h))
    would_collide = game_state.game_world.would_entity_collide_if_new_pos(agent_entity, future_pos_within_world)
    return would_collide
 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.game_world.visual_effects.append(visual_effect1)
         game_state.game_world.visual_effects.append(visual_effect2)
示例#14
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.game_world.player_entity.set_not_moving()
     game_state.game_world.player_entity.visible = False
     game_state.game_world.visual_effects += create_teleport_effects(
         buffed_entity.get_center_position())
示例#15
0
 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]
示例#16
0
 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, TICK_DMG, 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.game_world.visual_effects.append(visual_effect1)
         game_state.game_world.visual_effects.append(visual_effect2)
示例#17
0
    def update_path_towards_target(self, agent_entity: WorldEntity, game_state: GameState, target_entity: WorldEntity):
        agent_cell = _translate_world_position_to_cell(agent_entity.get_position(),
                                                       game_state.game_world.entire_world_area)
        target_cell = _translate_world_position_to_cell(target_entity.get_position(),
                                                        game_state.game_world.entire_world_area)

        agent_cell_size = (agent_entity.pygame_collision_rect.w // GRID_CELL_WIDTH + 1,
                           agent_entity.pygame_collision_rect.h // GRID_CELL_WIDTH + 1)
        self.global_path_finder.register_entity_size(agent_cell_size)
        path_with_cells = self.global_path_finder.run(agent_cell_size, agent_cell, target_cell)
        if path_with_cells:
            # Note: Cells are expressed in non-negative values (and need to be translated to game world coordinates)
            path = [_translate_cell_to_world_position(cell, game_state.game_world.entire_world_area) for cell in
                    path_with_cells]
            if DEBUG_RENDER_PATHFINDING:
                _add_visual_lines_along_path(game_state, path)
            self.path = path
        else:
            self.path = None
示例#18
0
def create_money_pile_on_ground(amount: int,
                                pos: Tuple[int, int]) -> MoneyPileOnGround:
    if amount == 1:
        sprite = Sprite.COINS_1
    elif amount == 2:
        sprite = Sprite.COINS_2
    else:
        sprite = Sprite.COINS_5
    return MoneyPileOnGround(WorldEntity(pos, ITEM_ENTITY_SIZE, sprite),
                             amount)
示例#19
0
    def control_npc(self, game_state: GameState, npc: NonPlayerCharacter, player_entity: WorldEntity,
                    is_player_invisible: bool, time_passed: Millis):
        if npc.stun_status.is_stunned():
            return
        super().control_npc(game_state, npc, player_entity, is_player_invisible, time_passed)

        self._time_since_state_change += time_passed

        if self._state == State.BASE:
            if self._time_since_state_change > NpcMind.STATE_DURATION_BASE:
                self._time_since_state_change -= NpcMind.STATE_DURATION_BASE
                self._state = State.FIRING

                npc.gain_buff_effect(get_buff_effect(BUFF_STUNNED),
                                     Millis(NpcMind.STATE_DURATION_FIRING))
                return
        elif self._state == State.FIRING:
            if self._time_since_state_change > NpcMind.STATE_DURATION_FIRING:
                self._time_since_state_change -= NpcMind.STATE_DURATION_FIRING
                self._state = State.BASE
                return
            self._time_since_fired += time_passed
            if self._time_since_fired > NpcMind.FIRE_COOLDOWN:
                self._time_since_fired -= NpcMind.FIRE_COOLDOWN
                directions_to_player = get_directions_to_position(npc.world_entity, player_entity.get_position())
                new_direction = directions_to_player[0]
                if random.random() < 0.1 and directions_to_player[1] is not None:
                    new_direction = directions_to_player[1]
                npc.world_entity.direction = new_direction
                npc.world_entity.set_not_moving()
                center_position = npc.world_entity.get_center_position()
                distance_from_enemy = 35
                projectile_pos = translate_in_direction(
                    get_position_from_center_position(center_position, PROJECTILE_SIZE),
                    npc.world_entity.direction, distance_from_enemy)
                projectile_speed = 0.3
                projectile_entity = WorldEntity(projectile_pos, PROJECTILE_SIZE, Sprite.NONE,
                                                npc.world_entity.direction, projectile_speed)
                projectile = Projectile(projectile_entity, create_projectile_controller(PROJECTILE_TYPE))
                game_state.game_world.projectile_entities.append(projectile)
                play_sound(SoundId.ENEMY_MAGIC_SKELETON_BOSS)
示例#20
0
def deal_npc_damage(damage_amount: float, damage_type: DamageType,
                    game_state: GameState, attacker_entity: WorldEntity,
                    attacker_npc: NonPlayerCharacter, target: EnemyTarget):
    attacker_position = attacker_entity.get_center_position()
    game_state.game_world.visual_effects.append(
        VisualRect((200, 0, 0), attacker_position, 50, 50, Millis(200), 3,
                   attacker_entity))
    if target.non_enemy_npc:
        deal_npc_damage_to_npc(game_state, target.non_enemy_npc, damage_amount)
    else:
        deal_damage_to_player(game_state, damage_amount, damage_type,
                              attacker_npc)
示例#21
0
 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))
示例#22
0
 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.game_world.visual_effects.append(visual_effect)
示例#23
0
 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
示例#24
0
 def apply_middle_effect(self, game_state: GameState,
                         buffed_entity: WorldEntity,
                         buffed_npc: NonPlayerCharacter,
                         time_passed: Millis):
     self.time_since_start += time_passed
     if not self.has_teleport_happened and self.time_since_start > PORTAL_DELAY / 2:
         self.has_teleport_happened = True
         game_state.game_world.warp_points = []
         game_state.game_world.player_entity.set_position(self.destination)
         game_state.game_world.visual_effects += create_teleport_effects(
             buffed_entity.get_center_position())
         play_sound(SoundId.WARP)
def _apply_ability(game_state: GameState) -> AbilityResult:
    player_entity = game_state.game_world.player_entity
    distance_from_player = 35
    projectile_pos = translate_in_direction(
        get_position_from_center_position(player_entity.get_center_position(), PROJECTILE_SIZE),
        player_entity.direction,
        distance_from_player)
    projectile_speed = 0.2
    entity = WorldEntity(projectile_pos, PROJECTILE_SIZE, PROJECTILE_SPRITE, player_entity.direction,
                         projectile_speed)
    projectile = Projectile(entity, create_projectile_controller(PROJECTILE_TYPE))
    game_state.game_world.projectile_entities.append(projectile)
    effect_position = (projectile_pos[0] + PROJECTILE_SIZE[0] // 2,
                       projectile_pos[1] + PROJECTILE_SIZE[1] // 2)
    game_state.game_world.visual_effects.append(VisualCircle((250, 150, 50), effect_position, 9, 18, Millis(80), 0))
    return AbilityWasUsedSuccessfully()
示例#26
0
def create_npc(npc_type: NpcType, pos: Tuple[int, int]) -> NonPlayerCharacter:
    data: NpcData = NON_PLAYER_CHARACTERS[npc_type]
    entity = WorldEntity(pos, data.size, data.sprite, Direction.LEFT,
                         data.speed)
    # TODO is this global pathfinder a problem for handling dungeons that exist in parallel with the main map?
    global_path_finder = get_global_path_finder()
    npc_mind = create_npc_mind(npc_type, global_path_finder)
    health_resource = HealthOrManaResource(data.max_health, data.health_regen)
    return NonPlayerCharacter(npc_type,
                              entity,
                              health_resource,
                              npc_mind,
                              data.npc_category,
                              data.enemy_loot_table,
                              data.death_sound_id,
                              data.max_distance_allowed_from_start_position,
                              is_boss=data.is_boss)
示例#27
0
def get_target(agent_entity: WorldEntity,
               game_state: GameState) -> EnemyTarget:
    # Enemies should prioritize attacking a summon over attacking the player
    player_summons = [
        npc for npc in game_state.game_world.non_player_characters
        if npc.npc_category == NpcCategory.PLAYER_SUMMON
    ]
    if player_summons:
        player_summon = player_summons[0]
        agent_position = agent_entity.get_position()
        distance_to_npc_target = get_manhattan_distance(
            player_summon.world_entity.get_position(), agent_position)
        distance_to_player = get_manhattan_distance(
            game_state.game_world.player_entity.get_position(), agent_position)
        if distance_to_npc_target < distance_to_player:
            return EnemyTarget.npc(player_summon.world_entity, player_summon)
    return EnemyTarget.player(game_state.game_world.player_entity)
示例#28
0
def _apply_ability(game_state: GameState) -> AbilityResult:
    player_entity = game_state.game_world.player_entity
    aoe_center_pos = translate_in_direction(
        player_entity.get_center_position(), player_entity.direction, 60)
    aoe_pos = get_position_from_center_position(aoe_center_pos,
                                                PROJECTILE_SIZE)
    projectile_speed = 0.1
    entity = WorldEntity(aoe_pos, PROJECTILE_SIZE, PROJECTILE_SPRITE,
                         player_entity.direction, projectile_speed)
    projectile = Projectile(entity,
                            create_projectile_controller(PROJECTILE_TYPE))
    game_state.game_world.projectile_entities.append(projectile)
    has_lightfooted_upgrade = game_state.player_state.has_upgrade(
        HeroUpgradeId.MAGE_LIGHT_FOOTED)
    if not has_lightfooted_upgrade:
        game_state.player_state.gain_buff_effect(
            get_buff_effect(BuffType.RECOVERING_AFTER_ABILITY), Millis(300))
    return AbilityWasUsedSuccessfully()
 def control_npc(self, game_state: GameState, npc: NonPlayerCharacter,
                 player_entity: WorldEntity, is_player_invisible: bool,
                 time_passed: Millis):
     if npc.stun_status.is_stunned():
         return
     super().control_npc(game_state, npc, player_entity,
                         is_player_invisible, time_passed)
     self.sprint_cooldown_remaining -= time_passed
     sprint_distance_limit = 250
     if self.sprint_cooldown_remaining <= 0:
         is_far_away = get_manhattan_distance(
             npc.world_entity.get_position(),
             player_entity.get_position()) > sprint_distance_limit
         if is_far_away:
             npc.gain_buff_effect(
                 get_buff_effect(BuffType.ENEMY_GOBLIN_SPEARMAN_SPRINT),
                 Millis(2500))
             self.sprint_cooldown_remaining = self.random_cooldown()
示例#30
0
 def apply_start_effect(self, game_state: GameState,
                        buffed_entity: WorldEntity,
                        buffed_npc: NonPlayerCharacter):
     game_state.player_state.stun_status.add_one()
     player_entity = game_state.game_world.player_entity
     player_entity.set_not_moving()
     player_entity.visible = False
     game_state.game_world.visual_effects += create_teleport_effects(
         buffed_entity.get_center_position())
     player_collision_rect = (player_entity.pygame_collision_rect.w,
                              player_entity.pygame_collision_rect.h)
     home_warp_point = create_warp_point(game_state.player_spawn_position,
                                         player_collision_rect)
     remote_warp_point = create_warp_point(
         player_entity.get_center_position(), player_collision_rect)
     game_state.game_world.warp_points = [
         home_warp_point, remote_warp_point
     ]