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.player_entity.get_center_position() distance = 80 affected_enemies = game_state.get_enemies_within_x_y_distance_of( distance, hero_center_pos) game_state.visual_effects.append( VisualRect((50, 50, 50), hero_center_pos, distance * 2, int(distance * 2.1), Millis(200), 2, None)) game_state.visual_effects.append( VisualRect((150, 150, 0), hero_center_pos, distance, distance * 2, Millis(150), 3, None)) game_state.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 open_chest(self, chest: Chest): loot = chest.loot_table.generate_loot() chest_position = chest.world_entity.get_position() self._put_loot_on_ground(chest_position, loot) chest.has_been_opened = True visual_effects = [ VisualRect((200, 0, 200), chest.world_entity.get_center_position(), 50, 100, Millis(100), 2), VisualRect((200, 0, 200), chest.world_entity.get_center_position(), 50, 100, Millis(180), 3) ] self.game_state.visual_effects += visual_effects
def _apply_ability(game_state: GameState) -> AbilityResult: hero_center_pos = game_state.game_world.player_entity.get_center_position() distance = 60 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, 100), hero_center_pos, distance * 2, int(distance * 2.1), Millis(200), 2, None)) game_state.game_world.visual_effects.append( VisualRect((150, 150, 200), hero_center_pos, distance, distance * 2, Millis(150), 3, None)) for enemy in affected_enemies: enemy.gain_buff_effect(get_buff_effect(BUFF_TYPE_STUNNED), STUN_DURATION) return AbilityWasUsedSuccessfully()
def _apply_ability(game_state: GameState) -> AbilityResult: player_entity = game_state.game_world.player_entity rect_w = 36 # Note: We assume that this ability is used by this specific hero hero_entity_size = HEROES[HeroId.WARRIOR].entity_size slash_pos = translate_in_direction( player_entity.get_center_position(), player_entity.direction, rect_w / 2 + hero_entity_size[0] * 0.25) slash_rect = Rect(int(slash_pos[0] - rect_w / 2), int(slash_pos[1] - rect_w / 2), rect_w, rect_w) affected_enemies = game_state.game_world.get_enemy_intersecting_rect(slash_rect) has_aoe_upgrade = game_state.player_state.has_upgrade(HeroUpgradeId.ABILITY_SLASH_AOE_BONUS_DAMAGE) hit_multiple_enemies = len(affected_enemies) > 1 for enemy in affected_enemies: if has_aoe_upgrade and hit_multiple_enemies: damage: float = MAX_DMG else: damage: float = MIN_DMG + random.random() * (MAX_DMG - MIN_DMG) deal_player_damage_to_enemy(game_state, enemy, damage, DamageType.PHYSICAL) game_state.game_world.visual_effects.append( VisualRect((100, 0, 0), slash_pos, rect_w, int(rect_w * 0.7), Millis(200), 2, None)) game_state.player_state.gain_buff_effect(get_buff_effect(BuffType.RECOVERING_AFTER_ABILITY), Millis(300)) return AbilityWasUsedSuccessfully()
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
def _apply_ability(game_state: GameState) -> AbilityResult: player_entity = game_state.game_world.player_entity rect_w = 28 slash_center_pos = translate_in_direction( player_entity.get_center_position(), player_entity.direction, rect_w / 2 + PLAYER_ENTITY_SIZE[0] * 0.25) slash_rect = Rect(int(slash_center_pos[0] - rect_w / 2), int(slash_center_pos[1] - rect_w / 2), rect_w, rect_w) affected_enemies = game_state.game_world.get_enemy_intersecting_rect( slash_rect) if not affected_enemies: return AbilityFailedToExecute(reason="No targets") # Note: Dependency on other ability 'stealth' should_stun = game_state.player_state.has_active_buff(BuffType.STEALTHING) if should_stun: game_state.camera_shake = CameraShake(Millis(50), Millis(150), 4) buff_effect = get_buff_effect(DEBUFF, should_stun) affected_enemies[0].gain_buff_effect(buff_effect, DEBUFF_DURATION) game_state.game_world.visual_effects.append( VisualRect((150, 150, 75), slash_center_pos, rect_w, int(rect_w * 0.7), Millis(200), 2, None)) game_state.game_world.visual_effects.append( VisualCross((100, 100, 70), slash_center_pos, 6, Millis(100), 2)) game_state.player_state.gain_buff_effect( get_buff_effect(BuffType.RECOVERING_AFTER_ABILITY), Millis(250)) return AbilityWasUsedSuccessfully()
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.visual_effects.append( VisualRect((250, 250, 50), effect_position, 30, 40, Millis(100), 1, buffed_entity))
def open_chest(self, chest: Chest): increased_money_chance = self.game_state.player_state.increased_loot_money_chance increased_rare_or_unique_chance = self.game_state.player_state.increased_loot_rare_or_unique_chance loot_table = get_loot_table(chest.loot_table) loot = loot_table.generate_loot(increased_money_chance, increased_rare_or_unique_chance, self.game_state.is_dungeon) chest_position = chest.world_entity.get_position() self._put_loot_on_ground(chest_position, loot) chest.has_been_opened = True visual_effects = [ VisualRect((200, 0, 200), chest.world_entity.get_center_position(), 50, 100, Millis(100), 2), VisualRect((200, 0, 200), chest.world_entity.get_center_position(), 50, 100, Millis(180), 3) ] self.game_state.game_world.visual_effects += visual_effects
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_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, 0), game_state.player_entity.get_center_position(), 6, 18, Millis(200), 3))
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.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)
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): 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_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))
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 _add_visual_lines_along_path(game_state, path): for i in range(len(path) - 1): current_pos = path[i] next_pos = path[i + 1] game_state.visual_effects.append( VisualRect((100, 150, 150), _get_middle_of_cell_from_position(current_pos), 7, 10, Millis(DEBUG_PATHFINDER_INTERVAL), 1)) game_state.visual_effects.append( VisualLine((250, 250, 250), _get_middle_of_cell_from_position(current_pos), _get_middle_of_cell_from_position(next_pos), Millis(DEBUG_PATHFINDER_INTERVAL), 1))
def _apply_ability(game_state: GameState) -> AbilityResult: player_entity = game_state.player_entity rect_w = 28 slash_center_pos = translate_in_direction( player_entity.get_center_position(), player_entity.direction, rect_w / 2 + PLAYER_ENTITY_SIZE[0] * 0.25) slash_rect = Rect(int(slash_center_pos[0] - rect_w / 2), int(slash_center_pos[1] - rect_w / 2), rect_w, rect_w) affected_enemies = game_state.get_enemy_intersecting_rect(slash_rect) is_stealthed = game_state.player_state.has_active_buff(BuffType.STEALTHING) if is_stealthed: play_sound(SoundId.ABILITY_SHIV_STEALTHED) else: play_sound(SoundId.ABILITY_SHIV) for enemy in affected_enemies: damage: float = MIN_DMG + random.random() * (MAX_DMG - MIN_DMG) # Note: Dependency on other ability 'stealth' if is_stealthed: # Talent: increase the damage bonus that Shiv gets from being used while stealthing has_damage_upgrade = game_state.player_state.has_upgrade( HeroUpgradeId.ABILITY_SHIV_SNEAK_BONUS_DAMAGE) damage *= SHIV_UPGRADED_STEALTH_DAMAGE_MULTIPLIER if has_damage_upgrade else SHIV_STEALTH_DAMAGE_MULTIPLIER game_state.camera_shake = CameraShake(Millis(50), Millis(150), 4) else: # Talent: if attacking an enemy that's at 100% health while not stealthing, deal bonus damage has_damage_upgrade = game_state.player_state.has_upgrade( HeroUpgradeId.ABILITY_SHIV_FULL_HEALTH_BONUS_DAMAGE) if has_damage_upgrade and enemy.health_resource.is_at_max(): damage *= SHIV_TALENT_FULL_HEALTH_DAMAGE_MULTIPLIER deal_player_damage_to_enemy(game_state, enemy, damage, DamageType.PHYSICAL, visual_emphasis=is_stealthed) break game_state.visual_effects.append( VisualRect((150, 150, 75), slash_center_pos, rect_w, int(rect_w * 0.7), Millis(200), 2, None)) game_state.visual_effects.append( VisualCross((100, 100, 70), slash_center_pos, 6, Millis(100), 2)) game_state.player_state.gain_buff_effect( get_buff_effect(BuffType.RECOVERING_AFTER_ABILITY), Millis(250)) return AbilityWasUsedSuccessfully()
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 _visual_rect(self, visual_rect: VisualRect): self.world_render.rect(visual_rect.color, visual_rect.rect(), visual_rect.line_width)