void scene_view::delete_selected()
{
    const auto &sel_paths = m_selection["paths"];

    if (m_mode == mode_path && !sel_paths.empty())
    {
        int idx = *sel_paths.rbegin();
        if (idx >= (int)m_paths.size())
            return;

        if (!m_paths[idx].points.empty())
            m_paths[idx].points.pop_back();

        if (m_paths[idx].points.empty())
        {
            m_paths.erase(m_paths.begin() + idx);
            update_objects_tree();
        }
        update();
    }

    if (m_mode != mode_edit)
        return;

    for (auto p = sel_paths.rbegin(); p != sel_paths.rend(); ++p)
    {
        if (*p >= m_paths.size())
            continue;

        m_paths.erase(m_paths.begin() + *p);
    }

    const auto &sel_zones = m_selection["zones"];
    for (auto z = sel_zones.rbegin(); z != sel_zones.rend(); ++z)
    {
        if (*z >= m_zones.size())
            continue;

        m_zones.erase(m_zones.begin() + *z);
        m_zones_internal.erase(m_zones_internal.begin() + *z);
    }

    const auto &sel_objects = m_selection["objects"];
    for (auto o = sel_objects.rbegin(); o != sel_objects.rend(); ++o)
    {
        if (*o >= m_objects.size())
            continue;

        m_objects.erase(m_objects.begin() + *o);
    }

    update_objects_tree();
    update();
}
void scene_view::mousePressEvent(QMouseEvent *event)
{
    auto btns = event->buttons();
    const bool mouse_left = btns.testFlag(Qt::LeftButton);

    if (m_mode == mode_add && mouse_left && !m_selected_add.id.empty())
    {
        m_objects.push_back(m_selected_add);
        m_objects.back().name = new_name("object", m_objects);
        update_objects_tree();
    }

    if (m_mode == mode_zone && mouse_left)
    {
        add_zone(m_zone_add);
        m_zones.back().name = new_name("zone", m_zones);
        update_objects_tree();
    }

    if (m_mode == mode_path && mouse_left)
    {
        auto p0 = nya_math::vec4(m_cursor_pos, m_selected_add.y);
        const auto &sel_paths = m_selection["paths"];
        if (sel_paths.empty())
        {
            path p;
            p.name = new_name("path", m_paths);
            p.points.push_back(p0);
            m_paths.push_back(p);
            update_objects_tree();
            set_selection("paths", m_paths.size() - 1);
        }
        else
        {
            int idx = *sel_paths.rbegin();
            if (idx < (int)m_paths.size())
            {
                m_paths[idx].points.push_back(p0);
                set_selection("paths", idx);
            }
        }
    }

    m_mouse_x = event->localPos().x();
    m_mouse_y = event->localPos().y();

    update();
}
void main_window::on_new_mission()
{
    QStringList items;
    auto &list = game::get_locations_list();
    for (auto &l: list)
    {
        auto str = QString::fromStdString(l.second);
        str.append((" [" + l.first + "]").c_str());
        items << str;
    }

    bool ok = false;
    QString item = QInputDialog::getItem(this, "Select location", "Location:", items, 0, false, &ok);
    if (!ok || item.isEmpty())
        return;

    const int idx = items.indexOf(item);
    if (idx < 0 || idx >= (int)list.size())
        return;

    m_filename.clear();
    clear_mission();
    m_location = list[idx].first;
    m_scene_view->load_location(m_location);
    scene_view::object p;
    p.attributes["align"] = "ally";
    p.pos.y = m_scene_view->get_height(p.pos.x, p.pos.z);
    p.y = 100.0f;
    m_scene_view->set_player(p);
    update_objects_tree();

    m_script_edit->setText("--Open-Horizon mission script\n\n"
                           "function init()\n"
                           "    --do init here\n"
                           "end\n");

    m_mission_title->setText("Mission");

    m_navigator->setCurrentIndex(mode_info);

    m_scene_view->set_focus("player spawn", 0);
}
void main_window::on_load_mission()
{
    auto filename = QFileDialog::getOpenFileName(this, "Load mission", "missions", "*.zip");
    if (!filename.length())
        return;

    std::string filename_str = to_str(filename);

    auto prov = &nya_resources::get_resources_provider();
    nya_resources::file_resources_provider fprov;
    nya_resources::set_resources_provider(&fprov);
    nya_resources::zip_resources_provider zprov;
    bool result = zprov.open_archive(filename_str.c_str());
    nya_resources::set_resources_provider(prov);
    if (!result)
    {
        alert("Unable to load location " + filename_str);
        return;
    }

    m_filename.assign(filename_str);

    pugi::xml_document doc;
    if (!load_xml(zprov.access("objects.xml"), doc))
        return;

    auto root = doc.first_child();
    std::string loc = root.attribute("location").as_string();
    if (loc.empty())
        return;

    clear_mission();

    m_location = loc;
    m_scene_view->load_location(loc);

    auto p = root.child("player");
    scene_view::object plr;
    plr.attributes["align"] = "ally";
    plr.yaw = p.attribute("yaw").as_float();
    plr.pos = read_vec3(p);
    plr.y = p.attribute("editor_y").as_float();
    plr.pos.y -= plr.y;
    auto at = p.child("attribute");
    for (auto a = at.attributes_begin(); a != at.attributes_end(); ++a)
        plr.attributes[a->name()] = a->value();

    m_scene_view->set_player(plr);

    for (auto o = root.child("object"); o; o = o.next_sibling("object"))
    {
        scene_view::object obj;
        obj.name = o.attribute("name").as_string();
        obj.id = o.attribute("id").as_string();
        obj.active = o.attribute("active").as_bool();
        obj.yaw = o.attribute("yaw").as_float();
        obj.pos = read_vec3(o);
        obj.y = o.attribute("editor_y").as_float();
        obj.pos.y -= obj.y;

        auto at = o.child("attribute");
        for (auto a = at.attributes_begin(); a != at.attributes_end(); ++a)
            obj.attributes[a->name()] = a->value();
        m_scene_view->add_object(obj);
    }

    for (auto z = root.child("zone"); z; z = z.next_sibling("zone"))
    {
        scene_view::zone zn;
        zn.name = z.attribute("name").as_string();
        zn.active = z.attribute("active").as_bool();
        zn.radius = z.attribute("radius").as_float();
        zn.pos = read_vec3(z);
        auto at = z.child("attribute");
        for (auto a = at.attributes_begin(); a != at.attributes_end(); ++a)
            zn.attributes[a->name()] = a->value();
        m_scene_view->add_zone(zn);
    }

    for (auto p = root.child("path"); p; p = p.next_sibling("path"))
    {
        scene_view::path pth;
        pth.name = p.attribute("name").as_string();
        for (auto p0 = p.child("point"); p0; p0 = p0.next_sibling("point"))
        {
            nya_math::vec4 p;
            p.xyz() = read_vec3(p0);
            p.w = p0.attribute("editor_y").as_float();
            p.y -= p.w;
            pth.points.push_back(p);
        }
        m_scene_view->get_paths().push_back(pth);
    }

    auto script_res = zprov.access("script.lua");
    if (script_res)
    {
        std::string script;
        script.resize(script_res->get_size());
        if (!script.empty())
            script_res->read_all(&script[0]);
        m_script_edit->setText(script.c_str());
        script_res->release();
    }

    if (load_xml(zprov.access("info.xml"), doc))
    {
        auto root = doc.first_child();

        m_mission_title->setText(root.attribute("name").as_string());
        m_mission_description->setText(root.child("description").first_child().value());

        auto author = root.child("author");
        m_mission_author->setText(author.attribute("name").as_string());
        m_mission_email->setText(author.attribute("email").as_string());
    }

    update_objects_tree();
    m_navigator->setCurrentIndex(mode_info);

    m_scene_view->set_focus("player spawn", 0);
}