Esempio n. 1
0
/**
 * \brief Unregisters all menus associated to a context.
 *
 * This function can be called safely even while iterating on the menus list.
 *
 * \param context_index Index of a table or userdata containing menus.
 */
void LuaContext::remove_menus(int context_index) {

  const void* context;
  if (lua_type(l, context_index) == LUA_TUSERDATA) {
    ExportableToLuaPtr* userdata = static_cast<ExportableToLuaPtr*>(
        lua_touserdata(l, context_index));
    context = userdata->get();
  }
  else {
    context = lua_topointer(l, context_index);
  }

  // Some menu:on_finished() callbacks may create menus themselves,
  // and we don't want those new menus to get removed.
  for (LuaMenuData& menu: menus) {
    menu.recently_added = false;
  }

  for (LuaMenuData& menu: menus) {
    ScopedLuaRef menu_ref = menu.ref;
    if (menu.context == context && !menu.recently_added) {
      menu.ref.clear();
      menu.context = nullptr;
      menu_on_finished(menu_ref);
    }
  }
}
Esempio n. 2
0
/**
 * \brief Calls the on_draw() method of the menus associated to a context.
 * \param context_index Index of an object with menus.
 * \param dst_surface The destination surface to draw.
 */
void LuaContext::menus_on_draw(int context_index, const SurfacePtr& dst_surface) {

  const void* context;
  if (lua_type(l, context_index) == LUA_TUSERDATA) {
    ExportableToLuaPtr* userdata = static_cast<ExportableToLuaPtr*>(
        lua_touserdata(l, context_index));
    context = userdata->get();
  }
  else {
    context = lua_topointer(l, context_index);
  }

  for (LuaMenuData& menu: menus) {
    if (menu.context == context) {
      menu_on_draw(menu.ref, dst_surface);
    }
  }
}
Esempio n. 3
0
/**
 * \brief Unregisters all timers associated to a context.
 *
 * This function can be called safely even while iterating on the timer list.
 *
 * \param context_index Index of a table or userdata containing timers.
 */
void LuaContext::remove_timers(int context_index) {

  const void* context;
  if (lua_type(l, context_index) == LUA_TUSERDATA) {
    ExportableToLuaPtr* userdata = static_cast<ExportableToLuaPtr*>(
        lua_touserdata(l, context_index));
    context = userdata->get();
  }
  else {
    context = lua_topointer(l, context_index);
  }

  for (auto& kvp: timers) {
    const TimerPtr& timer = kvp.first;
    if (kvp.second.context == context) {
      kvp.second.callback_ref.clear();
      timers_to_remove.push_back(timer);
    }
  }
}
Esempio n. 4
0
/**
 * \brief Calls the on_input() method of the menus associated to a context.
 * \param context_index Index of an object with menus.
 * \param event The input event to handle.
 * \return \c true if the event was handled and should stop being propagated.
 */
bool LuaContext::menus_on_input(int context_index, const InputEvent& event) {

  const void* context;
  if (lua_type(l, context_index) == LUA_TUSERDATA) {
    ExportableToLuaPtr* userdata = static_cast<ExportableToLuaPtr*>(
        lua_touserdata(l, context_index));
    context = userdata->get();
  }
  else {
    context = lua_topointer(l, context_index);
  }

  bool handled = false;
  std::list<LuaMenuData>::reverse_iterator it;
  for (it = menus.rbegin(); it != menus.rend() && !handled; ++it) {
    const ScopedLuaRef& menu_ref = it->ref;
    if (it->context == context) {
      handled = menu_on_input(menu_ref, event);
    }
  }

  return handled;
}
Esempio n. 5
0
/**
 * \brief Registers a menu into a context (table or a userdata).
 *
 * This function can be called safely even while iterating on the menus list.
 *
 * \param menu_ref Lua ref of the menu to add.
 * \param context_index Index of the table or userdata in the stack.
 * \param on_top \c true to place this menu on top of existing one in the
 * same context, \c false to place it behind.
 */
void LuaContext::add_menu(
    const ScopedLuaRef& menu_ref,
    int context_index,
    bool on_top
) {
  const void* context;
  if (lua_type(l, context_index) == LUA_TUSERDATA) {
    ExportableToLuaPtr* userdata = static_cast<ExportableToLuaPtr*>(
        lua_touserdata(l, context_index));
    context = userdata->get();
  }
  else {
    context = lua_topointer(l, context_index);
  }

  if (on_top) {
    menus.emplace_back(menu_ref, context);
  }
  else {
    menus.emplace_front(menu_ref, context);
  }

  menu_on_started(menu_ref);
}
Esempio n. 6
0
/**
 * \brief Registers a timer into a context (table or a userdata).
 * \param timer A timer.
 * \param context_index Index of the table or userdata in the stack.
 * \param callback_ref Lua ref to the function to call when the timer finishes.
 */
void LuaContext::add_timer(
    const TimerPtr& timer,
    int context_index,
    const ScopedLuaRef& callback_ref
) {
  const void* context;
  if (lua_type(l, context_index) == LUA_TUSERDATA) {
    ExportableToLuaPtr* userdata = static_cast<ExportableToLuaPtr*>(
        lua_touserdata(l, context_index)
    );
    context = userdata->get();
  }
  else {
    context = lua_topointer(l, context_index);
  }

  callback_ref.push();

#ifndef NDEBUG
  // Sanity check: check the uniqueness of the ref.
  for (const auto& kvp: timers) {
    if (kvp.second.callback_ref.get() == callback_ref.get()) {
      std::ostringstream oss;
      oss << "Callback ref " << callback_ref.get()
          << " is already used by a timer (duplicate luaL_unref?)";
      Debug::die(oss.str());
    }
  }
#endif

  Debug::check_assertion(timers.find(timer) == timers.end(),
      "Duplicate timer in the system");

  timers[timer].callback_ref = callback_ref;
  timers[timer].context = context;

  Game* game = main_loop.get_game();
  if (game != nullptr) {
    // We are during a game: depending on the timer's context,
    // suspend the timer or not.
    if (is_map(l, context_index)
        || is_entity(l, context_index)
        || is_item(l, context_index)) {

      bool initially_suspended = false;

      // By default, we want the timer to be automatically suspended when a
      // camera movement, a dialog or the pause menu starts.
      if (!is_entity(l, context_index)) {
        // The timer normally gets suspended/resumed with the map.
        timer->set_suspended_with_map(true);

        // But in the initial state, we override that rule.
        // We initially suspend the timer only during a dialog.
        // In particular, we don't want to suspend timers created during a
        // camera movement.
        // This would be very painful for users.
        initially_suspended = game->is_dialog_enabled();
      }
      else {
        // Entities are more complex: they also get suspended when disabled
        // and when far from the camera. Therefore, they don't simply follow
        // the map suspended state.
        EntityPtr entity = check_entity(l, context_index);
        initially_suspended = entity->is_suspended() || !entity->is_enabled();
      }

      timer->set_suspended(initially_suspended);
    }
  }
}