void visual::on_malfunction_changed( malfunction_kind_t kind )
    {
        if (kind == MF_FIRE_ON_BOARD || kind == MF_SMOKE_ON_BOARD)
        {
            visual_system* vsys = dynamic_cast<visual_system*>(sys_);

            bool has_smoke = malfunction(MF_FIRE_ON_BOARD) || malfunction(MF_SMOKE_ON_BOARD);

            if (!smoke_object_ && has_smoke && engine_node_)
            {
                smoke_object_ = vsys->create_visual_object(nm::node_control_ptr(engine_node_),"sfx//smoke.scg");
            }


        }
    }
    void visual::update(double time)
    {
        view::update(time);
        update_len(time);

        double dt = time - (last_update_ ? *last_update_ : 0);
        //if (cg::eq_zero(dt))
        //    return;

        bool has_smoke = malfunction(MF_FIRE_ON_BOARD) || malfunction(MF_SMOKE_ON_BOARD);
        
        //if (has_smoke)
        //{
        //    last_fire_time_ = time;
        //}

        geo_base_3 base = dynamic_cast<visual_system_props*>(sys_)->vis_props().base_point;
        geo_base_3 root_pos = root()->get_global_pos();
        quaternion root_orien = root()->get_global_orien();

        
        if (smoke_object_ && engine_node_)
        {
            if (nodes_management::vis_node_info_ptr(root())->is_visible())
            {
                geo_base_3 node_pos   = engine_node_->get_global_pos();
                quaternion node_orien = engine_node_->get_global_orien();
                point_3f   pos        = base(node_pos);

                quaternion sr = from_osg_quat(smoke_object_->node()->asTransform()->asMatrixTransform()->getMatrix().getRotate());
                const float angular_speed = 3 * 2 * osg::PI/60.0;
                quaternion des_orien;
                des_orien = sr * quaternion(cpr(cg::rad2grad() * angular_speed * dt,0,0));
                quaternion omega_rel     = cg::get_rotate_quaternion(node_orien,des_orien)/*.rot_axis().omega()*/ / (dt);                
                
                // smoke_object_->node()->as_transform()->set_transform(cg::transform_4f(cg::as_translation(pos), cg::rotation_3f(node_orien.rotation())));
                // smoke_object_->node()->asTransform()->asMatrixTransform()->setMatrix(to_osg_transform(cg::transform_4f(cg::as_translation(pos), cg::rotation_3f(des_orien.rotation()/*node_orien.rotation()*/))));
                
                smoke_object_->set_visible(true);

            }
            else
                smoke_object_->set_visible(false);
        }

        last_update_ = time;
    }
void model::on_malfunction_changed( aircraft::malfunction_kind_t kind ) 
{
    if (kind == aircraft::MF_CHASSIS_FRONT)
    {
        shassis_->set_malfunction(aircraft::SG_FRONT, malfunction(kind));
    }
    else if (kind == aircraft::MF_CHASSIS_REAR_LEFT)
    {
        shassis_->set_malfunction(aircraft::SG_REAR_LEFT, malfunction(kind));
    }
    else if (kind == aircraft::MF_CHASSIS_REAR_RIGHT)
    {
        shassis_->set_malfunction(aircraft::SG_REAR_RIGHT, malfunction(kind));
    }
    else if (kind == aircraft::MF_ONE_ENGINE || kind == aircraft::MF_ALL_ENGINES)
    {
        double factor = 1;
        if (malfunction(aircraft::MF_ALL_ENGINES))
            factor = 0;
        else if (malfunction(aircraft::MF_ONE_ENGINE))
        {
            factor = 0.7;
            FIXME(Test)
            rotors_->set_malfunction(aircraft::RG_REAR_LEFT,malfunction(kind));
        }
        // FIXME TODO OR NOT TODO
        //auto controls = flight_manager_control_->get_controls();
        //controls.engine_factor = factor;
        //flight_manager_control_->set_controls(controls);
    }
    else if (kind == aircraft::MF_FUEL_LEAKING)
    {   
        // FIXME TODO OR NOT TODO
        //auto controls = flight_manager_control_->get_controls();
        //controls.fuel_leaking = true;
        //flight_manager_control_->set_controls(controls);
    }
}