/** * \brief This function is called when the entity has just moved. * * If it is an NPC, its sprite's direction is updated. */ void Npc::notify_position_changed() { Entity::notify_position_changed(); if (subtype == USUAL_NPC) { const SpritePtr& sprite = get_sprite(); if (get_movement() != nullptr) { // The NPC is moving. if (sprite != nullptr) { if (sprite->get_current_animation() != "walking") { sprite->set_current_animation("walking"); } int direction4 = get_movement()->get_displayed_direction4(); sprite->set_current_direction(direction4); } } if (get_hero().get_facing_entity() == this && get_commands_effects().get_action_key_effect() == CommandsEffects::ACTION_KEY_SPEAK && !get_hero().is_facing_point_in(get_bounding_box())) { get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_NONE); } } }
/** * \brief This function is called by the engine when there is a collision with another entity. * * If the entity is the hero, we allow him to interact with this entity. * * \param entity_overlapping the entity overlapping the detector * \param collision_mode the collision mode that detected the collision */ void Npc::notify_collision(Entity& entity_overlapping, CollisionMode collision_mode) { if (collision_mode == COLLISION_FACING && entity_overlapping.is_hero()) { Hero& hero = static_cast<Hero&>(entity_overlapping); if (get_commands_effects().get_action_key_effect() == CommandsEffects::ACTION_KEY_NONE && hero.is_free()) { if (subtype == USUAL_NPC // the hero can talk to usual NPCs from any direction || get_direction() == -1 || hero.is_facing_direction4((get_direction() + 2) % 4)) { // show the appropriate action icon get_commands_effects().set_action_key_effect(subtype == USUAL_NPC ? CommandsEffects::ACTION_KEY_SPEAK : CommandsEffects::ACTION_KEY_LOOK); } else if (can_be_lifted() && get_equipment().has_ability(Ability::LIFT)) { get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_LIFT); } } } else if (collision_mode == COLLISION_OVERLAPPING && entity_overlapping.get_type() == EntityType::FIRE) { if (behavior == BEHAVIOR_ITEM_SCRIPT) { EquipmentItem& item = get_equipment().get_item(item_name); get_lua_context()->item_on_npc_collision_fire(item, *this); } else { get_lua_context()->npc_on_collision_fire(*this); } } }
/** * \brief This function is called when the entity has just moved. */ void Bomb::notify_position_changed() { Entity::notify_position_changed(); if (get_hero().get_facing_entity() == this && get_commands_effects().get_action_key_effect() == CommandsEffects::ACTION_KEY_LIFT && !get_hero().is_facing_point_in(get_bounding_box())) { get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_NONE); } }
/** * \copydoc Entity::notify_action_command_pressed */ bool Npc::notify_action_command_pressed() { Hero& hero = get_hero(); if (hero.is_free() && get_commands_effects().get_action_key_effect() != CommandsEffects::ACTION_KEY_NONE ) { CommandsEffects::ActionKeyEffect effect = get_commands_effects().get_action_key_effect(); get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_NONE); SpritePtr sprite = get_sprite(); // if this is a usual NPC, look towards the hero if (subtype == USUAL_NPC) { int direction = (get_hero().get_animation_direction() + 2) % 4; if (sprite != nullptr) { sprite->set_current_direction(direction); } } if (effect != CommandsEffects::ACTION_KEY_LIFT) { // start the normal behavior if (behavior == BEHAVIOR_DIALOG) { get_game().start_dialog(dialog_to_show, ScopedLuaRef(), ScopedLuaRef()); } else { call_script_hero_interaction(); } return true; } else { // lift the entity if (get_equipment().has_ability(Ability::LIFT)) { std::string animation_set_id = "stopped"; if (sprite != nullptr) { animation_set_id = sprite->get_animation_set_id(); } hero.start_lifting(std::make_shared<CarriedObject>( hero, *this, animation_set_id, "stone", 2, 0) ); Sound::play("lift"); remove_from_map(); return true; } } } return false; }
/** * \copydoc Entity::notify_action_command_pressed */ bool Block::notify_action_command_pressed() { if (get_commands_effects().get_action_key_effect() == CommandsEffects::ACTION_KEY_GRAB) { get_hero().start_grabbing(); return true; } return false; }
/** * \brief Starts this state. * \param previous_state the previous state */ void Hero::LiftingState::start(const State* previous_state) { State::start(previous_state); // initialize the entity that will be lifted lifted_item->set_map(get_map()); get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_THROW); get_sprites().set_animation_lifting(); get_sprites().set_lifted_item(lifted_item); get_entity().set_facing_entity(nullptr); get_equipment().notify_ability_used(Ability::LIFT); }
/** * \brief Starts this state. * \param previous_state the previous state */ void Hero::StairsState::start(const State* previous_state) { State::start(previous_state); // movement int speed = stairs->is_inside_floor() ? 40 : 24; std::string path = stairs->get_path(way); std::shared_ptr<PathMovement> movement = std::make_shared<PathMovement>( path, speed, false, true, false ); // sprites and sound HeroSprites& sprites = get_sprites(); if (carried_item == nullptr) { sprites.set_animation_walking_normal(); } else { sprites.set_lifted_item(carried_item); sprites.set_animation_walking_carrying(); } sprites.set_animation_direction((path[0] - '0') / 2); get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_NONE); Hero& hero = get_entity(); if (stairs->is_inside_floor()) { if (way == Stairs::NORMAL_WAY) { // Toward a higher layer: change the layer now. int layer = stairs->get_layer(); Debug::check_assertion(layer < get_map().get_num_layers(), "Invalid stairs layer"); get_entities().set_entity_layer(hero, layer + 1); } } else { sprites.set_clipping_rectangle(stairs->get_clipping_rectangle(way)); if (way == Stairs::REVERSE_WAY) { Point dxy = movement->get_xy_change(); int fix_y = 8; if (path[path.size() - 1] == '2') { fix_y *= -1; } hero.set_xy(hero.get_x() - dxy.x, hero.get_y() - dxy.y + fix_y); } } hero.set_movement(movement); }
/** * \copydoc Entity::notify_action_command_pressed */ bool Bomb::notify_action_command_pressed() { CommandsEffects::ActionKeyEffect effect = get_commands_effects().get_action_key_effect(); if (effect == CommandsEffects::ACTION_KEY_LIFT && get_hero().get_facing_entity() == this && get_hero().is_facing_point_in(get_bounding_box())) { get_hero().start_lifting(std::make_shared<CarriedObject>( get_hero(), *this, "entities/bomb", "", 0, explosion_date) ); Sound::play("lift"); remove_from_map(); return true; } return false; }
/** * \brief Ends this state. * \param next_state the next state */ void Hero::LiftingState::stop(const State* next_state) { State::stop(next_state); if (lifted_item != nullptr) { get_sprites().set_lifted_item(nullptr); // the lifted item is still managed by this state switch (next_state->get_previous_carried_item_behavior()) { case CarriedItem::BEHAVIOR_THROW: throw_item(); break; case CarriedItem::BEHAVIOR_DESTROY: case CarriedItem::BEHAVIOR_KEEP: lifted_item = nullptr; break; } get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_NONE); } }