Ejemplo n.º 1
0
/**
 * @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 opens the door if possible, otherwise a message is shown.
 */
void Door::notify_action_command_pressed() {

  if (get_hero().is_free() && is_closed()) {

    if (can_open()) {
      Sound::play("door_unlocked");
      Sound::play("door_open");

      if (is_saved()) {
        get_savegame().set_boolean(savegame_variable, true);
      }

      if (is_opening_condition_consumed()) {
        consume_opening_condition();
      }

      set_opening();

      get_hero().check_position();
    }
    else if (!cannot_open_dialog_id.empty()) {
      Sound::play("wrong");
      get_dialog_box().start_dialog(cannot_open_dialog_id);
    }
  }
}
Ejemplo n.º 2
0
/**
 * @brief Updates the entity.
 */
void Door::update() {

  Detector::update();

  if (!initialized) {
    update_dynamic_tiles();
    initialized = true;
  }

  if (is_closed()
      && get_opening_method() == OPENING_BY_EXPLOSION
      && get_equipment().has_ability("detect_weak_walls")
      && Geometry::get_distance(get_center_point(), get_hero().get_center_point()) < 40
      && !is_suspended()
      && System::now() >= next_hint_sound_date) {
    Sound::play("cane");
    next_hint_sound_date = System::now() + 500;
  }

  if (is_changing() && get_sprite().is_animation_finished()) {
    // Toggle door_open when the changing animation finishes.
    set_open(is_opening());
  }

  if (is_saved() && !is_changing()) {
    bool open_in_savegame = get_savegame().get_boolean(savegame_variable);
    if (open_in_savegame && is_closed()) {
      set_opening();
    }
    else if (!open_in_savegame && is_open()) {
      set_closing();
    }
  }
}
Ejemplo n.º 3
0
/**
 * \brief Saves the low-level keyboard command where the specified game key is
 * mapped.
 * \param command A game command.
 * \param keyboard_key The keyboard key to map to this game command in the
 * savegame.
 */
void GameCommands::set_saved_keyboard_binding(
    Command command, InputEvent::KeyboardKey keyboard_key) {

  const std::string& savegame_variable = get_keyboard_binding_savegame_variable(command);
  const std::string& keyboard_key_name = InputEvent::get_keyboard_key_name(keyboard_key);
  get_savegame().set_string(savegame_variable, keyboard_key_name);
}
Ejemplo n.º 4
0
/**
 * \brief Determines from the savegame the low-level keyboard key where the
 * specified game command is mapped.
 * \param command A game command.
 * \return The keyboard key mapped to this game command in the savegame.
 */
InputEvent::KeyboardKey GameCommands::get_saved_keyboard_binding(
    GameCommand command) const {

  const std::string& savegame_variable = get_keyboard_binding_savegame_variable(command);
  const std::string& keyboard_key_name = get_savegame().get_string(savegame_variable);
  return name_to_enum(keyboard_key_name, InputEvent::KEY_NONE);
}
Ejemplo n.º 5
0
/**
 * @brief Makes the door immediately open or closed.
 * @param door_open true to make it opened, false to make it closed.
 */
void Door::set_open(bool door_open) {

  state = door_open ? OPEN : CLOSED;

  if (door_open) {
    set_collision_modes(COLLISION_NONE); // to avoid being the hero's facing entity
  }
  else {
    get_sprite().set_current_animation("closed");
    set_collision_modes(COLLISION_FACING_POINT | COLLISION_SPRITE);

    // ensure that we are not closing the door on the hero
    if (is_on_map() && overlaps(get_hero())) {
      get_hero().avoid_collision(*this, (get_direction() + 2) % 4);
    }
  }

  if (is_on_map()) {
    update_dynamic_tiles();

    if (is_saved()) {
      get_savegame().set_boolean(savegame_variable, door_open);
    }

    if (door_open) {
      get_lua_context().door_on_opened(*this);
    }
    else {
      get_lua_context().door_on_closed(*this);
    }
  }
}
Ejemplo n.º 6
0
/**
 * \brief Updates the chest.
 *
 * This function is called repeatedly by the map.
 * This is a redefinition of MapEntity::update()
 * the handle the chest opening.
 */
void Chest::update() {

  if (is_open() && !is_suspended()) {

    if (!treasure_given && treasure_date != 0 && System::now() >= treasure_date) {

      treasure_date = 0;
      treasure.ensure_obtainable();  // Make the chest empty if the treasure is not allowed.
      if (!treasure.is_empty()) {
        // Give a treasure to the player.

        get_hero().start_treasure(treasure, ScopedLuaRef());
        treasure_given = true;
      }
      else {  // The chest is empty.

        if (treasure.is_saved()) {
          // Mark the treasure as found in the savegame.
          get_savegame().set_boolean(treasure.get_savegame_variable(), true);
        }

        treasure_given = true;

        bool done = get_lua_context().chest_on_empty(*this);
        if (!done) {
          // The script does not define any behavior:
          // by default, do nothing and unfreeze the hero.
          get_hero().start_free();
        }
      }
    }
  }

  MapEntity::update();
}
Ejemplo n.º 7
0
static int a_save(int index, int subindex)
{
   if (index == M_INIT) {
      b_loadgame(save);
      b_loadsave(savemenu[2], save[0]);
      b_loadsave(savemenu[3], save[1]);
      b_loadsave(savemenu[4], save[2]);
      backoff = shopmenu;
      return 0;
   }

// Player wants to save a game.
   switch (index) {
   case 2:
   case 3:
   case 4:     // Save game.
      save[index-2] = *get_savegame();
      b_updatesave(save[index-2]);
      b_savegame(save);
      b_loadsave(savemenu[index], save[index-2], "saved");
      break;
   case 5:     // Back to main menu;
      buildmenu(shopmenu);
      break;
   }

   return 0;
}
Ejemplo n.º 8
0
/**
 * \brief Determines from the savegame the low-level keyboard key where the
 * specified game command is mapped.
 * \param command A game command.
 * \return The keyboard key mapped to this game command in the savegame.
 */
InputEvent::KeyboardKey GameCommands::get_saved_keyboard_binding(
    Command command) const {

  const std::string& savegame_variable = get_keyboard_binding_savegame_variable(command);
  const std::string& keyboard_key_name = get_savegame().get_string(savegame_variable);
  return InputEvent::get_keyboard_key_by_name(keyboard_key_name);
}
Ejemplo n.º 9
0
/**
 * \brief Ends this game.
 */
void Game::stop() {

  if (current_map != NULL && current_map->is_started()) {
    current_map->leave();
  }
  get_lua_context().game_on_finished(*this);
  get_savegame().notify_game_finished();
  started = false;
}
Ejemplo n.º 10
0
/**
 * \brief Kills the enemy.
 *
 * This function is called when the enemy has no more health points.
 */
void Enemy::kill() {

  // if the enemy is immobilized, give some money
  if (rank == RANK_NORMAL && is_immobilized() && !treasure.is_saved()) {
    // TODO choose random money (can we do this from scripts?)
  }

  // stop any movement and disable attacks
  set_collision_modes(COLLISION_NONE);
  clear_movement();
  invulnerable = true;
  can_attack = false;
  can_attack_again_date = 0;
  dying_animation_started = true;

  if (hurt_style == HURT_BOSS) {
    // A boss: create some explosions.
    exploding = true;
    nb_explosions = 0;
    next_explosion_date = System::now() + 2000;
  }
  else {
    // Replace the enemy sprites.
    clear_sprites();
    switch (get_ground_below()) {

      case GROUND_HOLE:
        // TODO animation of falling into a hole.
        Sound::play("jump");
        break;

      case GROUND_DEEP_WATER:
        // TODO water animation.
        Sound::play("splash");
        break;

      case GROUND_LAVA:
        // TODO lava animation.
        Sound::play("splash");
        break;

      default:
        create_sprite("enemies/enemy_killed");
        Sound::play("enemy_killed");
        break;
    }
  }

  // save the enemy state if required
  if (is_saved()) {
    get_savegame().set_boolean(savegame_variable, true);
  }
}
Ejemplo n.º 11
0
/**
 * @brief Updates the entity.
 */
void ShopItem::update() {

  if (is_looking_item && !get_game().is_dialog_enabled()) {

    // the description message has just finished
    const std::string question_dialog_id = "_shop.question";
    get_dialog_box().start_dialog(question_dialog_id);
    get_dialog_box().set_variable(question_dialog_id, price);
    is_asking_question = true;
    is_looking_item = false;
  }
  else if (is_asking_question && !get_game().is_dialog_enabled()) {

    // the question has just finished
    is_asking_question = false;
    int answer = get_dialog_box().get_last_answer();

    if (answer == 0) {

      // the player wants to buy the item
      Equipment& equipment = get_equipment();
      EquipmentItem& item = treasure.get_item();

      if (equipment.get_money() < price) {
        // not enough rupees
        Sound::play("wrong");
        get_dialog_box().start_dialog("_shop.not_enough_money");
      }
      else if (item.has_amount() && item.get_amount() >= item.get_max_amount()) {
        // the player already has the maximum amount of this item
        Sound::play("wrong");
        get_dialog_box().start_dialog("_shop.amount_full");
      }
      else {

        bool can_buy = get_lua_context().shop_item_on_buying(*this);
        if (can_buy) {

          // give the treasure
          equipment.remove_money(price);

          get_hero().start_treasure(treasure, LUA_REFNIL);
          if (treasure.is_saved()) {
            remove_from_map();
            get_savegame().set_boolean(treasure.get_savegame_variable(), true);
          }
          get_lua_context().shop_item_on_bought(*this);
        }
      }
    }
  }
}
Ejemplo n.º 12
0
/**
 * @brief Starts opening the door and plays the corresponding animations.
 *
 * Nothing is done if the door is already in the process of being open.
 */
void Door::open() {

  if (is_open() || is_opening()) {
    // The door is already open or being open: nothing to do.
    return;
  }

  set_opening();

  if (is_saved()) {
    get_savegame().set_boolean(savegame_variable, true);
  }
}
Ejemplo n.º 13
0
/**
 * @brief Starts closing the door and plays the corresponding animations.
 *
 * Nothing is done if the door is already in the process of being closed.
 */
void Door::close() {

  if (is_closed() || is_closing()) {
    // The door is already closed or being closed: nothing to do.
    return;
  }

  set_closing();

  if (is_saved()) {
    get_savegame().set_boolean(savegame_variable, false);
  }
}
Ejemplo n.º 14
0
/**
 * @brief Returns whether the player is able to open this chest now.
 * @return true if this is a small chest or if the player has the big key.
 */
bool Chest::can_open() {

  switch (get_opening_method()) {

    case OPENING_BY_INTERACTION:
      // No condition: the hero can always open the chest.
      return true;

    case OPENING_BY_INTERACTION_IF_SAVEGAME_VARIABLE:
    {
      // The hero can open the chest if a savegame variable is set.
      const std::string& required_savegame_variable = get_opening_condition();
      if (required_savegame_variable.empty()) {
        return false;
      }

      Savegame& savegame = get_savegame();
      if (savegame.is_boolean(required_savegame_variable)) {
        return savegame.get_boolean(required_savegame_variable);
      }

      if (savegame.is_integer(required_savegame_variable)) {
        return savegame.get_integer(required_savegame_variable) > 0;
      }

      if (savegame.is_string(required_savegame_variable)) {
        return !savegame.get_string(required_savegame_variable).empty();
      }

      return false;
    }

    case OPENING_BY_INTERACTION_IF_ITEM:
    {
      // The hero can open the chest if he has an item.
      const std::string& required_item_name = get_opening_condition();
      if (required_item_name.empty()) {
        return false;
      }
      const EquipmentItem& item = get_equipment().get_item(required_item_name);
      return item.is_saved()
        && item.get_variant() > 0
        && (!item.has_amount() || item.get_amount() > 0);
    }

    default:
      return false;
  }
}
Ejemplo n.º 15
0
/**
 * @brief Consumes the savegame variable or the equipment item that was required
 * to open the door.
 */
void Door::consume_opening_condition() {

  switch (get_opening_method()) {

    case OPENING_BY_INTERACTION_IF_SAVEGAME_VARIABLE:
    {
      // Reset or decrement the savegame variable that was required.
      const std::string& required_savegame_variable = get_opening_condition();
      Savegame& savegame = get_savegame();
      if (!required_savegame_variable.empty()) {
        if (savegame.is_boolean(required_savegame_variable)) {
          savegame.set_boolean(required_savegame_variable, false);
        }
        else if (savegame.is_integer(required_savegame_variable)) {
          int current_value = savegame.get_integer(required_savegame_variable);
          savegame.set_integer(required_savegame_variable, current_value - 1);
        }
        else if (savegame.is_string(required_savegame_variable)) {
          savegame.set_string(required_savegame_variable, "");
        }
      }
      break;
    }

    case OPENING_BY_INTERACTION_IF_ITEM:
    {
      // Remove the equipment item that was required.
      if (!opening_condition.empty()) {
        EquipmentItem& item = get_equipment().get_item(opening_condition);
        if (item.is_saved() && item.get_variant() > 0) {
          if (item.has_amount()) {
            item.set_amount(item.get_amount() - 1);
          }
          else {
            item.set_variant(0);
          }
        }
      }
      break;
    }

    default:
      // Ignored.
      break;
  }
}
Ejemplo n.º 16
0
/**
 * @brief Updates the chest.
 *
 * This function is called repeatedly by the map.
 * This is a redefinition of MapEntity::update()
 * the handle the chest opening.
 */
void Chest::update() {

  if (is_open() && !suspended) {

    if (!treasure_given && treasure_date != 0 && System::now() >= treasure_date) {

      treasure_date = 0;

      if (!treasure.is_empty()) {
        // give a treasure to the player

        get_hero().start_treasure(treasure, LUA_REFNIL);
        treasure_given = true;
      }
      else { // the chest is empty

        // mark the treasure as found in the savegame
        if (treasure.is_saved()) {
          get_savegame().set_boolean(treasure.get_savegame_variable(), true);
        }

        treasure_given = true;

        bool done = get_lua_context().chest_on_empty(*this);
        if (!done) {

          // the script does not define any behavior:
          // by default, we tell the player the chest is empty
          Sound::play("wrong");
          get_dialog_box().start_dialog("_empty_chest");
          get_hero().start_free();
        }
      }
    }
  }

  MapEntity::update();
}
Ejemplo n.º 17
0
/**
 * @brief Updates the chest.
 *
 * This function is called repeatedly by the map.
 * This is a redefinition of MapEntity::update()
 * the handle the chest opening.
 */
void Chest::update() {

  if (is_open() && !suspended) {

    if (!treasure_given && treasure_date != 0 && System::now() >= treasure_date) {

      treasure_date = 0;

      if (treasure.get_item_name() != "_none") {
        // give a treasure to the player

        get_hero().start_treasure(treasure);
        treasure_given = true;
      }
      else { // the chest is empty

        // mark the treasure as found in the savegame
        int savegame_variable = treasure.get_savegame_variable();
        if (savegame_variable != -1) {
          get_savegame().set_boolean(savegame_variable, true);
        }

        treasure_given = true;

        if (!get_map_script().event_chest_empty(get_name())) {

          // the script does not define any behavior:
          // by default, we tell the player the chest is empty
          Sound::play("wrong");
          get_dialog_box().start_dialog("_empty_chest");
          get_hero().start_free();
        }
      }
    }
  }

  MapEntity::update();
}
Ejemplo n.º 18
0
/**
 * \brief Saves the low-level joypad action where the specified game command
 * is mapped.
 * \param command A game command.
 * \return The joypad action to map to this game command in the savegame.
 */
void GameCommands::set_saved_joypad_binding(
    Command command, const std::string& joypad_string) {

  const std::string& savegame_variable = get_joypad_binding_savegame_variable(command);
  get_savegame().set_string(savegame_variable, joypad_string);
}
Ejemplo n.º 19
0
/**
 * \brief Determines from the savegame the low-level joypad action where the
 * specified game command is mapped.
 * \param command A game command.
 * \return The joypad action mapped to this game command in the savegame.
 */
const std::string& GameCommands::get_saved_joypad_binding(
    Command command) const {

  const std::string& savegame_variable = get_joypad_binding_savegame_variable(command);
  return get_savegame().get_string(savegame_variable);
}
Ejemplo n.º 20
0
/**
 * \brief Starts this game.
 */
void Game::start() {
  started = true;
  get_savegame().notify_game_started();
  get_lua_context().game_on_started(*this);
  get_lua_context().hero_on_state_changed(get_hero(), get_hero().get_state_name());
}
Ejemplo n.º 21
0
/**
 * \brief Handles the transitions.
 *
 * This functions changes the map when needed and plays the
 * transitions between the two maps. This function is called
 * by the update() function.
 * Note that the two maps can actually be the same.
 */
void Game::update_transitions() {

  if (transition != NULL) {
    transition->update();
  }

  // if the map has just changed, close the current map if any and play an out transition
  if (next_map != NULL && transition == NULL) { // the map has changed (i.e. set_current_map has been called)

    if (current_map == NULL) { // special case: no map was playing, so we don't have any out transition to do
      current_map = next_map;
      next_map = NULL;
    }
    else { // normal case: stop the control and play an out transition before leaving the current map
      transition = Transition::create(
          transition_style,
          Transition::TRANSITION_CLOSING,
          current_map->get_visible_surface(),
          this);
      transition->start();
    }
  }

  Rectangle previous_map_location = current_map->get_location();

  // if a transition was playing and has just been finished
  if (transition != NULL && transition->is_finished()) {

    Transition::Direction transition_direction = transition->get_direction();
    bool needs_previous_surface = transition->needs_previous_surface();
    delete transition;
    transition = NULL;

    MainLoop& main_loop = get_main_loop();
    if (restarting) {
      current_map->unload();
      main_loop.set_game(new Game(main_loop, savegame));
      RefCountable::unref(savegame);
      savegame = NULL;  // The new game is the owner.
    }
    else if (transition_direction == Transition::TRANSITION_CLOSING) {

      if (next_map == current_map) {
        // same map
        hero->place_on_destination(*current_map, previous_map_location);
        transition = Transition::create(
            transition_style,
            Transition::TRANSITION_OPENING,
            current_map->get_visible_surface(),
            this);
        transition->start();
        next_map = NULL;
      }
      else {

        // change the map
        current_map->leave();

        // special treatments for a transition between two different worlds
        // (e.g. outside world to a dungeon)
        if (!next_map->has_world() || next_map->get_world() != current_map->get_world()) {

          // reset the crystal blocks
          crystal_state = false;

          // Save the location except if this is a special destination.
          const std::string& destination_name = next_map->get_destination_name();
          if (destination_name != "_same"
              && destination_name.substr(0,5) != "_side") {
            get_savegame().set_string(Savegame::KEY_STARTING_MAP, next_map->get_id());
            get_savegame().set_string(Savegame::KEY_STARTING_POINT, destination_name);
          }
        }

        // before closing the map, draw it on a backup surface for transition effects
        // that want to display both maps at the same time
        if (needs_previous_surface) {
          previous_map_surface = Surface::create(
              Video::get_quest_size()
          );
          previous_map_surface->set_software_destination(false);
          RefCountable::ref(previous_map_surface);
          current_map->draw();
          current_map->get_visible_surface().draw(*previous_map_surface);
        }

        // set the next map
        current_map->unload();
        RefCountable::unref(current_map);

        current_map = next_map;
        next_map = NULL;
      }
    }
    else {
      current_map->notify_opening_transition_finished();

      RefCountable::unref(previous_map_surface);
      previous_map_surface = NULL;
    }
  }

  // if a map has just been set as the current map, start it and play the in transition
  if (started && !current_map->is_started()) {
    Debug::check_assertion(current_map->is_loaded(), "This map is not loaded");
    transition = Transition::create(
        transition_style,
        Transition::TRANSITION_OPENING,
        current_map->get_visible_surface(),
        this);

    if (previous_map_surface != NULL) {
      // some transition effects need to display both maps simultaneously
      transition->set_previous_surface(previous_map_surface);
    }

    hero->place_on_destination(*current_map, previous_map_location);
    transition->start();
    current_map->start();
    notify_map_changed();
  }
}
Ejemplo n.º 22
0
/**
 * \brief Returns the equipment of the player.
 *
 * It is equivalent to get_savegame().get_equipment().
 *
 * \return The equipment.
 */
const Equipment& Game::get_equipment() const {
  return get_savegame().get_equipment();
}