def _apply_scroll(game_state: GameState): player_entity = game_state.game_world.player_entity summon_size = NON_PLAYER_CHARACTERS[NpcType.PLAYER_SUMMON_DRAGON].size player_size = game_state.game_world.player_entity.pygame_collision_rect.w, game_state.game_world.player_entity.h candidate_relative_positions = [ (0, - summon_size[1]), # top (player_size[0], - summon_size[1]), # top right (player_size[0], 0), # right (player_size[0], player_size[1]), # down right (0, player_size[1]), # down (-summon_size[0], player_size[1]), # down left (-summon_size[0], 0), # left (-summon_size[0], -summon_size[1]) # top left ] for relative_pos in candidate_relative_positions: summon_pos = sum_of_vectors(player_entity.get_position(), relative_pos) summon = create_npc(NpcType.PLAYER_SUMMON_DRAGON, summon_pos) is_valid_pos = not game_state.game_world.would_entity_collide_if_new_pos(summon.world_entity, summon_pos) if is_valid_pos: game_state.game_world.remove_all_player_summons() game_state.game_world.add_non_player_character(summon) summon.gain_buff_effect(get_buff_effect(BuffType.SUMMON_DIE_AFTER_DURATION), DURATION_SUMMON) game_state.game_world.visual_effects.append( VisualCircle((200, 200, 30), player_entity.get_position(), 40, 70, Millis(140), 3)) game_state.game_world.visual_effects.append( VisualCircle((200, 200, 30), summon_pos, 40, 70, Millis(140), 3)) return ConsumableWasConsumed("Summoned dragon") return ConsumableFailedToBeConsumed("No space to summon dragon")
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_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)
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)
def _apply_ability(game_state: GameState) -> AbilityResult: player_entity = game_state.game_world.player_entity previous_position = player_entity.get_center_position() used_from_stealth = game_state.player_state.has_active_buff( BuffType.STEALTHING) for distance in range(40, 200, 10): new_position = translate_in_direction( (player_entity.x, player_entity.y), player_entity.direction, distance) if game_state.game_world.is_position_within_game_world(new_position) \ and not game_state.game_world.would_entity_collide_if_new_pos(player_entity, new_position): if _would_collide_with_wall(game_state, player_entity, distance): return AbilityFailedToExecute(reason="Wall is blocking") should_regain_mana_and_cd = False enemy_hit = _get_enemy_that_was_hit(game_state, player_entity, distance) if enemy_hit: game_state.camera_shake = CameraShake(Millis(50), Millis(150), 4) deal_player_damage_to_enemy(game_state, enemy_hit, DAMAGE, DamageType.MAGIC) has_reset_upgrade = game_state.player_state.has_upgrade( HeroUpgradeId.ABILITY_DASH_KILL_RESET) enemy_died = enemy_hit.health_resource.is_at_or_below_zero() if has_reset_upgrade and enemy_died: should_regain_mana_and_cd = True player_entity.set_position(new_position) new_center_position = player_entity.get_center_position() color = (250, 140, 80) game_state.game_world.visual_effects.append( VisualCircle(color, previous_position, 17, 35, Millis(150), 1)) game_state.game_world.visual_effects.append( VisualLine(color, previous_position, new_center_position, Millis(250), 2)) game_state.game_world.visual_effects.append( VisualRect(color, previous_position, 37, 46, Millis(150), 1)) game_state.game_world.visual_effects.append( VisualCircle(color, new_center_position, 25, 40, Millis(300), 1, player_entity)) has_speed_upgrade = game_state.player_state.has_upgrade( HeroUpgradeId.ABILITY_DASH_MOVEMENT_SPEED) if has_speed_upgrade: game_state.player_state.gain_buff_effect( get_buff_effect(BUFF_SPEED), BUFF_SPEED_DURATION) if used_from_stealth: game_state.player_state.gain_buff_effect( get_buff_effect(BUFF_FROM_STEALTH), BUFF_FROM_STEALTH_DURATION) return AbilityWasUsedSuccessfully( should_regain_mana_and_cd=should_regain_mana_and_cd) return AbilityFailedToExecute(reason="No space")
def _apply(game_state: GameState): pos = game_state.game_world.player_entity.get_center_position() effect1 = VisualCircle((100, 150, 100), pos, 40, 120, Millis(2200), 2) effect2 = VisualCircle((100, 150, 100), pos, 40, 130, Millis(2000), 1) game_state.game_world.visual_effects += [effect1, effect2] affected_enemies = game_state.game_world.get_enemies_within_x_y_distance_of( 120, pos) for enemy in affected_enemies: enemy.gain_buff_effect(get_buff_effect(BUFF_TYPE), DEBUFF_DURATION) return ConsumableWasConsumed()
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 > 500: self._time_since_graphics = 0 if buffed_npc: deal_npc_damage_to_npc(game_state, buffed_npc, 2) game_state.visual_effects.append( VisualCircle((180, 50, 50), buffed_npc.world_entity.get_center_position(), 10, 20, Millis(50), 0, buffed_entity)) else: deal_damage_to_player(game_state, 2, DamageType.MAGIC, None) game_state.visual_effects.append( VisualCircle((180, 50, 50), game_state.player_entity.get_center_position(), 10, 20, Millis(50), 0, buffed_entity))
def _handle_gain_exp_events(self, gain_exp_events): did_level_up = False new_abilities: List[str] = [] did_unlock_new_talent = False for event in gain_exp_events: if isinstance(event, PlayerLeveledUp): did_level_up = True if isinstance(event, PlayerLearnedNewAbility): new_abilities.append(ABILITIES[event.ability_type].name) if isinstance(event, PlayerUnlockedNewTalent): did_unlock_new_talent = True if did_level_up: play_sound(SoundId.EVENT_PLAYER_LEVELED_UP) self.game_state.visual_effects.append( VisualCircle( (150, 150, 250), self.game_state.player_entity.get_center_position(), 9, 35, Millis(150), 2)) self.info_message.set_message( "You reached level " + str(self.game_state.player_state.level)) if new_abilities: allocate_input_keys_for_abilities( self.game_state.player_state.abilities) if len(new_abilities) == 1: self.info_message.enqueue_message("New ability: " + new_abilities[0]) elif len(new_abilities) > 1: self.info_message.enqueue_message("Gained several new abilities") if did_unlock_new_talent: self.talent_was_unlocked.notify(None) self.info_message.enqueue_message("You can pick a talent!")
def apply_wall_collision(self, game_state: GameState, projectile: Projectile): game_state.game_world.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
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.game_world.visual_effects.append( VisualCircle(self._color, game_state.game_world.player_entity.get_center_position(), 25, 35, Millis(100), 0)) projectile.has_collided_and_should_be_removed = True
def apply_player_collision(self, game_state: GameState, projectile: Projectile): deal_damage_to_player(game_state, 1, DamageType.MAGIC, None) game_state.player_state.gain_buff_effect(get_buff_effect(BuffType.ENEMY_GOBLIN_WARLOCK_BURNT), Millis(5000)) game_state.game_world.visual_effects.append( VisualCircle((180, 50, 50), game_state.game_world.player_entity.get_center_position(), 25, 50, Millis(100), 0)) projectile.has_collided_and_should_be_removed = True
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): color = (random.randint(150, 200), random.randint(150, 200), random.randint(50, 100)) head = VisualRect(color, projectile.world_entity.get_center_position(), 15, 15, Millis(120), 4, projectile.world_entity) tail = VisualCircle(color, projectile.world_entity.get_center_position(), 13, 13, Millis(180), 2) game_state.game_world.visual_effects += [head, tail]
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_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))
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.game_world.visual_effects.append( VisualCircle(self._color, npc.world_entity.get_center_position(), 25, 35, Millis(100), 0)) projectile.has_collided_and_should_be_removed = True
def update(self, npc: NonPlayerCharacter, game_state: GameState, time_passed: Millis): self._time_since_summoning += time_passed if self._time_since_summoning > self._summoning_cooldown: necro_center_pos = npc.world_entity.get_center_position() self._time_since_summoning = 0 self._alive_summons = [ summon for summon in self._alive_summons if summon in game_state.game_world.non_player_characters ] if len(self._alive_summons) < self._max_summons: relative_pos_from_summoner = (random.randint(-150, 150), random.randint(-150, 150)) summon_center_pos = sum_of_vectors(necro_center_pos, relative_pos_from_summoner) summon_type = random.choice(self._summon_npc_types) summon_size = NON_PLAYER_CHARACTERS[summon_type].size summon_pos = game_state.game_world.get_within_world( get_position_from_center_position(summon_center_pos, summon_size), summon_size) summon_enemy = self._create_npc(summon_type, summon_pos) is_wall_blocking = game_state.game_world.walls_state.does_rect_intersect_with_wall( rect_from_corners(necro_center_pos, summon_center_pos)) is_position_blocked = game_state.game_world.would_entity_collide_if_new_pos( summon_enemy.world_entity, summon_pos) if not is_wall_blocking and not is_position_blocked: self._summoning_cooldown = self._random_summoning_cooldown( ) game_state.game_world.add_non_player_character( summon_enemy) self._alive_summons.append(summon_enemy) game_state.game_world.visual_effects.append( VisualCircle((80, 150, 100), necro_center_pos, 40, 70, Millis(120), 3)) game_state.game_world.visual_effects.append( VisualCircle((80, 150, 100), summon_center_pos, 40, 70, Millis(120), 3)) play_sound(SoundId.ENEMY_NECROMANCER_SUMMON) else: # Failed to summon, so try again without waiting full duration self._summoning_cooldown = 500 else: self._summoning_cooldown = self._random_summoning_cooldown()
def apply_player_summon_collision(self, npc: NonPlayerCharacter, game_state: GameState, projectile: Projectile): deal_npc_damage_to_npc(game_state, npc, 1) npc.gain_buff_effect( get_buff_effect(BuffType.ENEMY_GOBLIN_WARLOCK_BURNT), Millis(5000)) game_state.visual_effects.append( VisualCircle((180, 50, 50), npc.world_entity.get_center_position(), 25, 50, Millis(100), 0)) projectile.has_collided_and_should_be_removed = True
def apply_enemy_collision(self, npc: NonPlayerCharacter, game_state: GameState, projectile: Projectile): if npc not in self._enemies_hit: deal_player_damage_to_enemy(game_state, npc, DAMAGE, DamageType.MAGIC) game_state.game_world.visual_effects.append( VisualCircle((250, 100, 250), npc.world_entity.get_center_position(), 15, 25, Millis(100), 0)) self._enemies_hit.append(npc)
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_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 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.visual_effects.append(visual_effect) game_state.visual_effects.append( create_visual_stun_text(buffed_entity)) buffed_npc.stun_status.add_one() buffed_entity.set_not_moving()
def _create_visual_splash(effect_position, game_state): game_state.visual_effects.append( VisualCircle((250, 100, 50), effect_position, 22, 45, Millis(100), 0)) particle_colors = [(250, 100, 100), (250, 50, 100), (250, 100, 50)] particle_system = VisualParticleSystem(num_particles=10, position=effect_position, colors=particle_colors, alpha=100, duration_interval=(Millis(50), Millis(200))) game_state.visual_effects.append(particle_system)
def _apply_teleport(game_state: GameState) -> AbilityResult: player_entity = game_state.player_entity previous_position = player_entity.get_center_position() new_position = translate_in_direction((player_entity.x, player_entity.y), player_entity.direction, 140) player_entity.set_position(new_position) new_center_position = player_entity.get_center_position() color = (140, 140, 230) game_state.visual_effects.append( VisualCircle(color, previous_position, 17, 35, Millis(150), 1)) game_state.visual_effects.append( VisualRect(color, previous_position, 37, 50, Millis(150), 1)) game_state.visual_effects.append( VisualLine(color, previous_position, new_center_position, Millis(200), 1)) game_state.visual_effects.append( VisualCircle(color, new_center_position, 25, 50, Millis(300), 2, player_entity)) return AbilityWasUsedSuccessfully()
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.visual_effects.append(visual_effect) return False
def _put_loot_on_ground(self, enemy_death_position: Tuple[int, int], loot: List[LootEntry]): for loot_entry in loot: if len(loot) > 1: position_offset = (random.randint(-20, 20), random.randint(-20, 20)) else: position_offset = (0, 0) loot_position = sum_of_vectors(enemy_death_position, position_offset) if isinstance(loot_entry, MoneyLootEntry): money_pile_on_ground = create_money_pile_on_ground( loot_entry.amount, loot_position) self.game_state.game_world.money_piles_on_ground.append( money_pile_on_ground) elif isinstance(loot_entry, ItemLootEntry): item_id = randomized_item_id(loot_entry.item_type) item_on_ground = create_item_on_ground(item_id, loot_position) self.game_state.game_world.items_on_ground.append( item_on_ground) elif isinstance(loot_entry, AffixedItemLootEntry): item_id = loot_entry.item_id item_on_ground = create_item_on_ground(item_id, loot_position) self.game_state.game_world.items_on_ground.append( item_on_ground) loot_center_pos = (loot_position[0] + ITEM_ENTITY_SIZE[0] // 2, loot_position[1] + ITEM_ENTITY_SIZE[1] // 2) self.game_state.game_world.visual_effects.append( VisualCircle((170, 200, 170), loot_center_pos, 30, 40, Millis(500), 2)) self.game_state.game_world.visual_effects.append( VisualCircle((70, 100, 70), loot_center_pos, 25, 35, Millis(500), 2)) elif isinstance(loot_entry, ConsumableLootEntry): consumable_on_ground = create_consumable_on_ground( loot_entry.consumable_type, loot_position) self.game_state.game_world.consumables_on_ground.append( consumable_on_ground)
def control_npc(self, game_state: GameState, npc: NonPlayerCharacter, player_entity: WorldEntity, _is_player_invisible: bool, time_passed: Millis): self._time_since_decision += 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() if not npc.health_resource.is_at_max(): healing_amount = random.randint(10, 20) npc.health_resource.gain(healing_amount) circle_effect = VisualCircle( (80, 200, 150), npc.world_entity.get_center_position(), 30, 50, Millis(350), 3) game_state.visual_effects.append(circle_effect) number_effect = create_visual_healing_text( npc.world_entity, healing_amount) game_state.visual_effects.append(number_effect) play_sound(SoundId.ENEMY_SKELETON_MAGE_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.projectile_entities.append(projectile) play_sound(SoundId.ENEMY_ATTACK_SKELETON_MAGE) if self._time_since_decision > self._decision_interval: self._time_since_decision = 0 if random.random() < 0.2: direction = random_direction() npc.world_entity.set_moving_in_dir(direction) else: npc.world_entity.set_not_moving()
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()
def _apply_ability(game_state: GameState) -> AbilityResult: player_entity = game_state.game_world.player_entity player_center_pos = player_entity.get_center_position() game_state.game_world.visual_effects.append( VisualCircle((150, 150, 250), player_center_pos, 95, 190, Millis(200), 3)) affected_enemies = game_state.game_world.get_enemies_within_x_y_distance_of(180, player_center_pos) effect_position = get_position_from_center_position(player_center_pos, EFFECT_SPRITE_SIZE) game_state.game_world.visual_effects.append( VisualSprite(Sprite.EFFECT_ABILITY_FROST_NOVA, effect_position, Millis(200), player_entity)) for enemy in affected_enemies: damage_was_dealt = deal_player_damage_to_enemy(game_state, enemy, 5, DamageType.MAGIC ) if damage_was_dealt: enemy.gain_buff_effect(get_buff_effect(BuffType.REDUCED_MOVEMENT_SPEED), Millis(4000)) return AbilityWasUsedSuccessfully()
def strike_enemies(game_state: GameState, num_enemies: int): player_entity = game_state.game_world.player_entity player_center_position = player_entity.get_center_position() close_enemies = game_state.game_world.get_enemies_within_x_y_distance_of( 140, player_center_position) # TODO: sound effect for enemy in close_enemies[0:num_enemies]: damage_amount: float = MIN_DMG + random.random() * (MAX_DMG - MIN_DMG) deal_player_damage_to_enemy(game_state, enemy, damage_amount, DamageType.MAGIC) enemy_center_position = enemy.world_entity.get_center_position() game_state.game_world.visual_effects.append( VisualCircle((250, 250, 0), player_center_position, 50, 140, Millis(100), 1, player_entity)) game_state.game_world.visual_effects.append( VisualLine((250, 250, 0), player_center_position, enemy_center_position, Millis(80), 3))
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