/** * \copydoc Detector::notify_action_command_pressed */ bool Chest::notify_action_command_pressed() { if (is_enabled() && get_hero().is_free() && get_keys_effect().get_action_key_effect() != KeysEffect::ACTION_KEY_NONE ) { if (can_open()) { Sound::play("chest_open"); set_open(true); treasure_date = System::now() + 300; get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); get_hero().start_freezed(); } else if (!get_cannot_open_dialog_id().empty()) { Sound::play("wrong"); get_game().start_dialog(get_cannot_open_dialog_id(), ScopedLuaRef(), ScopedLuaRef()); } return true; } return false; }
/** * \brief Notifies this state that the action command was just pressed. */ void Hero::FreeState::notify_action_command_pressed() { Hero& hero = get_hero(); Detector* facing_entity = hero.get_facing_entity(); bool facing_entity_interaction = false; if (facing_entity != nullptr) { if (get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_NONE || get_keys_effect().is_action_key_acting_on_facing_entity() ) { // action on the facing entity facing_entity_interaction = facing_entity->notify_action_command_pressed(); } } if (!facing_entity_interaction) { // The event was not handled by the facing entity. if (hero.is_facing_point_on_obstacle()) { // grab an obstacle hero.set_state(new GrabbingState(hero)); } else if (hero.can_run()) { // run hero.start_running(); } } }
/** * @brief This function is called when the entity has just moved. */ void Bomb::notify_position_changed() { if (get_hero().get_facing_entity() == this && get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_LIFT && !get_hero().is_facing_point_in(get_bounding_box())) { get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); } }
/** * @brief This function is called by the engine when an entity overlaps the shop item. * * If the entity is the hero, we allow him to buy the item. * * @param entity_overlapping the entity overlapping the detector * @param collision_mode the collision mode that detected the collision */ void ShopItem::notify_collision(MapEntity &entity_overlapping, CollisionMode collision_mode) { if (entity_overlapping.is_hero() && !get_game().is_suspended()) { Hero &hero = (Hero&) entity_overlapping; if (get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_NONE && hero.is_free()) { // we show the 'look' icon get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_LOOK); } } }
/** * \copydoc Detector::notify_action_command_pressed */ bool Crystal::notify_action_command_pressed() { if (get_hero().is_free() && get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_LOOK ) { get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); // start a dialog get_game().start_dialog("_crystal", ScopedLuaRef(), ScopedLuaRef()); return true; } return false; }
/** * \brief This function is called by the engine when an entity overlaps the shop item. * * If the entity is the hero, we allow him to buy the item. * * \param entity_overlapping the entity overlapping the detector * \param collision_mode the collision mode that detected the collision */ void ShopTreasure::notify_collision( MapEntity& entity_overlapping, CollisionMode /* collision_mode */) { if (entity_overlapping.is_hero() && !get_game().is_suspended()) { Hero& hero = static_cast<Hero&>(entity_overlapping); if (get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_NONE && hero.is_free()) { // we show the 'look' icon get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_LOOK); } } }
/** * \brief Stops this state. * \param next_state the next state */ void Hero::CarryingState::stop(State *next_state) { PlayerMovementState::stop(next_state); get_sprites().set_lifted_item(NULL); get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); if (carried_item != NULL) { switch (next_state->get_previous_carried_item_behavior(*carried_item)) { case CarriedItem::BEHAVIOR_THROW: throw_item(); break; case CarriedItem::BEHAVIOR_DESTROY: delete carried_item; carried_item = NULL; break; case CarriedItem::BEHAVIOR_KEEP: carried_item = NULL; break; default: Debug::die("Invalid carried item behavior"); } } }
/** * \brief Notifies this state that the action command was just pressed. */ void Hero::CarryingState::notify_action_command_pressed() { if (get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_THROW) { throw_item(); hero.set_state(new FreeState(hero)); } }
/** * @brief Ends this state. * @param next_state the next state */ void Hero::LiftingState::stop(State *next_state) { State::stop(next_state); if (lifted_item != NULL) { get_sprites().set_lifted_item(NULL); // the lifted item is still managed by this state switch (next_state->get_previous_carried_item_behavior(*lifted_item)) { case CarriedItem::BEHAVIOR_THROW: throw_item(); break; case CarriedItem::BEHAVIOR_DESTROY: delete lifted_item; lifted_item = NULL; break; case CarriedItem::BEHAVIOR_KEEP: lifted_item = NULL; break; } get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); } }
/** * \brief Starts this state. * \param previous_state the previous state */ void Hero::FreezedState::start(const State* previous_state) { State::start(previous_state); get_sprites().set_animation_stopped_normal(); get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); }
/** * \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 != NULL) { get_sprites().set_lifted_item(NULL); // 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: destroy_lifted_item(); break; case CarriedItem::BEHAVIOR_KEEP: // The next state is now the owner and has incremented the refcount. Debug::check_assertion(lifted_item->get_refcount() > 1, "Invalid carried item refcount"); RefCountable::unref(lifted_item); lifted_item = NULL; break; } get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); } }
/** * \brief Stops this state. * \param next_state the next state */ void Hero::SwimmingState::stop(State* next_state) { PlayerMovementState::stop(next_state); Hero& hero = get_hero(); hero.set_walking_speed(hero.get_normal_walking_speed()); get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); }
/** * \brief This function is called when this entity detects a collision with the hero. * \param hero the hero * \param collision_mode the collision mode that detected the collision */ void Destructible::notify_collision_with_hero(Hero& hero, CollisionMode /* collision_mode */) { if (get_weight() != -1 && !is_being_cut && !is_waiting_for_regeneration() && !is_regenerating && get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_NONE && hero.is_free()) { if (get_equipment().has_ability(Ability::LIFT, get_weight())) { get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_LIFT); } else { get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_LOOK); } } }
/** * \brief Starts this state. * \param previous_state the previous state */ void Hero::SwimmingState::start(State* previous_state) { PlayerMovementState::start(previous_state); get_equipment().notify_ability_used("swim"); get_hero().set_walking_speed(get_slow_swimming_speed()); get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_SWIM); }
/** * @brief Notifies this detector that the player is interacting with it by * pressing the action command. * * This function is called when the player presses the action command * while the hero is facing this detector, and the action command effect lets * him do this. * A dialog is shown to let the hero buy the item. */ void ShopItem::notify_action_command_pressed() { if (get_hero().is_free() && get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_LOOK) { get_dialog_box().start_dialog(dialog_id); is_looking_item = true; } }
/** * @brief This function is called when the player interacts with this entity. * * This function is called when the player presses the action key * while the hero is facing this detector, and the action icon lets him do this. */ void CrystalSwitch::action_key_pressed() { if (get_hero().is_free()) { get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); // start a dialog get_dialog_box().start_dialog("_crystal_switch"); } }
/** * \brief This function is called when this entity detects a collision with the hero. * \param hero the hero * \param collision_mode the collision mode that detected the collision */ void Destructible::notify_collision_with_hero(Hero& hero, CollisionMode collision_mode) { if (features[subtype].can_be_lifted && !is_being_cut && !is_disabled() && !is_regenerating && get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_NONE && hero.is_free()) { int weight = features[subtype].weight; if (get_equipment().has_ability("lift", weight)) { get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_LIFT); } else { get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_LOOK); } } }
/** * \brief Notifies this state that the attack command was just pressed. */ void Hero::State::notify_attack_command_pressed() { if (!hero.is_suspended() && get_keys_effect().get_sword_key_effect() == KeysEffect::SWORD_KEY_SWORD && can_start_sword()) { hero.set_state(new SwordSwingingState(hero)); } }
/** * \brief Notifies this detector that the player is interacting with it by * pressing the action command. * * This function is called when the player presses the action command * while the hero is facing this detector, and the action command effect lets * him do this. */ void Crystal::notify_action_command_pressed() { if (get_hero().is_free()) { get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); // start a dialog get_game().start_dialog("_crystal", LUA_REFNIL); } }
/** * \brief Notifies this detector that the player is interacting with it by * pressing the action command. * * This function is called when the player presses the action command * while the hero is facing this detector, and the action command effect lets * him do this. */ void Destructible::notify_action_command_pressed() { KeysEffect::ActionKeyEffect effect = get_keys_effect().get_action_key_effect(); if ((effect == KeysEffect::ACTION_KEY_LIFT || effect == KeysEffect::ACTION_KEY_LOOK) && features[subtype].can_be_lifted && !is_being_cut && !is_disabled() && !is_regenerating) { int weight = features[subtype].weight; if (get_equipment().has_ability("lift", weight)) { uint32_t explosion_date = can_explode() ? System::now() + 6000 : 0; get_hero().start_lifting(new CarriedItem( get_hero(), *this, get_animation_set_id(), get_destruction_sound_id(), get_damage_on_enemies(), explosion_date) ); // play the sound Sound::play("lift"); // create the pickable item create_pickable(); // remove the item from the map if (!features[subtype].can_regenerate) { destruction_callback(); remove_from_map(); } else { // the item can actually regenerate play_destroy_animation(); } } else { if (features[subtype].can_be_cut && !features[subtype].can_explode && !get_equipment().has_ability("sword", 1)) { get_game().start_dialog("_cannot_lift_should_cut", LUA_REFNIL); } else if (!get_equipment().has_ability("lift", 1)) { get_game().start_dialog("_cannot_lift_too_heavy", LUA_REFNIL); } else { get_game().start_dialog("_cannot_lift_still_too_heavy", LUA_REFNIL); } } } }
/** * @brief Notifies this detector that a collision was just detected with another entity. * * This function is called by the engine when there is a collision with another entity. * * @param entity_overlapping the entity overlapping the detector * @param collision_mode the collision mode that detected the collision */ void Door::notify_collision(MapEntity& entity_overlapping, CollisionMode collision_mode) { if (is_closed() && entity_overlapping.is_hero()) { Hero& hero = static_cast<Hero&>(entity_overlapping); if (get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_NONE && hero.is_free()) { if (can_open()) { // The action command opens the door. get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_OPEN); } else if (!get_cannot_open_dialog_id().empty()) { // The action command shows a dialog. get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_LOOK); } } } }
/** * \brief Starts this state. * \param previous_state the previous state */ void Hero::CarryingState::start(State *previous_state) { PlayerMovementState::start(previous_state); if (is_current_state()) { get_sprites().set_lifted_item(carried_item); // action icon "throw" get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_THROW); } }
/** * \copydoc Detector::notify_action_command_pressed */ bool ShopTreasure::notify_action_command_pressed() { if (get_hero().is_free() && get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_LOOK) { LuaContext& lua_context = get_lua_context(); lua_context.notify_shop_treasure_interaction(*this); return true; } return false; }
/** * \copydoc Detector::notify_action_command_pressed */ bool Destructible::notify_action_command_pressed() { KeysEffect::ActionKeyEffect effect = get_keys_effect().get_action_key_effect(); if ((effect == KeysEffect::ACTION_KEY_LIFT || effect == KeysEffect::ACTION_KEY_LOOK) && get_weight() != -1 && !is_being_cut && !is_waiting_for_regeneration() && !is_regenerating) { if (get_equipment().has_ability(Ability::LIFT, get_weight())) { uint32_t explosion_date = get_can_explode() ? System::now() + 6000 : 0; get_hero().start_lifting(std::make_shared<CarriedItem>( get_hero(), *this, get_animation_set_id(), get_destruction_sound(), get_damage_on_enemies(), explosion_date) ); // Play the sound. Sound::play("lift"); // Create the pickable treasure. create_treasure(); if (!get_can_regenerate()) { // Remove this destructible from the map. remove_from_map(); } else { // The item can actually regenerate. play_destroy_animation(); } // Notify Lua. get_lua_context().destructible_on_lifting(*this); } else { // Cannot lift the object. get_hero().start_grabbing(); get_lua_context().destructible_on_looked(*this); } return true; } return false; }
/** * \brief Notifies this detector that the player is interacting with it by * pressing the action command. * * This function is called when the player presses the action command * while the hero is facing this detector, and the action command effect lets * him do this. * The hero lifts the bomb if possible. */ void Bomb::notify_action_command_pressed() { KeysEffect::ActionKeyEffect effect = get_keys_effect().get_action_key_effect(); if (effect == KeysEffect::ACTION_KEY_LIFT && get_hero().get_facing_entity() == this && get_hero().is_facing_point_in(get_bounding_box())) { get_hero().start_lifting(new CarriedItem(get_hero(), *this, "entities/bomb", "", 0, explosion_date)); Sound::play("lift"); remove_from_map(); } }
/** * \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_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_THROW); get_sprites().set_animation_lifting(); get_sprites().set_lifted_item(lifted_item); get_hero().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_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); Hero& hero = get_hero(); if (stairs.is_inside_floor()) { if (way == Stairs::NORMAL_WAY) { // Towards an upper layer: change the layer now Layer layer = stairs.get_layer(); Debug::check_assertion(layer != LAYER_HIGH, "Invalid stairs layer"); get_entities().set_entity_layer(hero, Layer(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); }
/** * @brief This function is called when the player interacts with this chest. * * This function is called when the player presses the action key * when the hero is facing this detector, and the action icon lets him do this. * The hero opens the chest if possible. */ void Chest::action_key_pressed() { if (is_visible() && get_hero().is_free()) { if (!big_chest || get_equipment().has_ability("open_dungeon_big_locks")) { Sound::play("chest_open"); set_open(true); treasure_date = System::now() + 300; get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); get_hero().start_freezed(); } else { Sound::play("wrong"); get_dialog_box().start_dialog("_big_key_required"); } } }
/** * \brief Notifies this state that the action command was just pressed. */ void Hero::FreeState::notify_action_command_pressed() { if (get_keys_effect().is_action_key_acting_on_facing_entity()) { // action on the facing entity hero.get_facing_entity()->notify_action_command_pressed(); } else if (hero.is_facing_point_on_obstacle()) { // grab an obstacle hero.set_state(new GrabbingState(hero)); } else if (get_equipment().has_ability("run")) { // run hero.start_running(); } }
/** * @brief Starts this state. * @param previous_state the previous state */ void Hero::StairsState::start(State* previous_state) { State::start(previous_state); // movement int speed = stairs.is_inside_floor() ? 40 : 24; std::string path = stairs.get_path(way); PathMovement* movement = new PathMovement(path, speed, false, true, false); // sprites and sound HeroSprites& sprites = get_sprites(); if (carried_item == NULL) { 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_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_NONE); if (stairs.is_inside_floor()) { if (way == Stairs::NORMAL_WAY) { // low layer to intermediate layer: change the layer now get_entities().set_entity_layer(hero, LAYER_INTERMEDIATE); } } else { sprites.set_clipping_rectangle(stairs.get_clipping_rectangle(way)); if (way == Stairs::REVERSE_WAY) { Rectangle 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.get_x(), hero.get_y() - dxy.get_y() + fix_y); } } hero.set_movement(movement); }