--*********************************************************************************************************************
--*********************************************************************************************************************
function public.Init()

  cmn.gamemode_types = { "casual", "advanced", "hardcore", "custom" };

  game = {};
  game.hint = {};

  public.is_in_map = 0;
  ----------------------------------------------------------------------------------
  private.LoadStandardCursors();
  ----------------------------------------------------------------------------------
  common.SetCheaterKeyF( 1, "level1" );
  --common.SetCheaterKeyF( 2, "level2" );
  --common.SetCheaterKeyF( 5, "levelext" );
  ----------------------------------------------------------------------------------
  ----------------------------------------------------------------------------------
  ng_global.noskipgames = {};   --таблица МИ и ММИ пройденных без скипа
  ng_global.start_room = {};

  public.achiev = {};
  ng_global.achiev = {};

  ng_global.achiev[ "collect_1_flower" ] = {0, 0, 1};
  ng_global.achiev[ "collect_5_flowers" ] = {0, 0, 1};
  ng_global.achiev[ "collect_15_flowers" ] = {0, 0, 1};
  ng_global.achiev[ "collect_30_flowers" ] = {0, 0, 1};
  ng_global.achiev[ "collect_100_flowers" ] = {0, 0, 1};
  ng_global.achiev[ "collect_200_flowers" ] = {0, 0, 1};
  ng_global.achiev[ "collector" ] = {0, 0, 1};

  ng_global.achiev[ "one_mg_without_skip" ] = {0, 0, 1};
  ng_global.achiev[ "three_mg_without_skip" ] = {0, 0, 3};
  ng_global.achiev[ "seven_mg_without_skip" ] = {0, 0, 5};
  ng_global.achiev[ "fifteen_mg_without_skip" ] = {0, 0, 10};
  ng_global.achiev[ "all_mg_without_skip" ] = {0, 0, 52};

  ng_global.achiev[ "one_ho_without_hint" ] = {0, 0, 1};
  ng_global.achiev[ "three_ho_without_hint" ] = {0, 0, 3};
  ng_global.achiev[ "five_ho_without_hint" ] = {0, 0, 5};
  ng_global.achiev[ "ten_ho_without_hint" ] = {0, 0, 10};
  ng_global.achiev[ "all_ho_without_hint" ] = {0, 0, 14};

  ng_global.achiev[ "three_ho_three_min" ] = {0, 0, 1};
  ng_global.achiev[ "five_ho_three_min" ] = {0, 0, 1};
  ng_global.achiev[ "ten_ho_three_min" ] = {0, 0, 1};

  ng_global.achiev[ "one_mg_less_one_min" ] = {0, 0, 1};
  ng_global.achiev[ "one_ho_less_one_min" ] = {0, 0, 1};
  ng_global.achiev[ "one_ho_more_ten_min" ] = {0, 0, 1};

  ng_global.achiev[ "three_item_ho" ] = {0, 0, 1};
  ng_global.achiev[ "five_item_ho" ] = {0, 0, 1};
  ng_global.achiev[ "ten_item_ho" ] = {0, 0, 1};

  --ng_global.rm_alicehome_state =
  --  {
  --    [ "flowers_on_table" ]   = 0,
  --    [ "toys_for_cat" ]       = 0,
  --    [ "door_with_curtain" ]  = 0,
  --    [ "bear" ]               = 0,
  --    [ "picture_of_friends" ] = 0,
  --    [ "coffee_table" ]       = 0,
  --    [ "wall_paper" ]         = 0,
  --    [ "chandeliers" ]        = 0,
  --    [ "sofa_covering" ]      = 0,
  --    [ "bookcase" ]           = 0,
  --    [ "pillows" ]            = 0,
  --    [ "diplomas" ]           = 0,
  --    [ "printer" ]            = 0,
  --    [ "basket_for_cat" ]     = 0,
  --    [ "laptop" ]             = 0,
  --    [ "complete_kitchen" ]   = 0
  --  };

  ng_global.state_ho = {0, 0, 0,
                        0, 0, 0,
                        0, 0, 0,
                        0, 0, 0,
                        0, 0, 0};

  ng_global.global_task = 0;

  ----------------------------------------------------------------------------------
  ----------------------------------------------------------------------------------
  public.animtime = 0.3;

  common.dialog.options.slider_width = 210;

  cmn.SetEventDone     = public.SetEventDone;
  cmn.IsEventDone      = public.IsEventDone;
  cmn.SetEventStart    = public.SetEventStart;
  cmn.IsEventStart     = public.IsEventStart;
  cmn.HoTaskFind       = public.HoTaskFind;
  cmn.HoItemFind       = public.HoItemFind;
  cmn.MiniGameHide     = public.MiniGameHide;
  cmn.MiniGameShow     = public.MiniGameShow;
  cmn.SetMarkedTask    = public.SetMarkedTask;
  cmn.UnmarkTask       = public.UnmarkTask;
  cmn.IsUnmarkedTask   = public.IsUnmarkedTask;
  cmn.InitHo           = public.InitHo;
  cmn.GotoRoom         = common.GotoRoom;
  cmn.GotoSubRoom      = common.GotoSubRoom;
  cmn.GetObjectPrefix  = common.GetObjectPrefix;
  cmn.GetObjectName    = common.GetObjectName;
  cmn.DialogWindowShow = common.DialogWindowShow;
  cmn.LevelSwitch      = common.LevelSwitch;
  ------------------------------------------------
  common.dialog.common.ThxPlaying = public.DialogCommonThxPlaying;
  common.dialog.options.Close = public.DialogOptionsClose;
  common.dialog.custom = {};
  common.dialog.custom.Open = public.DialogCustomOpen;
  common.dialog.help = {};
  common.dialog.help.Open = public.DialogHelpOpen;
  ------------------------------------------------
  cmn.IsSubscribersIncluded = public.IsSubscribersIncluded;   --нужно для читера
  cmn.AddSubscribersToQueue = common.AddSubscribersToQueue;
  cmn.ExecuteQueue          = common.CallRoomEventHandlers;
  ------------------------------------------------

  cmn.ObjIntersectCheck   = public.ObjIntersectCheck;
  cmn.GetMultyObject      = public.GetMultyObject;
  cmn.CheckMultiObject    = public.CheckMultiObject;
  cmn.Lock                = public.Lock;
  cmn.PlayFullscreenVideo = public.PlayFullscreenVideo;
  cmn.WrongApply          = public.WrongApply;
  cmn.ShowBbt             = public.ShowBbt;
  cmn.ShowDlgBbt          = public.ShowDlgBbt;
  cmn.ShowNote            = public.ShowNote;
  cmn.HideNote            = public.HideNote;
  cmn.GetCurrentNote      = public.GetCurrentNote;

  cmn.PlayAudio           = public.PlayAudio;
  cmn.StopAllEnv          = public.StopAllEnv;
  cmn.StopAllMus          = public.StopAllMus;
  cmn.PauseAllEnv         = public.PauseAllEnv;
  cmn.UnPauseAllEnv       = public.UnPauseAllEnv;
  cmn.PlayCutScene        = public.PlayCutScene;

  cmn.TutorialShow        = public.tutorial.TutorialShow;
  cmn.GotoRoomMDown       = public.GotoRoomMDown;
  cmn.GotoRoomMUp         = public.GotoRoomMUp;
  cmn.GotoSubRoomMDown    = public.GotoSubRoomMDown;
  cmn.GotoSubRoomMUp      = public.GotoSubRoomMUp;

  cmn.ShowPopupInv        = public.ShowPopupInv;
  cmn.HidePopupInv        = public.HidePopupInv;
  cmn.ShowCursor          = public.ShowCursor;
  cmn.ApplyObj            = public.ApplyObj;

  cmn.achiev              = public.achiev;
  cmn.StartTimePassing    = public.StartTimePassing;
  cmn.EndTimePassing      = public.EndTimePassing;

  private.HintInit();
  
end;
function public.IsSubscribersIncluded()

  return true;

end;
function private.LoadStandardCursors()

  --[[
  case 0:  pWinCursor = NULL; break;
  case 1:  pWinCursor = IDC_APPSTARTING; break;
  case 2:  pWinCursor = IDC_ARROW; break;
  case 3:  pWinCursor = IDC_CROSS; break;
  case 4:  pWinCursor = IDC_HAND; break;
  case 5:  pWinCursor = IDC_HELP; break;
  case 6:  pWinCursor = IDC_IBEAM; break;
  case 7:  pWinCursor = IDC_ICON; break;
  case 8:  pWinCursor = IDC_NO; break;
  case 9:  pWinCursor = IDC_SIZE; break;
  case 10: pWinCursor = IDC_SIZEALL; break;
  case 11: pWinCursor = IDC_SIZENESW; break;
  case 12: pWinCursor = IDC_SIZENS; break;
  case 13: pWinCursor = IDC_SIZEWE; break;
  case 14: pWinCursor = IDC_UPARROW; break;
  case 15: pWinCursor = IDC_WAIT; break;
  ]]

  common.CursorLoad( "CURSOR_NULL",    "",                            0  );
  common.CursorLoad( "CURSOR_DEFAULT", "assets/cursors/cursor",       2  );
  common.CursorLoad( "CURSOR_LOUPE",   "assets/cursors/cursor_loupe", 10 );
  common.CursorLoad( "CURSOR_GET",     "assets/cursors/cursor_get",   4  );
  common.CursorLoad( "CURSOR_HAND",    "assets/cursors/cursor_hand",  4  );
  common.CursorLoad( "CURSOR_USE",     "assets/cursors/cursor_use",   4  );
  common.CursorLoad( "CURSOR_DOWN",    "assets/cursors/cursor_down",  10 );
  common.CursorLoad( "CURSOR_UP",      "assets/cursors/cursor_up",    10 );
  common.CursorLoad( "CURSOR_LEFT",    "assets/cursors/cursor_left",  10 );
  common.CursorLoad( "CURSOR_RIGHT",   "assets/cursors/cursor_right", 10 );
  common.CursorLoad( "CURSOR_FINGER",  "assets/cursors/cursor_finger",10 );

end;
--*********************************************************************************************************************
--***function *** DIALOG *** () end************************************************************************************
--*********************************************************************************************************************
  --------------------------------------------------------------------
  function public.DialogButtonMouseDown( dialog_name, dialog_button, param )

    DbgTrace( "[ EXAMPLE ] Проигран звук клика для диалога < "..dialog_name.." > по кнопке < "..dialog_button.." >." );

  end;
  --------------------------------------------------------------------
  function public.DialogButtonMouseEnter( dialog_name, but_side )

    SetCursor( CURSOR_HAND );
    local but_name = "spr_dialog_"..dialog_name.."_button_"..but_side.."_focus";
    local but_alp = ObjGet( but_name ).alp;
    ObjAnimate( but_name, "alp", 0, 0, "", { 0, 0, but_alp, ( public.animtime * ( 1 - but_alp ) ), 0, 1 } );

  end;
  --------------------------------------------------------------------
  function public.DialogButtonMouseLeave( dialog_name, but_side )

    SetCursor( CURSOR_DEFAULT );
    local but_name = "spr_dialog_"..dialog_name.."_button_"..but_side.."_focus";
    local but_alp = ObjGet( but_name ).alp;
    ObjAnimate( but_name, "alp", 0, 0, "", { 0, 0, but_alp, ( public.animtime * but_alp ), 0, 0 } );

  end;
  --------------------------------------------------------------------
  function public.DialogCheckMouseEnter( sender_name )
    
    SetCursor( CURSOR_HAND );    
    local but_name = "spr_dialog_"..sender_name.."_check_focus";
    local but_alp = ObjGet( but_name ).alp;
    ObjAnimate( but_name, "alp", 0, 0, "", { 0, 0, but_alp, ( public.animtime * ( 1 - but_alp ) ), 0, 1 } );

  end;
  --------------------------------------------------------------------
  function public.DialogCheckMouseLeave( sender_name )

    SetCursor( CURSOR_DEFAULT );
    local but_name = "spr_dialog_"..sender_name.."_check_focus";
    local but_alp = ObjGet( but_name ).alp;
    ObjAnimate( but_name, "alp", 0, 0, "", { 0, 0, but_alp, ( public.animtime * but_alp ), 0, 0 } );

  end;
  --------------------------------------------------------------------
  function public.DialogOptionsScrollMouseEnter( scroll_name )
    
    SetCursor( CURSOR_HAND );    
    local but_name = "spr_dialog_options_"..scroll_name.."_scroll_slider_focus";
    local but_alp = ObjGet( but_name ).alp;
    ObjAnimate( but_name, "alp", 0, 0, "", { 0, 0, but_alp, ( public.animtime * ( 1 - but_alp ) ), 0, 1 } );

  end;
  --------------------------------------------------------------------
  function public.DialogOptionsScrollMouseLeave( scroll_name )

    SetCursor( CURSOR_DEFAULT );
    local but_name = "spr_dialog_options_"..scroll_name.."_scroll_slider_focus";
    local but_alp = ObjGet( but_name ).alp;
    ObjAnimate( but_name, "alp", 0, 0, "", { 0, 0, but_alp, ( public.animtime * but_alp ), 0, 0 } );

  end;
--*********************************************************************************************************************
--***function *** - common: () end ************************************************************************************
--*********************************************************************************************************************
  --------------------------------------------------------------------
  function public.DialogCommonThxPlaying()

    common.dialog.common.Close();
    cmn.LevelSwitch( "menu", "game" );

  end;
  --------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** - help: () end ************************************************************************************
--*********************************************************************************************************************
  --------------------------------------------------------------------
  function public.DialogHelpOpen()

    

  end;
  --------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** - options: () end ***********************************************************************************
--*********************************************************************************************************************
  --------------------------------------------------------------------
  function public.DialogOptionsClose( sender_name )

    --DbgTrace("***common_impl.DialogOptionsClose");

    common.LogTrace( "[ - ] Закрытие окна опций: сохранение настроек." );

    SaveProfiles();
    SaveSettings();
    common.DialogWindowHide( "options" );

    if ( sender_name == "left" ) then

      common.ApplicationClose();

      SetCursor( CURSOR_DEFAULT );
      common.LevelSwitch( "menu", "game" );

    elseif( sender_name == "right" ) then
    
      PauseLevel( 0 );

      public.DialogCustomUpdate();
    
    end;

  end;
  --------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** - custom: () end ************************************************************************************
--*********************************************************************************************************************
  ------------custom game mode default state----------------------
  --   ng_global.custom_gamemode = {item = 1, fx = 1, fx_ho = 1, icon = 1, tasks = 1, tutorial = 1, texts = 1, use_hint = 1, use_skip = 1, hint_rechange = 15, skip_time = 15 };
  ----------------------------------------------------------------
  private.dialog_custom_slider_width = 210;
  private.dialog_custom_slider_offx = 0;
  private.dialog_custom_is_slider_startdrag = false;
  private.dialog_custom_fx = { "assets/levels/common/fx/empty", "assets/levels/common/fx/sparkle_effect" };
  private.dialog_custom_fx_ho = { "assets/levels/common/fx/empty", "assets/levels/common/fx/ho_effect" };
  private.dialog_custom_items = {};
  ----------------------------------------------------------------
  function public.DialogCustomCheckDown(name)

    local CusTable = ng_global.custom_gamemode;
    local param = CusTable[name];
    param = math.abs(param-1);
    --DbgTrace(name..": "..param);
    ObjSet("spr_dialog_custom_"..name.."_check_light",{alp = param} )
    ng_global.custom_gamemode[name] = param;
    private.DialogCustomCheckScroll();

  end;
  ----------------------------------------------------------------
  function private.DialogCustomCheckScroll()

    if (ng_global.custom_gamemode.use_hint == 0) then
      ObjSet("dialog_custom_hint_rechange", {input = 0, color_r = 0.5, color_g = 0.5, color_b = 0.5})
    else
      ObjSet("dialog_custom_hint_rechange", {input = 1, color_r = 1, color_g = 1, color_b = 1})
    end;

    if (ng_global.custom_gamemode.use_skip == 0) then
      ObjSet("dialog_custom_skip_time", {input = 0, color_r = 0.5, color_g = 0.5, color_b = 0.5})
    else
      ObjSet("dialog_custom_skip_time", {input = 1, color_r = 1, color_g = 1, color_b = 1})
    end;

    local new_x_skip = (private.dialog_custom_slider_width/75)*ng_global.custom_gamemode.skip_time-15*(private.dialog_custom_slider_width/75);
    local new_x_hint = (private.dialog_custom_slider_width/75)*ng_global.custom_gamemode.hint_rechange-15*(private.dialog_custom_slider_width/75);

    ObjSet( "dialog_custom_hint_rechange_scroll_slider", { pos_x = new_x_hint });
    ObjSet( "spr_dialog_custom_hint_rechange_scroll_slider", { pos_x = new_x_hint });
    ObjSet( "dialog_custom_skip_time_scroll_slider", { pos_x = new_x_skip });
    ObjSet( "spr_dialog_custom_skip_time_scroll_slider", { pos_x = new_x_skip });

  end;
  ----------------------------------------------------------------
  function public.DialogCustomClose()

    --DbgTrace("***common_impl.DialogCustomClose");

    common.DialogWindowHide( "custom" );

    if ( not ng_global.progress[ "std" ].common.gamestart ) and not( common.dialog.options.is_open ) then

      cmn.DialogWindowShow( "gamemode", "newgame", true );
      common.dialog.gamemode.CheckDown('custom');

    else

      cmn.DialogWindowShow( "gamemode", "options", true );
      common.dialog.gamemode.CheckDown('custom');

      --cmn.DialogCustomUpdate();  
    end;

  end;
  ----------------------------------------------------------------
  function public.DialogCustomOpen()

    --DbgTrace("***common_impl.DialogCustomOpen");

    local CusTable = ng_global.custom_gamemode;

    for key, value in pairs(CusTable) do

      --DbgTrace(key..": "..CusTable[key]);

      ObjSet("spr_dialog_custom_"..key.."_check_light",{alp = CusTable[key]} )

    end;

    private.DialogCustomCheckScroll();
    
  end;
  --------------------------------------------------------------
  function public.DialogCustomUpdate()

    --DbgTrace("***common_impl.DialogCustomUpdate");

    local CusTable = ng_global.custom_gamemode;
    local FxTable = {}
    local FxHoTable = {}
    private.dialog_custom_items = {};

    --gamemode fx seach areas 
    for i = 1, #game.room_names, 1 do

      local room = cmn.GetObjectName( game.room_names[i] );

      --DbgTrace("room = "..room);

      private.DialogCustomGetItems( game.room_names[i] );

      local rel = ObjGetRelations( "obj_"..room.."_gates" );

      if rel.childs then

        local obj_prefix = "";

        for i = 1, #rel.childs, 1 do

          obj_prefix = cmn.GetObjectPrefix( rel.childs[i] );

          if obj_prefix == "gzz" or obj_prefix == "gmg" then

            table.insert( FxTable, rel.childs[i] );

          end;

          if obj_prefix == "gzz" then
            private.DialogCustomGetItems(string.gsub(rel.childs[i], "gzz_"..room, "zz"));
          end;
        
        end;

      end;

    end;

    --gamemode fx_ho seach areas 
    for i = 1,  #game.room_names, 1 do

      local room = cmn.GetObjectName( game.room_names[i] );

      --DbgTrace("room = "..room);

      local rel = ObjGetRelations("obj_"..room.."_gates");

      if rel.childs then

        for i = 1, #rel.childs, 1  do

          if cmn.GetObjectPrefix( rel.childs[i] ) == "gho" then

            table.insert( FxHoTable, rel.childs[i] );

          end;

        end; 

      end;

    end;

    if ng_global.gamemode == 3 then

      common.UpdateGameMode(0);

      --gamemode fx areas on/off
      for i = 1, #FxTable, 1 do
        ObjSet( FxTable[i], { res = private.dialog_custom_fx[ CusTable.fx + 1 ] } );
        --DbgTrace( FxTable[i].." = "..private.dialog_custom_fx[ CusTable.fx + 1 ] );
      end;

      for i = 1, #private.dialog_custom_items, 1 do
        --DbgTrace(""..private.dialog_custom_items[i]);
        ObjSet( private.dialog_custom_items[i], { res = private.dialog_custom_fx[ CusTable.fx + 1 ] } );
        --DbgTrace( FxTable[i].." = "..private.dialog_custom_fx[ CusTable.fx + 1 ] );
      end;

      --gamemode fx areas on/off
      for i = 1, #FxHoTable, 1 do
        ObjSet( FxHoTable[i], { res = private.dialog_custom_fx_ho[ CusTable.fx_ho + 1 ] } );
        --DbgTrace( FxHoTable[i].." = "..private.dialog_custom_fx_ho[ CusTable.fx_ho + 1 ] );
      end;

    elseif ng_global.gamemode == 0 then  

      --gamemode fx areas on/off
      for i = 1, #FxTable, 1 do
        ObjSet( FxTable[i], { res = private.dialog_custom_fx[2] } );
      end;

      for i = 1, #private.dialog_custom_items, 1 do
        --DbgTrace(""..private.dialog_custom_items[i]);
        ObjSet( private.dialog_custom_items[i], { res = private.dialog_custom_fx[2] } );
        --DbgTrace( FxTable[i].." = "..private.dialog_custom_fx[ CusTable.fx + 1 ] );
      end;

      --gamemode fx areas on/off
      for i = 1, #FxHoTable, 1 do
        ObjSet( FxHoTable[i], { res = private.dialog_custom_fx_ho[2] } );
      end;

    end;

  end;
  --------------------------------------------------------------------
  function public.DialogCustomScrollDown( scroll_name )

    -- позиция объекта относительно главного объекта
    local slider_objname = "dialog_custom_"..scroll_name.."_scroll_slider";
    local obj_x = GetObjPosByObj( "spr_"..slider_objname )[ 1 ];
    
    local cur_x = GetGameCursorPos()[ 1 ];
    local off_x = cur_x - obj_x;

    local new_x = ObjGet( "spr_"..slider_objname ).pos_x + off_x;

    if ( new_x < 0 ) then new_x = 0; end;
    if ( new_x > private.dialog_custom_slider_width ) then new_x = private.dialog_custom_slider_width; end;

    ObjSet( slider_objname, { pos_x = new_x });

    private.DialogCustomScrollSet( scroll_name, new_x );

  end;
  --------------------------------------------------------------------
  function public.DialogCustomScrollDrag( scroll_name )

    SetCursor( CURSOR_HAND );

    local cur_pos = GetGameCursorPos();

    if ( not private.dialog_custom_is_slider_startdrag ) then
      private.dialog_custom_is_slider_startdrag = true;
      local obj_x = ObjGet( "dialog_custom_"..scroll_name.."_scroll_slider" ).pos_x;
      private.dialog_custom_slider_offx = cur_pos[ 1 ] - obj_x;
    end;

    local new_x = cur_pos[ 1 ] - private.dialog_custom_slider_offx;

    if ( new_x < 0 ) then new_x = 0; end;
    if ( new_x > private.dialog_custom_slider_width ) then new_x = private.dialog_custom_slider_width; end;

    private.DialogCustomScrollSet( scroll_name, new_x );

  end;
  --------------------------------------------------------------------
  function public.DialogCustomScrollDrop( scroll_name )

    -- драг завершен
    private.dialog_custom_is_slider_startdrag = false;

    local new_x = ObjGet( "spr_dialog_custom_"..scroll_name.."_scroll_slider" ).pos_x;
    local new_y = ObjGet( "spr_dialog_custom_"..scroll_name.."_scroll_slider" ).pos_y;

    -- возвращаем drag-объект в позиции слайдера
    ObjSet( "dialog_custom_"..scroll_name.."_scroll_slider", { pos_x = new_x, pos_y = new_y });

    private.DialogCustomScrollSet( scroll_name, new_x );

  end;
  --------------------------------------------------------------------
  function private.DialogCustomScrollSet ( scroll_name, new_x )

    local percent = math.floor( ( new_x * 75 ) / private.dialog_custom_slider_width );
    --ObjSet( "txt_dialog_custom_"..scroll_name.."_percent", { text = percent.."%" } );
    ObjSet( "spr_dialog_custom_"..scroll_name.."_scroll_slider", { pos_x = new_x } );
    percent = percent + 15;
    if ( scroll_name == "hint_rechange" ) then
      ng_global.custom_gamemode.hint_rechange = percent;
    elseif ( scroll_name == "skip_time" ) then
      ng_global.custom_gamemode.skip_time = percent;
    end;

    --DbgTrace(percent);

  end;
  --------------------------------------------------------------------
  function public.DialogCustomScrollMouseEnter( scroll_name )

    SetCursor( CURSOR_HAND );    
    local but_name = "spr_dialog_custom_"..scroll_name.."_scroll_slider_focus";
    local but_alp = ObjGet( but_name ).alp;
    ObjAnimate( but_name, 8, 0, 0, "", { 0, 0, but_alp, ( public.animtime * ( 1 - but_alp ) ), 0, 1 } );

  end;
  --------------------------------------------------------------------
  function public.DialogCustomScrollMouseLeave( scroll_name )
   
    SetCursor( CURSOR_DEFAULT );
    local but_name = "spr_dialog_custom_"..scroll_name.."_scroll_slider_focus";
    local but_alp = ObjGet( but_name ).alp;
    ObjAnimate( but_name, 8, 0, 0, "", { 0, 0, but_alp, ( public.animtime * but_alp ), 0, 0 } );

  end;
  ---------------------------------------------------------------------
  function private.DialogCustomGetItems( room ) --рекурсивно находит все gfx_

    local rel = ObjGetRelations(room);

    if rel.childs then

      for i = 1, #rel.childs, 1  do

        if cmn.GetObjectPrefix( rel.childs[i] ) == "gfx" then

          table.insert( private.dialog_custom_items, rel.childs[i] );

        end;

        private.DialogCustomGetItems( rel.childs[i] );

      end;
    end;

  end;
  ---------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** PROFILE *** () end***********************************************************************************
--*********************************************************************************************************************
  function public.ProgressReset( prg, save )

    private.is_in_map = 0;
    ng_global.map_diary_pages = 0;
    ng_global.map_diary_current_page = 0;

    ng_global.start_room = {};

    ng_global.custom_gamemode = { item = 1, fx = 1, fx_ho = 1, icon = 1, tasks = 1, tutorial = 1, texts = 1, use_hint = 1, use_skip = 1, hint_rechange = 90, skip_time = 90 };

    if ( prg == "std" ) then

      ng_global.progress[ prg ].common.chapter = "level1";

    elseif( prg == "ext" ) then

      ng_global.progress[ prg ].common.chapter = "levelext";

    end;

    ng_global.ho_count = 0;

    ng_global.global_task = 0;

    if IsDemoEdition() or IsSurveyEdition() then

      ng_global.noskipgames = {};

      ng_global.collectable = {};

      public.achiev = {};
      ng_global.achiev = {};

      ng_global.achiev[ "collect_1_flower" ] = {0, 0, 1};
      ng_global.achiev[ "collect_5_flowers" ] = {0, 0, 1};
      ng_global.achiev[ "collect_15_flowers" ] = {0, 0, 1};
      ng_global.achiev[ "collect_30_flowers" ] = {0, 0, 1};
      ng_global.achiev[ "collect_100_flowers" ] = {0, 0, 1};
      ng_global.achiev[ "collect_200_flowers" ] = {0, 0, 1};
      ng_global.achiev[ "collector" ] = {0, 0, 1};

      ng_global.achiev[ "one_mg_without_skip" ] = {0, 0, 1};
      ng_global.achiev[ "three_mg_without_skip" ] = {0, 0, 3};
      ng_global.achiev[ "seven_mg_without_skip" ] = {0, 0, 5};
      ng_global.achiev[ "fifteen_mg_without_skip" ] = {0, 0, 10};
      ng_global.achiev[ "all_mg_without_skip" ] = {0, 0, 52};

      ng_global.achiev[ "one_ho_without_hint" ] = {0, 0, 1};
      ng_global.achiev[ "three_ho_without_hint" ] = {0, 0, 3};
      ng_global.achiev[ "five_ho_without_hint" ] = {0, 0, 5};
      ng_global.achiev[ "ten_ho_without_hint" ] = {0, 0, 10};
      ng_global.achiev[ "all_ho_without_hint" ] = {0, 0, 14};

      ng_global.achiev[ "three_ho_three_min" ] = {0, 0, 1};
      ng_global.achiev[ "five_ho_three_min" ] = {0, 0, 1};
      ng_global.achiev[ "ten_ho_three_min" ] = {0, 0, 1};

      ng_global.achiev[ "one_mg_less_one_min" ] = {0, 0, 1};
      ng_global.achiev[ "one_ho_less_one_min" ] = {0, 0, 1};
      ng_global.achiev[ "one_ho_more_ten_min" ] = {0, 0, 1};

      ng_global.achiev[ "three_item_ho" ] = {0, 0, 1};
      ng_global.achiev[ "five_item_ho" ] = {0, 0, 1};
      ng_global.achiev[ "ten_item_ho" ] = {0, 0, 1};

      --ng_global.rm_alicehome_state =
      --  {
      --    [ "flowers_on_table" ]   = 0,
      --    [ "toys_for_cat" ]       = 0,
      --    [ "door_with_curtain" ]  = 0,
      --    [ "bear" ]               = 0,
      --    [ "picture_of_friends" ] = 0,
      --    [ "coffee_table" ]       = 0,
      --    [ "wall_paper" ]         = 0,
      --    [ "chandeliers" ]        = 0,
      --    [ "sofa_covering" ]      = 0,
      --    [ "bookcase" ]           = 0,
      --    [ "pillows" ]            = 0,
      --    [ "diplomas" ]           = 0,
      --    [ "printer" ]            = 0,
      --    [ "basket_for_cat" ]     = 0,
      --    [ "laptop" ]             = 0,
      --    [ "complete_kitchen" ]   = 0
      --  };

      ng_global.state_ho = {0, 0, 0,
                            0, 0, 0,
                            0, 0, 0,
                            0, 0, 0,
                            0, 0, 0};

      ng_global.bonus = {};
      ng_global.bonus_count = 0;
      ng_global.bonus_count_total = 0;
      ng_global.bonus_count_counter = 0;
      ng_global.bonus_count_current = 0;
      ng_global.show_bonus = 0;

      for i = 1, 150, 1 do
        ng_global.bonus[i] = 0;
      end;

    end;

  end;
  --*********************************************************************************************************************
  function public.ProfileInit()

    ng_global.custom_gamemode = { item = 1, fx = 1, fx_ho = 1, icon = 1, tasks = 1, tutorial = 1, texts = 1, use_hint = 1, use_skip = 1, hint_rechange = 90, skip_time = 90 };

    ng_global.bonus = {};
    ng_global.bonus_count = 0;
    ng_global.bonus_count_total = 0;
    ng_global.bonus_count_counter = 0;
    ng_global.bonus_count_current = 0;
    ng_global.show_bonus = 0;

    for i = 1, 150, 1 do
      ng_global.bonus[i] = 0;
    end;

    ng_global.collectable = {};

    ng_global.achiev = {};

    ng_global.achiev[ "collect_1_flower" ] = {0, 0, 1};
    ng_global.achiev[ "collect_5_flowers" ] = {0, 0, 1};
    ng_global.achiev[ "collect_15_flowers" ] = {0, 0, 1};
    ng_global.achiev[ "collect_30_flowers" ] = {0, 0, 1};
    ng_global.achiev[ "collect_100_flowers" ] = {0, 0, 1};
    ng_global.achiev[ "collect_200_flowers" ] = {0, 0, 1};
    ng_global.achiev[ "collector" ] = {0, 0, 1};

    ng_global.achiev[ "one_mg_without_skip" ] = {0, 0, 1};
    ng_global.achiev[ "three_mg_without_skip" ] = {0, 0, 3};
    ng_global.achiev[ "seven_mg_without_skip" ] = {0, 0, 5};
    ng_global.achiev[ "fifteen_mg_without_skip" ] = {0, 0, 10};
    ng_global.achiev[ "all_mg_without_skip" ] = {0, 0, 52};

    ng_global.achiev[ "one_ho_without_hint" ] = {0, 0, 1};
    ng_global.achiev[ "three_ho_without_hint" ] = {0, 0, 3};
    ng_global.achiev[ "five_ho_without_hint" ] = {0, 0, 5};
    ng_global.achiev[ "ten_ho_without_hint" ] = {0, 0, 10};
    ng_global.achiev[ "all_ho_without_hint" ] = {0, 0, 14};

    ng_global.achiev[ "three_ho_three_min" ] = {0, 0, 1};
    ng_global.achiev[ "five_ho_three_min" ] = {0, 0, 1};
    ng_global.achiev[ "ten_ho_three_min" ] = {0, 0, 1};

    ng_global.achiev[ "one_mg_less_one_min" ] = {0, 0, 1};
    ng_global.achiev[ "one_ho_less_one_min" ] = {0, 0, 1};
    ng_global.achiev[ "one_ho_more_ten_min" ] = {0, 0, 1};

    ng_global.achiev[ "three_item_ho" ] = {0, 0, 1};
    ng_global.achiev[ "five_item_ho" ] = {0, 0, 1};
    ng_global.achiev[ "ten_item_ho" ] = {0, 0, 1};

    --ng_global.rm_alicehome_state =
    --  {
    --    [ "flowers_on_table" ]   = 0,
    --    [ "toys_for_cat" ]       = 0,
    --    [ "door_with_curtain" ]  = 0,
    --    [ "bear" ]               = 0,
    --    [ "picture_of_friends" ] = 0,
    --    [ "coffee_table" ]       = 0,
    --    [ "wall_paper" ]         = 0,
    --    [ "chandeliers" ]        = 0,
    --    [ "sofa_covering" ]      = 0,
    --    [ "bookcase" ]           = 0,
    --    [ "pillows" ]            = 0,
    --    [ "diplomas" ]           = 0,
    --    [ "printer" ]            = 0,
    --    [ "basket_for_cat" ]     = 0,
    --    [ "laptop" ]             = 0,
    --    [ "complete_kitchen" ]   = 0
    --  };

  end;
--*********************************************************************************************************************
--***function *** ROOM - SUBROOM *** () end****************************************************************************
--*********************************************************************************************************************
  function public.GotoRoom( room_object, need_fade, dontsave )

    if public.is_in_map == 1 then

      int_map_impl.CloseLd();

    end;

  end;
  --------------------------------------------------------------------
  function public.GotoSubRoom( zz_object, pos_beg, pos_end )

  end;
--*********************************************************************************************************************
--***function *** SETTINGS *** () end**********************************************************************************
--*********************************************************************************************************************
  function public.UpdateGameMode( gamemode )

  end;
  --------------------------------------------------------------------
  function public.SaveInterfaceTimers()

  end;
--*********************************************************************************************************************
--***function *** MINIGAME *** () end**********************************************************************************
--*********************************************************************************************************************
  function public.MiniGameShow( minigame_name, skip_multiplier )

    if ( skip_multiplier ) then

      if ( common.GetGamemode() == 0 ) then

        skip_multiplier = 3.333333;

      elseif ( common.GetGamemode() > 0 ) then

        skip_multiplier = 3.5;

      end;

    end;

    minigame_name = minigame_name or common.GetObjectName( GetCurrentRoom() );

    if common.IsInSubRoom() then
      minigame_name = common.GetObjectName( common.GetCurrentSubRoom() );
    end;

    local result = false;

    local event_name = "win_"..minigame_name;

    if ( not cmn.IsEventStart( event_name ) ) then

      cmn.SetEventStart( event_name );
      private.SetSkipTimer( minigame_name, 1 );

      result = true;

    end;

    interface.ButtonHintHide();

    interface.ButtonInfoShow();
    interface.ButtonResetShow();
    interface.ButtonSkipShow();

    interface.ButtonSkipReload( private.GetSkipTimer( minigame_name ), skip_multiplier or 1 );

    return result;

  end;
  -------------------------------------------------------------------------------------
  function public.MiniGameHide( minigame_name )

    minigame_name = minigame_name or common.GetObjectName( GetCurrentRoom() );

    --if common.IsInSubRoom() then
    --  minigame_name = common.GetObjectName( common.GetCurrentSubRoom() );
    --end;

    local result = false;

    local event_name = "win_"..minigame_name;

    if  (     cmn.IsEventStart( event_name ) )
    and ( not cmn.IsEventDone( event_name )  )
    then

      private.SetSkipTimer( minigame_name, interface.ButtonSkipGetTime() );
      --DbgTrace( "save skip for &lt; "..prg_name.." &gt; =  "..current_progress[ prg_name ].skiptimer );

      interface.ButtonInfoHide();
      interface.ButtonResetHide();
      interface.ButtonSkipHide();

      interface.ButtonHintShow();

      result = true;

    end;

    return result;

  end;
  --------------------------------------------------------------------------------------
  function private.GetSkipTimer( minigame_name )

    local prg = prg.current;
    local event_name = "win_"..minigame_name;
    return ng_global.progress[ prg ][ event_name ].skiptimer;

  end;
  --------------------------------------------------------------------------------------
  function private.SetSkipTimer( minigame_name, time_relative )

    local prg = prg.current;
    local event_name = "win_"..minigame_name;
    ng_global.progress[ prg ][ event_name ].skiptimer = time_relative;

  end;
--*********************************************************************************************************************
--***function *** HO *** () end****************************************************************************************
--*********************************************************************************************************************
  function public.ProcessHoStart( ho_name )

    local ho_found = ng_global.progress[ ng_global.currentprogress ][ "win_"..ho_name ].found;

    for i = 1, #ho_found, 1 do

      if ( ho_found[ i ][ "task" ] ) then

        ObjDelete( ho_found[ i ][ "object" ] );

      end;

      if ( ho_found[ i ][ "item" ] ) then

        ObjDelete( ho_found[ i ][ "item" ] );

      end;

    end;

  end;
  -----------------------------------------------------------------------------------
  function public.HoItemFind( sender )

    public.PlayAudio("snd", "assets/levels/common/audio/aud_takeobject_ho");

    local ho_name          = common.GetObjectName( GetCurrentRoom() );
    local item_name        = "itm_"..common.GetObjectName( sender );
    local item_object_name = sender;

    ng_global.progress[ ng_global.currentprogress ][ "win_"..ho_name ].start = 1;

    local item_found = { item = item_name, object = item_object_name };

    table.insert( ng_global.progress[ ng_global.currentprogress ][ "win_"..ho_name ].found, item_found );

    interface.itempanel.countdown = interface.itempanel.countdown - 1;

    if ( interface.itempanel.countdown == 0 ) then

      ng_global.progress[ ng_global.currentprogress ][ "win_"..ho_name ].done = 1;
      ng_global.progress[ ng_global.currentprogress ].common.currentroom = ng_global.progress[ ng_global.currentprogress ][ "win_"..ho_name ].exitroom;

      _G[ "ho_"..ho_name ].HoComplete();

    end;

    int_itempanel_impl.HoItemContourFindAnim( item_object_name, item_name, interface.itempanel.countdown );
  
      
    if ( IsCollectorsEdition() or IsSurveyEdition() ) then
      
      if not ObjGet( "tmr_"..ho_name.."_object_achiev" ) then

        public.StopwatchHoStart();
        public.StopwatchHoEnd();

      else

        public.StopwatchHoEnd();

      end;

    end;

  end;
  -----------------------------------------------------------------------------------
  function public.HoTaskFind( sender, task )

    public.PlayAudio("snd", "assets/levels/common/audio/aud_takeobject_ho");

    local ho_name          = common.GetObjectName( GetCurrentRoom() );
    local task_name        = task;
    local task_object_name = sender;

    ng_global.progress[ ng_global.currentprogress ][ "win_"..ho_name ].start = 1;

    local task_found = { task = task_name, object = task_object_name };

    table.insert( ng_global.progress[ ng_global.currentprogress ][ "win_"..ho_name ].found, task_found );

    interface_impl.TaskPanelTaskComplete( ho_name, task_name, task_object_name );

    if ( IsCollectorsEdition() or IsSurveyEdition() ) then
      
      if not ObjGet( "tmr_"..ho_name.."_object_achiev" ) then

        public.StopwatchHoStart();
        public.StopwatchHoEnd();

      else

        public.StopwatchHoEnd();

      end;

    end;

  end;
  --------------------------------------------------------------------
  function public.SetMarkedTask( ho_name, task )

    local prg = prg.current;

    local event_win_ho = "win_"..ho_name;

    ng_global.progress[ prg ][ event_win_ho ].unmark[ task ] = {};
    ng_global.progress[ prg ][ event_win_ho ].unmark[ task ].done = 0;

  end
  --------------------------------------------------------------------------------------
  function public.UnmarkTask( ho_name, task )

    local prg = prg.current;

    local event_win_ho = "win_"..ho_name;

    ng_global.progress[ prg ][ event_win_ho ].unmark[ task ].done = 1;
    ng_global.progress[ prg ][ event_win_ho ].start = 1;

    interface.TaskPanelTaskUnmark( ho_name, task );

  end
  --------------------------------------------------------------------------------------
  function public.IsUnmarkedTask( ho_name, task )

    local prg = prg.current;

    local event_win_ho = "win_"..ho_name;

    if ( ng_global.progress[ prg ][ event_win_ho ].unmark[ task ].done == 1 ) then

      return true;

    else

      return false;

    end;

  end
  --------------------------------------------------------------------------------------
  function public.InitHo( ho_name )

    local prg = prg.current;

    local event_win_ho = "win_"..ho_name;

    ng_global.progress[ prg ][ event_win_ho ].start = 1;
    ng_global.progress[ prg ][ event_win_ho ].unmark = {};
    ng_global.progress[ prg ][ event_win_ho ].found = {};

  end
--*********************************************************************************************************************
--***function *** Inv Object *** () end*******************************************************************************
--*********************************************************************************************************************
  function public.UseItem( funcs )

    for id, func in pairs( funcs ) do

      if( func() ) then
        break;
      end;
      
    end;
    
  end;
--*********************************************************************************************************************
--***function *** Complex Inv *** () end*******************************************************************************
--*********************************************************************************************************************
  function public.ShowComplexItem( inv_name )

    if interface.GetCurrentComplexInv() == "" then

      local objname = "inv_complex_"..inv_name;
      common.CallRoomEventHandlers( objname );
      interface.ComplexInvShow( objname );

    else

      interface.ComplexInvHide();

    end;

    if common.IsInSubRoom() then
      common.CloseSubRoom();
    end;

  end;
  --*********************************************************************************************************************
  function public.HideComplexItem()

    interface.ComplexInvHide();

  end;
  --*********************************************************************************************************************
  function public.InventoryComplexItemAdd( inv_objname, scene_objname, func )

    interface.InventoryItemAdd( inv_objname, scene_objname, func );  
    ObjSet( inv_objname, { drag = false } );

  end;
  --*********************************************************************************************************************
  function private.StringDivide(string)

    local table = {}
    local id = 1
    local il = 1
    for i = 1, string.len(string) do
      if string.sub(string,i,i) == "_" then
        table[id] = string.sub(string,il,i-1)
        il = i+1
        id = id + 1
      end
      if i == string.len(string) then
        table[id] = string.sub(string,il,i)
        il = i+1
        id = id + 1
      end
    end
    return table;

  end;
  --*********************************************************************************************************************
  function public.ObjIntersectCheck( obj_to_apply, obj_to_check, obj_complex_inv )

    local obj_complex_inv = obj_complex_inv or "inv_complex_"..private.StringDivide( obj_to_check )[3];  

    return interface.GetCurrentComplexInv() == obj_complex_inv and ObjIntersect( obj_to_apply, obj_to_check );

  end;
--*********************************************************************************************************************
--***function *** PROGRESS *** () end**********************************************************************************
--*********************************************************************************************************************
  function public.SetEventDone( event_name )

    ng_global.progress[ prg.current ][ event_name ].done = 1;

  end;
  --------------------------------------------------------------------------------------
  function public.IsEventDone( event_name )

    return ng_global.progress[ prg.current ][ event_name ].done == 1;

  end;
  --------------------------------------------------------------------------------------
  function public.SetEventStart( event_name )

    ng_global.progress[ prg.current ][ event_name ].start = 1;

  end;
  --------------------------------------------------------------------------------------
  function public.IsEventStart( event_name )

    return ng_global.progress[ prg.current ][ event_name ].start > 0;

  end;
--*********************************************************************************************************************
--***function *** EVENTS *** () end************************************************************************************
--*********************************************************************************************************************
  function public.CheaterKeyPress( keycode )

  end;  
  --------------------------------------------------------------------------------------
  function public.Application_Closing()

    if IsSurveyEdition() then
   
        local url = GetUrl();
        OpenBrowser( url );

    end;

  end; 
  --------------------------------------------------------------------------------------
  function public.PanelNotification_Click( notification_type )

    DbgTrace( "Notification Panel Clicked. Notification type: "..notification_type );

  end;
  --------------------------------------------------------------------------------------
  function public.ButtonGuide_Click()

  end;  
  --------------------------------------------------------------------------------------
  function public.ButtonHint_Click( hint_state, ho_no_obj )

    ho_no_obj = ho_no_obj or false

    if ( ng_global.gamemode < 2 ) or ( ng_global.gamemode == 3 and ng_global.custom_gamemode.use_hint == 1 ) then

      if ( hint_state ) then

        cmn.PlayAudio( "snd", "assets/levels/common/audio/aud_use_hint" );

        local is_ho_hint = false;
        local currentroom = GetCurrentRoom();

        if common.IsInSubRoom() then
          currentroom = common.GetCurrentSubRoom();
        end;

        if  ( common.GetObjectPrefix( GetCurrentRoom() ) == "ho" ) then

          local room = common.GetObjectName( GetCurrentRoom() );
          ng_global.progress[ng_global.currentprogress][ "win_"..room ].is_hint = 1;

        end;

        if  ( common.GetObjectPrefix( GetCurrentRoom() ) == "ho" ) and ho_no_obj == false then

          common_impl.HideComplexItem();

          --DbgTrace("*хинт в хо");

          local room = common.GetObjectName( GetCurrentRoom() );

          if ( game[ room ].double_hint ) then

            --DbgTrace( "*есть двойной хинт" );

            --int.event.HoDoubleHintShow();

          else

            --DbgTrace( "*нету двойного хинта" );

            interface.TaskPanelHoHintShow();
            interface.ItemPanelHoHintShow();

          end;

          local prg_name = "win_"..room;

          ng_global.progress[ ng_global.currentprogress ][ prg_name ].clk_hint = 1;
          interface.ButtonHintReload( 1 );

        else

          local current_progress = ng_global.progress[ ng_global.currentprogress ];

          for i = 1, #game.progress_names, 1 do   

            local prg_name = game.progress_names[ i ];
            --DbgTrace("prg_name "..prg_name.." done "..current_progress[ prg_name ].done);

            if  ( current_progress[ prg_name ].done == 0 ) and ( game.hint[ prg_name ] )  then

              --реализация хинта для локации, отличная от стандартной
              --DbgTrace( "Button [ H ] Hint show for &lt; "..prg_name.." &gt;." );

              if common.GetCurrentRoom() == game.hint[ prg_name ].room or 
                 common.GetCurrentSubRoom() == game.hint[ prg_name ].zz   then

                --DbgTrace("*находимся в нужной комнате или zz");

                if game.hint[ prg_name ].zz then

                  --DbgTrace( "*действие в zz = "..game.hint[ prg_name ].zz );

                  private.CheckRoomState( prg_name, currentroom )

                else

                  --DbgTrace( "*действие не в zz" );

                  if currentroom == game.hint[ prg_name ].room then

                    --DbgTrace("*находимся в нужной комнате");

                    private.CheckHintType( prg_name );

                  else
                  
                    if (common.GetObjectPrefix( currentroom )== "mg") or (common.GetObjectPrefix( currentroom )== "rm") then

                      interface_impl.DialogHintShow( game.hint[ prg_name ].room );

                    else

                      --DbgTrace("*находимся в ненужной zz");

                      --ld.hint.HintShowAnim( "spr_int_frame_subroom_button_cross" );

                      common_impl.HintShowPlace( "obj_int_frame_subroom_button" );

                    end;
                    
                  end;

                end;

                common_impl.HideComplexItem();

  ---------------для сборных инв предметов

              elseif game.hint[ prg_name ].room == "int_complex_inv" then

                  --DbgTrace( "*действие в сбороном предмете = "..game.hint[ prg_name ].room );

                  if not int_complex_inv.IsOnScreen() then

                     --DbgTrace("*сборный предмет не открыт");

                     int_inventory_impl.ShowAnim( "show" );
                     --int.InventoryItemAdd( game.hint[ prg_name ].zz_gate, "" );   --изза него был баг с вылазиньем предметов из инвентаря

                     private.HintShowAnim( game.hint[ prg_name ].zz_gate );   --показывает частицы на самом предмете в инвентаре

                     common_impl.HintShowPlace( game.hint[ prg_name ].zz_gate );  --показывает частицы в виде метеора летящего из кнопки хинта

                  else

                     --DbgTrace("*сборный предмет открыт");

                     private.CheckHintType( prg_name ); 

                  end;

  ----------------------------------------------
              else

                if ( not common_impl.show_hint.dialog ) then 

                  common_impl.show_hint.dialog = prg_name;

                  interface_impl.DialogHintShow( game.hint[ prg_name ].room );

                  common_impl.HideComplexItem();

                end;

              end;

              break;

            end;

          end;

        end;

        --int.ButtonHintReload( 1 );

      else
        --DbgTrace( "Hint is not ready now." );
        interface.DialogShow( "str_hardcore_notready", 512, 384 );
        --PlaySfx( "assets/levels/common/audio/aud_use_hint", 0, 0 );

      end;

    else

      interface.DialogShow( "str_hardcore_hint", 512, 384 );
      --PlaySfx( "assets/levels/common/audio/aud_use_hint", 0, 0 );

    end;

  end;
  --------------------------------------------------------------------------------------
  function public.ButtonInfo_Click()

    local mg_name = common.GetObjectName( GetCurrentRoom() );

    if common.IsInSubRoom() then
      mg_name = common.GetObjectName( common.GetCurrentSubRoom() );
    elseif interface.GetCurrentComplexInv() ~= "" then
      mg_name = common.GetObjectName( interface.GetCurrentComplexInv() );
    end;

    interface.DialogShow( "ifo_"..mg_name );

  end;
  --------------------------------------------------------------------------------------
  function public.ButtonLock_Click()

  end;
  --------------------------------------------------------------------------------------
  function public.ButtonMap_Click()

    interface.MapShow();

  end;
  --------------------------------------------------------------------------------------
  function public.ButtonMenu_Click()

  end;
  --------------------------------------------------------------------------------------
  function public.ButtonReset_Click()

    local mg_name = GetCurrentRoom();

    if common.IsInSubRoom() then

      local zz_name = common.GetCurrentSubRoom();
      _G[ mg_name ][ zz_name ].Reset();

    elseif interface.GetCurrentComplexInv() ~= "" then

      --local inv_name = common.GetObjectName( interface.GetCurrentComplexInv() );
      local inv_name = interface.GetCurrentComplexInv();
      _G[ mg_name ][ inv_name ].Reset();

    else 

      _G[ mg_name ].Reset();

    end;

  end;
  --------------------------------------------------------------------------------------
  function public.ButtonSkip_Click( skip_ready )

    if ( ng_global.gamemode < 2 ) or ( ng_global.gamemode == 3 and ng_global.custom_gamemode.use_skip == 1 ) then

      if ( skip_ready ) then

        local mg_name = GetCurrentRoom();

        if common.IsInSubRoom() then

          local zz_name = common.GetCurrentSubRoom();
          _G[ mg_name ][ zz_name ].Skip();

        elseif interface.GetCurrentComplexInv() ~= "" then

          --local inv_name = common.GetObjectName( interface.GetCurrentComplexInv() );
          local inv_name = interface.GetCurrentComplexInv();
          _G[ mg_name ][ inv_name ].Skip();

        else 

          _G[ mg_name ].Skip();

        end;

        interface.ButtonSkipReload( 1 );

      else

        interface.DialogShow( "skip_not_ready", 512, 384 );

      end;

    else

      interface.DialogShow( "skp_hardcore", 512, 384 );

    end;

  end;
  --------------------------------------------------------------------------------------
  function public.FrameSubroom_Click()

  end;
  --------------------------------------------------------------------------------------
  function public.Tutorial_Click( button_id )

    --DbgTrace("***common_impl.TutorialClick current = "..public.tutorial.current..", button_id = "..button_id);

    if ( ObjGet( "obj_tutorial_"..public.tutorial.current ) ) then

      --DbgTrace("***block off "..public.tutorial.current );

      ObjSet( "obj_tutorial_"..public.tutorial.current, { input = 0 } );

    end;

    ng_global.progress["std"][public.tutorial.current].done = 1;

    if ( button_id == "no" ) or ( button_id == "skip" ) then

      for i = 1, 17, 1 do 

        ng_global.progress["std"]["tutor_"..i].done = 1;

      end;

      ng_global.lvl1_tutor_skip = true;

      interface.TutorialHide();

    elseif button_id == "some" then

      for i = 1, 17, 1 do 

        if (i ~= 6) and (i ~= 11) and (i ~= 14) and (i ~= 17) then
         ng_global.progress["std"]["tutor_"..i].done = 1;
        end;

      end;

      interface.TutorialHide();

    elseif button_id == "yes" then

      local arrows = { { pos_x = 0, pos_y = -120, ang = 0 } };

      public.tutorial.TutorialShow( "tutor_1", 0, 512, 548, arrows );

    else

      if ( public.tutorial.current == "tutor_1" ) then

        interface.TutorialHide();

      elseif ( public.tutorial.current == "tutor_4" ) then 

        interface.TutorialHide();

        if (int_inventory.GetAutohide()) then
          int_inventory.Hide( false );
        end;

      elseif ( public.tutorial.current == "tutor_6" ) then 

        if cmn.IsEventDone("tutor_7") then
  
          interface.TutorialHide();

        else

          local arrows = { { pos_x = 240, pos_y = 140, ang = -2.6 } };

          public.tutorial.TutorialShow( "tutor_7", 0, 600, 384, arrows );

        end;

      elseif ( public.tutorial.current == "tutor_8" ) then 

        interface.TutorialHide();

        if (int_inventory.GetAutohide()) then
          int_inventory.Hide( false );
        end;

      elseif ( public.tutorial.current == "tutor_13" ) then 


        local arrows = { { pos_x = 320, pos_y = 0, ang = -1.57 } };

        if ( GetWideScreen() ) then

          ObjMultiSet( { {"obj_tutorial_tutor_12", { pos_x = -700 }},
                         {"obj_tutorial_tutor_12_1", { pos_x = 1127 }} } );

          public.tutorial.TutorialShow( "tutor_12", 0, 700, 431, arrows );

        else 

          ObjMultiSet( { {"obj_tutorial_tutor_12", { pos_x = -512 }},
                         {"obj_tutorial_tutor_12_1", { pos_x = 956 }} } );

          public.tutorial.TutorialShow( "tutor_12", 0, 512, 431, arrows );

        end;

      elseif ( public.tutorial.current == "tutor_11" ) then

        interface.TutorialHide();

        for i = 1, 3, 1 do

          if (ObjGet("spr_int_achiev_"..i).pos_x > -182 ) then
            int_achiev.AchMouseLeave( i );
          end;

        end;

        if not(cmn.IsEventDone("tutor_8")) and not(public.go_acievements) then 

          if (ObjGet("hub_int_inventory_boxstaple")) then

            cmn.SetEventDone("opn_carolsroomafterho");

            int_inventory.Show( true );

            local boxstaple_pos = GetObjPosByObj("hub_int_inventory_boxstaple");

            ObjMultiSet( { {"obj_tutorial_tutor_8", { pos_x = -boxstaple_pos[1] }},
                           {"obj_tutorial_tutor_8_1", { pos_x = boxstaple_pos[1] }} } );

            local arrows = { { pos_x = 0, pos_y = 160, ang = 3.14 } };
            public.tutorial.TutorialShow( "tutor_8", 0, boxstaple_pos[1], 450, arrows );

          end;

        end;

      else

        interface.TutorialHide();

      end;

    end;

--    if ( string.find( button_id, "yes" ) ) then
--
--      interface.TutorialHide();
--      game[ game.tutorial_current ].click();
--
--    elseif ( string.find( button_id, "empty" ) ) then
--
--      interface.TutorialHide();
--      game[ game.tutorial_current ].click();
--
--    elseif ( string.find( button_id, "no" ) ) then
--
--      game.TutorialSkip();
--      interface.TutorialHide();
--      if ( game[ game.tutorial_current ].hide ) then
--
--        game[ game.tutorial_current ].hide();
--    
--      end;
--
--    else
--
--      DbgTrace("impossible "..button_id);
--
--    end;

  end;
  --------------------------------------------------------------------------------------
  function public.HoHint_NoObjects()

    local currentroom = GetCurrentRoom();

    local ho_name = common.GetObjectName( currentroom );

    local ho_hint_progress_names = _G[ "ho_"..ho_name ].ho_hint_progress_names;

    --перебираем таблицу прогресса хо
    if ho_hint_progress_names then

      for i = 1, #ho_hint_progress_names, 1 do

        if ( not cmn.IsEventDone( ho_hint_progress_names[i] ) ) then

          --DbgTrace( "***not done "..ho_hint_progress_names[i] );

          if game.hint[ ho_hint_progress_names[i] ].zz then

            --DbgTrace( "*действие в zz = "..game.hint[ ho_hint_progress_names[i] ].zz );

            private.CheckRoomState( ho_hint_progress_names[i], currentroom )

          else

            --DbgTrace( "*действие на локации" );

            private.CheckHintType( ho_hint_progress_names[i] );

          end;

          break;

        end;

      end;

    end;

  end;
  --------------------------------------------------------------------------------------
  function public.DialogHo_Show()

    local ho_name = common.GetObjectName( GetCurrentRoom() );
    local ho_stage = ng_global.progress[ prg.current ][ "win_"..ho_name ].stage;

    if ( ho_stage ) and ( ho_stage[1] <= ho_stage[2] ) and ( interface_impl.taskpanel_countdown == 0 ) then

      _G[ "ho_"..ho_name ][ "stage_"..ho_stage[1] ] ();

    elseif ( ho_stage ) and ( ( ho_stage[1] > ho_stage[2] ) or ( interface_impl.taskpanel_countdown > 0 ) ) and ( _G[ "ho_"..ho_name ].win ) then

      --если int.taskpanel.countdown > 0 значит прошли читером

      ng_global.progress[ ng_global.currentprogress ][ "win_"..ho_name ].done = 1;

      _G[ "ho_"..ho_name ].win();

    else

      public.PlayAudio( "snd", "assets/levels/common/audio/aud_win_ho" );

      interface.TaskPanelHide();
      interface.ItemPanelHide();
      interface.DialogHoShow();

      ng_global.progress[ ng_global.currentprogress ][ "win_"..ho_name ].done = 1;
      ng_global.progress[ ng_global.currentprogress ].common.currentroom = ng_global.progress[ ng_global.currentprogress ][ "win_"..ho_name ].exitroom;

    end;

  end;
  --------------------------------------------------------------------------------------
  function public.DialogHo_Hide()

    local ho_name = common.GetObjectName( GetCurrentRoom() );
    cmn.CallEventHandler( "win_"..ho_name, GetCurrentRoom() );
    common.GotoRoom( game.relations[ GetCurrentRoom() ].exitroom );

  end;
  --------------------------------------------------------------------------------------
  function public.PanelNotification_Click( notification_type )

    DbgTrace( "Notification Panel Clicked. Notification type: "..notification_type );

  end;
  --------------------------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** GATES *** () end ************************************************************************************
--*********************************************************************************************************************
  function public.GotoRm( rm_name, need_fade )

    local rm_object_name = "rm_"..rm_name;

    need_fade = need_fade or 1;  

    common.GotoRoom( rm_object_name, need_fade );

  end;
  --------------------------------------------------------------------
  function public.GotoHo( ho_name, need_fade )

    local ho_object_name = "ho_"..ho_name;

    need_fade = need_fade or 1;  

    common.GotoRoom( ho_object_name, need_fade );

  end;
  --------------------------------------------------------------------
  function public.GotoMg( mg_name, need_fade )

    local mg_object_name = "mg_"..mg_name;

    need_fade = need_fade or 1;  

    common.GotoRoom( mg_object_name, need_fade );

  end;
  --------------------------------------------------------------------
  function public.GotoZz( zz_name, pos_beg )
    
    local zz_object_name = "zz_"..zz_name;

    common.GotoSubRoom( zz_object_name, pos_beg );

  end;
  --------------------------------------------------------------------
  --------------------------------------------------------------------
  private.goto_objname = "";   --имя обьекта по кторому прошел mdown
  --------------------------------------------------------------------
  function public.GotoRoomMDown( sender )

    private.goto_objname = sender;

    ObjWaitForMouseUp( sender, function () private.goto_objname = ''; end );

  end;
  --------------------------------------------------------------------
  function public.GotoRoomMUp( sender, room_object )

    if ( sender == private.goto_objname ) then

      cmn.GotoRoom( room_object );

    end;

    private.goto_objname = "";

  end;
  --------------------------------------------------------------------
  --------------------------------------------------------------------
  function public.GotoSubRoomMDown( sender )

    private.goto_objname = sender;

    ObjWaitForMouseUp( sender, function () private.goto_objname = ''; end );

  end;
  --------------------------------------------------------------------
  function public.GotoSubRoomMUp( sender, subroom_object, pos_end )

    pos_end = pos_end or nil;

    if ( sender == private.goto_objname ) then

      cmn.GotoSubRoom( subroom_object, nil, pos_end );

    end;

    private.goto_objname = "";

  end;
  --------------------------------------------------------------------
  --------------------------------------------------------------------
  function public.GateMouseEnter( sender, type_cursor )
    
    type_cursor = type_cursor or CURSOR_DEFAULT;
    SetCursor( type_cursor );

    local obj = "grm_"..sender;
    local obj_focus = obj.."_focus";
    local alp = ObjGet( obj_focus ).alp;

    ObjAnimate( obj_focus, "alp", 0, 0, "", { 0.0, 0, alp,   public.animtime *( 1 - alp ), 0, 1 } );

    common_impl.PopupShow( string.match(obj, "grm_.*_(.*)") );

  end;
  --------------------------------------------------------------------
  function public.GateMouseLeave( sender )

    local obj = "grm_"..sender;
    local obj_focus = obj.."_focus";
    local alp = ObjGet( obj_focus ).alp;
    local tme = 1;

    SetCursor( CURSOR_DEFAULT );

    ObjAnimate( obj_focus, "alp", 0, 0, "", { 0.0, 0, alp,   tme * alp, 0, 0 });

    common_impl.PopupHide();

  end;
--*********************************************************************************************************************
--***function *** POPUP *** () end ************************************************************************************
--*********************************************************************************************************************
  function public.PopupShow( popup_text )

    popup_text_id = "pop_"..popup_text;
    interface.PopupShow( popup_text_id );
    
  end;
  --------------------------------------------------------------------
  function public.ShowPopupInv( name_obj, cursor_type )

    cursor_type = cursor_type or CURSOR_DEFAULT;
    SetCursor( cursor_type );

    public.PopupShow( name_obj );

  end;
  --*********************************************************************************************************************
  function public.PopupHide()

    interface.PopupHide();
    
  end;
  --------------------------------------------------------------------
  function public.HidePopupInv(  )

    SetCursor( CURSOR_DEFAULT );

    interface.PopupHide();

  end;
--*********************************************************************************************************************
--***function *** Hint *** () end ************************************************************************************
--*********************************************************************************************************************
  function private.HintInit()

  public.show_hint = {};
  ----------------------------------------------------------------------------------
  private.save_autohide = 1;
  ----------------------------------------------------------------------------------
  private.hint ={};

  private.hint.res                  = "assets/interface/resources/hint_effect/pfx_circle2";--spark_red

  --ресурс на дополнительный эффект хинта
  private.hint.res_center           = "assets/interface/resources/hint_effect/pfx_circle2";--fx_hint_show2

  --ресурс для хинта на инвентарь
  private.hint.res_inv              = "assets/interface/resources/hint_effect/pfx_circle2";    

  private.hint.big_R                = 500;
  private.hint.big_R_zz             = 500;
  private.hint.small_R              = 60;
  private.hint.partsys_count        = 8;   -- количество систем частиц
  private.hint.time_fly             = 1.0; -- время, за которое частицы долетят до цели
  private.hint.time_fly_zz          = 0.8; -- время для зум-зоны
  private.hint.time_circle          = 0.3; -- время на один сдвиг по кругу
  private.hint.circle_cnt           = 6;   -- количество сдвигов частиц по кругу
  private.hint.tme_show             = 0.4;
  private.hint.tme_hide             = 0.4;
  private.hint.tme_circle_fx        = 1.0 --время показа центральной частицы
  private.hint.sinus_offset         = 70  --амплитуда синусоиды
  private.hint.sinus_points_cnt     = 50  --количество точек синусоиды
  private.hint.sinus_points_extrems = 2;  --количество экстремумов синусоиды

  private.hint.ShowInRm = {};
  private.hint.ShowInZz = {};
  private.hint.POS_OFFSET_X  = 940;
  private.hint.WIDE_OFFSET_X = 0;---- or 171

  end;
  --*********************************************************************************************************************
  function private.IsOdd(num)

    if math.fmod(num,2) == 0 then

      return -1;

    else

      return 1;

    end;

  end;
  ----------------------------------------------------------------------------------
  function private.CreateIndex( i, count )

    local index = (i) 
    - ( count * (( math.modf((i)/count) 
    - math.abs( math.ceil( (i)/count 
    - math.modf((i)/count) ) - 1 ) ) ) );

    return index;

  end;
  ----------------------------------------------------------------------------------
  function private.MathRound( roundIn , roundDig ) -- первый аргумент - число которое надо округлить, второй аргумент - количество символов после запятой.

    local mul = math.pow( 10, roundDig )
    return ( math.floor( ( roundIn * mul ) + 0.5 )/mul )

  end
  function private.GetCircleCoord( number, radius, ang_shift )

    local ang = 360 / number;
    local R  = radius or 70;
    local ang_num = ang_shift or 0;
    local pos = {};

    for i=1,number,1 do

      local cur_ang = math.rad(ang * ( i + ang_num ));   

      pos[ i ] = {}
      pos[ i ][ "x" ] = math.ceil( math.cos( cur_ang ) * R );
      pos[ i ][ "y" ] = math.ceil( math.sin( cur_ang ) * R );

    end;

    return pos;

  end;
  ----------------------------------------------------------------------------------
  --*********************************************************************************************************************
  ----------------------------------------------------------------------------------
  function private.CreateSinglePartySys( i, target_name, hint_pos_beg, hint_pos_end, tme, obj_name )

    local hint_name  = "pfx_hint_"..target_name.."_"..i;
    local obj_hint_name  = obj_name or "obj_hint_"..target_name;
    local index_anim_array = {};
    index_anim_array["x"] = {};
    index_anim_array["y"] = {};

    --DbgTrace("***ld.hint.CreateSinglePartySys target_name = "..target_name);

    ObjCreate( hint_name, "partsys" );

    ObjSet( hint_name,
    {
      res = private.hint.res;
      pos_x = hint_pos_beg[i][ "x" ], pos_y = hint_pos_beg[i][ "y" ], alp = 1
    } );

    ObjAttach( hint_name, obj_hint_name );

    local points = private.CreateSinusPoints( hint_pos_beg[i][ "x" ], hint_pos_beg[i][ "y" ], 
                                              hint_pos_end[i][ "x" ], hint_pos_end[i][ "y" ], 
                                              private.hint.sinus_offset, private.hint.sinus_points_extrems, private.hint.sinus_points_cnt );

    for index = 1,#points,1  do

      local c_index = index + 3*( index - 1 );
      local c_time = (tme/#points)*(index - 1);

      index_anim_array[c_index] = c_time; -- время
      index_anim_array[c_index + 1] = 0; -- интерполяция
      index_anim_array[c_index + 2] = points[index]["x"]; -- значение
      index_anim_array[c_index + 3] = -points[index]["y"]; -- значение

    end

    ObjAnimate(hint_name, "pos_xy",0,0, private.AnimPartSysCircle( i, hint_name), index_anim_array);

  end;
  ----------------------------------------------------------------------------------
  function private.AnimPartSysCircle( i, hint_name )

    local index_anim_array = {};
    local hint_pos_end = {}; 

    hint_pos_end = private.GetCircleCoord( private.hint.partsys_count, private.hint.small_R );

    for index = 1,private.hint.circle_cnt,1  do

      local c_index = index + 3*( index - 1 );
      local end_index = private.CreateIndex((i + index),privatehint.partsys_count);

      index_anim_array[c_index] = ( (index - 1) *private.hint.time_circle ); -- время
      index_anim_array[c_index + 1] = 0; -- интерполяция
      index_anim_array[c_index + 2] = hint_pos_end[ end_index ][ "x" ] + math.random( -30, 30 ); -- x
      index_anim_array[c_index + 3] = hint_pos_end[ end_index ][ "y" ] + math.random( -30, 30 ); -- y

    end

    ObjAnimate(hint_name, "pos_xy",0,0, PartSysStop( hint_name ), index_anim_array);

  end;
  ----------------------------------------------------------------------------------
  function private.CreateSinusPoints( x1, y1, x2, y2, offset, extrems, p_number )

    local func_extrems = extrems or 2;
    local length = math.sqrt((x1-x2)^2 + (y2-y1)^2);
    local points_number = p_number or 5;
    local step = length/(points_number - 1);
    local array = {};
    local A = offset or 30;
    local T = math.pi * func_extrems / length;

    local cos_y = (x2 - x1)/(math.sqrt((y1 - y2)^2 + (x2 - x1)^2));

    local ang = math.acos( cos_y );
    local sin = private.MathRound(math.sin(ang), 6);
    local cos = private.MathRound(math.cos(ang), 6);

    for i=1,points_number,1 do

      local curr_pos_x = 0 + (step * (i-1));
      local curr_pos_y = math.floor(A * math.sin(T * curr_pos_x));

      local pos_x1 = curr_pos_x*cos + curr_pos_y*sin;
      local pos_y1 = - curr_pos_x*sin + curr_pos_y*cos;

      if y1 < y2 then

        pos_y1 = curr_pos_x*sin - curr_pos_y*cos;

      end;

      local pos_x = (pos_x1 + x1);
      local pos_y = (pos_y1 + y1);

      array[i] = {x = (pos_x), y = (pos_y)};

    end;

    return array;

  end;
  ----------------------------------------------------------------------------------
  function private.CreateCenterPartSys( target_name, attach_name )

    local hint_name  = "pfx_hint_"..target_name.."_center";

    ObjCreate( hint_name, "partsys" );

    ObjSet( hint_name,
    {
      res = private.hint.res_center,
      pos_x = 0, pos_y = 0,
      scale_x = 1.6, scale_y = 1.6
    } );

    ObjAttach( hint_name, attach_name );

  end;
  ----------------------------------------------------------------------------------
  function private.CreateHintObj( target_name, room )

    local obj_hint_name  = "obj_hint_"..target_name;
    local pos = GetObjPosByObj(target_name, room);
    local hint_pos_beg = {};
    local hint_pos_end = {}; 
    local partsys_R = private.hint.big_R;
    local tme = private.hint.time_fly;
    local timer_name = "tmr_"..target_name;
    
    if common.GetObjectPrefix( room ) == "zz" and target_name ~= "obj_int_frame_subroom_button" then

      partsys_R = private.hint.big_R_zz;
      tme = private.hint.time_fly_zz;

    end;

    hint_pos_beg = private.GetCircleCoord( private.hint.partsys_count, partsys_R, -1 );

    hint_pos_end = private.GetCircleCoord( private.hint.partsys_count, private.hint.small_R );

    common_impl.show_hint[ room ] = target_name;

    ObjCreate( obj_hint_name, "obj" );

    ObjSet( obj_hint_name,
    {
      pos_x = pos[1], pos_y = pos[2], pos_z = 1000,
      active = 1, visible = 1, input = 0, alp = 0
    } );

    for i=1, private.hint.partsys_count,1 do

      private.CreateSinglePartySys( i, target_name, hint_pos_beg, hint_pos_end, tme );

    end;

    if target_name == "obj_int_frame_subroom_button" then

     ObjSet( obj_hint_name,
     {
       pos_x = 0, pos_y = 0
     } );

     ObjAttach( obj_hint_name, target_name );

    else

     ObjAttach( obj_hint_name, room );

    end;

    local alp_tme = tme + private.hint.time_circle*private.hint.circle_cnt;
   
    ObjAnimate(obj_hint_name, "alp",0,0, private.HintShowAnimEnd( target_name, room), 
      {
        0.0,0,0, 
        private.hint.tme_show,0,1,
        alp_tme,0,1,
        (alp_tme + private.hint.tme_hide),0,0
      });

    ObjCreate( timer_name, "timer" );
    ObjAttach( timer_name, obj_hint_name );

    ObjSet( timer_name, 
    {
      endtrig = function () private.CreateCenterPartSys(target_name, obj_hint_name); end,
      time    = private.hint.time_fly,
      playing = 1
    } );  

  end;
  ----------------------------------------------------------------------------------
  function private.CreateInvHintPartSys( target_name, room )

    local obj_hint_name  = "obj_hint_"..target_name;
    local hint_name  = "pfx_hint_"..target_name;
    local timer_inv_name = "tmr_inv_"..target_name;

    interface.InventoryShowObject( target_name );

    ObjCreate( obj_hint_name, "obj" );

    ObjSet( obj_hint_name,
    {
      pos_x = 0, pos_y = 0
    } );

    ObjAttach( obj_hint_name, target_name );

    ObjCreate( hint_name, "partsys" );

    ObjSet( hint_name,
    {
      res = private.hint.res_inv,
      pos_x = 0, pos_y = 0
    } );

    ObjAttach( hint_name, obj_hint_name );

    --ObjCreate( timer_inv_name, "timer" );
    --ObjAttach( timer_inv_name, InterfaceWidget_Top_Name );

    ObjAnimate( hint_name, "alp", 0, 0, 
                function () 
                  private.HintHideInventoryEnd(target_name);
                  private.HintShowAnimEnd(target_name, room);
                end, 
                { 
                  0.0, 0, 1, 
                  2.5, 0, 1,
                  3.0, 0, 0 
                } 
              );

    --ObjSet( timer_inv_name, 
    --{
    --  endtrig = "",
    --  time    = 3.5,
    --  playing = 1
    --} );  

  end;
  ----------------------------------------------------------------------------------
  function private.HintShowAnim( target_name )

    local room = GetCurrentRoom();

    --DbgTrace( "ld.hint.HintShowAnim [ H ] Hint object < "..target_name.." >." );

    if ( not common_impl.show_hint[ target_name ] ) then

      if ObjGet( target_name ) then

        common_impl.show_hint[ target_name ] = 1;

        --PlaySfx( "assets/levels/common/audio/aud_hint_show", 0, 0 );

        if string.match(target_name, "^in._") then

          private.CreateInvHintPartSys( target_name, room );

        else

          private.CreateHintObj( target_name, room );
      
        end;

      end;

    else

      --ld.LogTrace( ld.logtrace_message, "[ H ] No object < "..target_name.." >!" );    

    end;
    
  end;
  ----------------------------------------------------------------------------------
  function private.HintShowAnimEnd( target_name, room )

    local obj_hint_name  = "obj_hint_"..target_name;

    ObjDelete( obj_hint_name );

    common_impl.show_hint[ target_name ] = nil;
    common_impl.show_hint[ room ] = nil;
    
  end;
  ----------------------------------------------------------------------------------
  function private.HintHideInventoryEnd( target_name )

    local inv_timer_name = "tmr_inv_"..target_name;
    
    ObjDelete( inv_timer_name );

    if string.find(target_name, "inv") and private.save_autohide == 1 then
    
      interface.InventoryAutoHideSet( 1 );
      interface.InventoryClose();
      private.save_autohide = 0;
      
    end;

  end;
  ----------------------------------------------------------------------------------
  function private.CheckHintType(prg_name)

    if game.hint[ prg_name ].type == "use" then

      -- показать инвентарь
      if interface.InventoryAutoHideGet() then
        private.save_autohide = 1;
        interface.InventoryAutoHideSet( false );
        interface.InventoryOpen();
      else
        private.save_autohide = 0;
      end;

      if string.match( game.hint[ prg_name ].inv_obj, "^in._") then
        private.HintShowAnim( game.hint[ prg_name ].inv_obj );
      else
        common_impl.HintShowPlace( game.hint[ prg_name ].inv_obj, "", 1 );
      end;

      --ld.hint.HintShowAnim(game.hint[ prg_name ].use_place);

      common_impl.HintShowPlace( game.hint[ prg_name ].use_place, prg_name )

    elseif game.hint[ prg_name ].type == "get" then

      -- показать на подбираемый предмет

      --ld.hint.HintShowAnim(game.hint[ prg_name ].get_obj);
      common_impl.HintShowPlace( game.hint[ prg_name ].get_obj, prg_name )

    elseif game.hint[ prg_name ].type == "click" or game.hint[ prg_name ].type == "clk" then

      --показать на место клика

      --ld.hint.HintShowAnim(game.hint[ prg_name ].use_place);
      common_impl.HintShowPlace( game.hint[ prg_name ].use_place, prg_name )

    elseif game.hint[ prg_name ].type == "win" then

    -- показать на место клика

      --ld.hint.HintShowAnim(game.hint[ prg_name ].use_place);
      common_impl.HintShowPlace( game.hint[ prg_name ].use_place, prg_name )

    end; 

    interface.ButtonHintReload( 1 );

  end;
  ----------------------------------------------------------------------------------
  function private.CheckRoomState(prg_name, currentroom)

    if currentroom == game.hint[ prg_name ].zz then

      --DbgTrace("*находимся в нужной zz");

      --DbgTrace("CheckRoomState: show_action_subroom");
      private.CheckHintType(prg_name);
      
    elseif common.GetObjectPrefix( currentroom ) == "zz" then

      --DbgTrace("*находимся в не нужной zz");

      --DbgTrace("CheckRoomState: show_close_subroom");                    
      --ld.hint.HintShowAnim("obj_int_frame_subroom_button");

      common_impl.HintShowPlace( "obj_int_frame_subroom_button" )

  --  elseif  cmn.GetObjectPrefix( currentroom )== "mg" then
  --
  --     int.DialogHintShow( game.hint[ prg_name ].room );

    else

      --DbgTrace("*находимся в комнате где нужная gzz");

      --DbgTrace("CheckRoomState: show_gate_subroom");
      --ld.hint.HintShowAnim(game.hint[ prg_name ].zz_gate);
      
      common_impl.HintShowPlace( game.hint[ prg_name ].zz_gate );

    end;

  end;
  ----------------------------------------------------------------------------------
  function private.HintAdditionalFunc( room_current ) -- данная ф-я нигде не вызывается

    if common_impl.show_hint[ room_current ] then

      local hint_name  = "pfx_hint_"..common_impl.show_hint[ room_current ];

      ObjDelete( hint_name );

      common_impl.show_hint[ common_impl.show_hint[ room_current ] ] = nil;
      common_impl.show_hint[ room_current ] = nil;

    end;

    if int_effects_impl.ho_hint[room_current] then

      for key, value in pairs( int_effects_impl.ho_hint ) do

        local obj_hint_name  = "obj_int_effects_ho_hint_"..key;

        ObjDelete( obj_hint_name );
        int_effects_impl.ho_hint[ key ] = nil;
        int_effects_impl.ho_hint[ room_current ] = nil;

      end;

    end;

  end;
  ----------------------------------------------------------------------------------
  function public.HintShowPlace( place, prg_name, double_hint )   --prg_name добавил чтобы ставить правильно смещение для хинтов в сложных предметах
                                                                   --double_hint для двойных хинтов

    prg_name = prg_name or "";

    local rm  = GetCurrentRoom();

    if common.IsInSubRoom() then
      rm = common.GetCurrentSubRoom();
    end;

    --меняем название комнаты для хинтов в сложных предметах
    if ( int_complex_inv.IsOnScreen() and ( prg_name ~= "" )) then
      if ( game.hint[ prg_name ].room == "int_complex_inv" ) then
        rm  = "int_complex_inv";
      end;
    end;

    --меняем название комнаты для двойных хинтов
    if ( double_hint ) then
      rm  = rm.."_double_hint";
    end;

    local fx  = "fx_hint_place_"..rm;
    local fx2 = "fx_hint_place_"..rm.."_2";
    local obj = "obj_hint_place_"..rm;

    --DbgTrace("*ld.hint.HintShowPlace, place = "..place..", prg_name = "..prg_name..", obj = "..obj);

    if ObjGet(obj) then  -- добавил т.к. выдает ошибку при ObjGet( obj ).alp
      local alp = ObjGet(obj).alp; 
    else
      local alp = false;
    end;

    if (ObjGet(obj) == nil) and (ObjGet( place ) ~= nil) then 

      if place == "obj_int_frame_subroom_button" then

        --DbgTrace("*показываем хинт на закрытие zz");

        private.HintShowZZClose( rm, place );

      else

        local fx_res = "assets/interface/resources/hint_effect/pfx_line2";
        local fx_res2 = "assets/interface/resources/hint_effect/pfx_circle2";
        local tfly = 1;
        local talp1 = 1;
        local talp2 = 1.5;
        local cor = 0;
        local zzcorx, zzcory = 0, 0;
        local px,py = ObjGet(place).pos_x, ObjGet(place).pos_y;

        --DbgTrace( "int.deploy_inventory.show_obj "..int.deploy_inventory.show_obj );

        if ( not int_complex_inv.IsOnScreen() ) and string.match( place, "inv_" ) then

          --DbgTrace("*действие в сложном предмете, но сложный предмет не открыт");

          local pxy = GetObjPosByObj( place );

          px = pxy[1];
          py = 722;

          if px < 222 then px = 222;
          elseif px > 792 then px = 792;
          end;

        elseif string.match( rm, "zz_" ) then

          --DbgTrace("*показываем хинт в zz = "..rm);

          zzcorx = ObjGet( rm ).pos_x;
          zzcory = ObjGet( rm ).pos_y;

          if ( not zzcorx ) then

            zzcorx = ObjGet( string.sub( rm, 1, -13 ) ).pos_x;  --убираем "_double_hint" из названия zz
            zzcory = ObjGet( string.sub( rm, 1, -13 ) ).pos_y;

          end;

          private.hint.ShowInZz[ rm ] = 1;

        elseif ( int_complex_inv.IsOnScreen() ) and ( prg_name ~= "" ) then

            if ( game.hint[ prg_name ].room == "int_complex_inv" ) then

              --DbgTrace("*открыт сложный предмет и действие в сложном предмете");

              zzcorx = ObjGet( int_complex_inv.GetCurrentName() ).pos_x + 512;
              zzcory = ObjGet( int_complex_inv.GetCurrentName() ).pos_y + 384;

            else

              --DbgTrace("*открыт сложный предмет и действие не в сложном предмете");

              zzcorx = ObjGet( int_complex_inv.GetCurrentName() ).pos_x;   -- + 512
              zzcory = ObjGet( int_complex_inv.GetCurrentName() ).pos_y;   -- + 384

            end;

        elseif ( int_complex_inv.IsOnScreen() ) and ( prg_name == "" ) then

          --DbgTrace("*открыт сложный предмет и действие не в сложном предмете");

          zzcorx = ObjGet( int_complex_inv.GetCurrentName() ).pos_x;   -- + 512
          zzcory = ObjGet( int_complex_inv.GetCurrentName() ).pos_y;   -- + 384

        else
     
          private.hint.ShowInRm[ rm ]=1;    

        end;

  --      if GetWideScreen() == true then 
  --
  --          cor = ld.hint.WIDE_OFFSET_X;
  --
  --      end;

        local trg_after_fx = "";

        ObjCreate( fx,  "partsys" );
        ObjCreate( obj, "obj" );

        ObjSet( obj, { pos_z = 555, pos_x = 0, pos_y = 0 } );
        ObjSet( fx,  { res = fx_res } );

        ObjAttach( fx, obj  );
        ObjAttach( obj, "int_effects_impl" );

        --если это не хинт для "действие в сложном предмете, но сложный предмет не открыт",
        --то ставим частицы, которые подсвечивают место приземления "комметы"
        if not ( ( not int_complex_inv.IsOnScreen() ) and string.match( place, "inv_" ) ) then

          ObjCreate( fx2, "partsys" );
          ObjSet( fx2, { res = fx_res2, pos_x = zzcorx + px, pos_y = zzcory + py, active = 0 } );
          ObjAttach( fx2, obj );

          trg_after_fx = ObjSet(fx2, { active = 1 } );

        end;

        local interp1 = math.random( 1, 2 );
        local interp2 = 1;
        if interp1 == 1 then interp2 = 2 end;

        ObjAnimate( fx, "pos_x", 0, 0, "", 
        { 
          0.0,  0,       private.hint.POS_OFFSET_X, 
          tfly, interp1, zzcorx + px 
        } );

        ObjAnimate( fx, "pos_y",0,0, trg_after_fx, 
        { 
          0.0,        0,         675, 
          tfly, interp2, zzcory + py 
        } );

        ObjAnimate( fx, "alp", 0, 0, "", 
        { 
          0.0,  0, 1, 
          tfly, 0, 1, 
          tfly + talp1 * 1, 2, 0 
        } );
    
        ObjAnimate( obj, "alp", 0, 0, function () private.HintFxDel(rm, obj); end, 
        { 
          0.0,          0, 1.0, 
          tfly + talp1, 0, 1.0, 
          tfly + talp1 + talp2, 0, 0.0
        } );

      end;

    end;

  end;
  ----------------------------------------------------------------------------------
  function private.HintShowZZClose( rm, place )

    local obj     = "obj_hint_place_"..place;
    local fx2     = "fx_hint_place_"..place.."_2";
    local fx_res2 = "assets/interface/resources/hint_effect/pfx_circle2";

    if (ObjGet( obj ) == nil) then

      ObjCreate( fx2, "partsys" );
      ObjCreate( obj, "obj" );
      ObjSet( fx2, { res = fx_res2 } );
      ObjAttach( fx2, obj );
      ObjAttach( obj, "obj_int_frame_subroom_button" );

      ObjAnimate( fx2, "scale_xy", 0, 0, "", 
      { 
        0.0,  0, 0.0, 0.0, 
        0.75, 0, 1.0, 1.0 
      } );

      ObjAnimate( obj, "alp", 0, 0, function () private.HintFxDel(rm, obj); end, 
      { 
        0.0,  0, 1.0, 
        0.75, 0, 1.0, 
        1.5,  0, 0.0 
      } );

    end;

  end;
  ----------------------------------------------------------------------------------
  function private.HintFxDel( rm, object )

    --DbgTrace("*ld.hint.HintFxDel, object = "..object);

    ObjDelete( object );

    if string.match( rm,"zz_" ) then 

      private.hint.ShowInZz[ rm ] = nil;

    else

      private.hint.ShowInRm[ rm ] = nil;   
       
    end

  end;
  ----------------------------------------------------------------------------------
  --preclose ZZ,
  function private.HintFxZzSoftClear( zz )

    local obj = "obj_hint_place_"..zz;

    if ObjGet( obj ) then

      ObjAnimate( obj, "alp", 0, 0, function () private.HintFxDel(zz, obj); end, 
      { 
        0.0,  0, ObjGet( obj ).alp, 
        0.25, 0,                 0 
      } );

    end;

  end;
  ----------------------------------------------------------------------------------
  --preopen zz 
  --preclose rm,mg
  function private.HintFxRmSoftClear( rm )

    local obj = "obj_hint_place_"..rm;

    if ObjGet( obj ) then

      ObjAnimate( obj, "alp", 0, 0, function () private.HintFxDel(rm, obj); end, 
      { 
        0.0,   0, ObjGet( obj ).alp, 
        0.25,  0,                 0 
      } );

    end;

  end;
  ----------------------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** MultyObject *** () end ******************************************************************************
--*********************************************************************************************************************
  --------------------------------------------------------------------
  function public.GetMultyObject( mult_name, count_multobj )

    local sum = 0;

    for i = 1, count_multobj do

      if cmn.IsEventDone( "get_"..mult_name..i ) then

        sum = sum + 1;

        ObjSet( "inv_"..mult_name..i, { alp = 1 } );

      else

        ObjSet( "inv_"..mult_name..i, { alp = 0 } );

      end;

      ObjSet( "inv_"..mult_name.."_num"..i, { alp = 0 } );

    end;

    ObjSet( "inv_"..mult_name.."_num"..sum, { alp = 1 } );

  end;
  --------------------------------------------------------------------
  function public.CheckMultiObject( name_obj, count )

    local count_prg = 0;

    for i = 1, count, 1 do

      if cmn.IsEventDone( "get_"..name_obj..i ) then

        count_prg = count_prg + 1;

      end;

    end;

    if count_prg == count then

      return true;

    end;

    return false;

  end;
  --------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** Lock *** () end *************************************************************************************
--*********************************************************************************************************************
  --------------------------------------------------------------------
  --если нет params блочит/разблочит все
  --params - массив вида { interface = 1, room = 1 }
  function public.Lock( state, params )

    local room = "";
    if common.IsInSubRoom() then
      room = common.GetCurrentSubRoom();
    else
      room = GetCurrentRoom();
    end;

    --DbgTrace( "***cmn.Lock: state = "..state..", room = "..room );

    if state == 0 then

        interface.InterfaceSetInput(1);
        ObjSet( room, { input = 1 } );

    else

      if params then

        if params.interface then

          interface.InterfaceSetInput(0);

        end;

        if params.room then

          ObjSet( room, { input = 0 } );

        end;

      else

        local type_room = cmn.GetObjectPrefix( room );

        interface.InterfaceSetInput(0);

        if type_room ~= "ho" then
          ObjSet( room, { input = 0 } );
        end;

      end;

    end;

  end;
  --------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** Video *** () end ************************************************************************************
--*********************************************************************************************************************
--------------------------------------------------------------------
  function public.PlayFullscreenVideo( vidname, trg, mus, voc, skipmus, skiptime )

    trg = trg or "";
    mus = mus or "";
    voc = voc or "";
    skipmus = skipmus or 1;
    skiptime = skiptime or 3.5;

    --DbgTrace("***cmn.PlayFullscreenVideo: vidname = "..vidname..", trg = "..tostring(trg)..", mus = "..mus..", voc = "..voc);

    ObjSet( "vid_fullscreen_video", {res = vidname, pos_x = 512, pos_y = 384, pos_z = 1000, input = 1, active = 1, alp = 1 } );

    if mus ~= "" then
      public.PlayAudio( "vid_mus", mus );
    end;

    if voc ~= "" then
      public.PlayAudio( "voc", voc );
    end;

    local EndTrg  = function () private.StopFullscreenVideo( trg, mus, voc, 0, skipmus ); end;
    local SkipTrg = function () private.StopFullscreenVideo( trg, mus, voc, 1, skipmus ); end;

    interface.DialogVideoShow( "vid_fullscreen_video", 0, SkipTrg, skiptime );
    VidPlay('vid_fullscreen_video', EndTrg);

  end;
  --------------------------------------------------------------------
  function private.StopFullscreenVideo(trg, mus, voc, skip, skipmus)

    --DbgTrace("***private.StopFullscreenVideo: trg = "..tostring(trg)..", mus = "..mus..", voc = "..voc..", skip = "..skip);

    if skip == 1 then

      if skipmus == 1 then
        public.StopAllMus();
      end;

      if voc ~= "" then
        SndStop( voc, 0.5 );
      end;

    end;

    ObjAnimate("vid_fullscreen_video", 8,0,0, function () VidStop('vid_fullscreen_video'); end, {0,0,1, 0.5,0,0});

    interface.DialogVideoHide();
    
    if trg ~= "" then
      trg();
    end;
   
  end;
  --------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** CutScenes *** () end ************************************************************************************
--*********************************************************************************************************************
--------------------------------------------------------------------
  private.cs_sub_timers = {};    --тайминги сабов для катсцен
  --------------------------------------------------------------------
  --показать субтитры к кат-сцене
  function private.PlayCutSceneSub( name, index_obj )

    interface.DialogVideoSubtitleHide(); 
    interface.DialogVideoSubtitleShow( "s_cs_"..name.."_"..index_obj );

    local trg_after;

    if index_obj < #private.cs_sub_timers then

      trg_after = function ()
        private.PlayCutSceneSub( name, (index_obj+1) );
      end;
      
      -- пока показаны не все субтитры
      ObjSet( "tmr_common_cutscene", { endtrig = trg_after, time = ( private.cs_sub_timers[ index_obj + 1 ] - private.cs_sub_timers[ index_obj ] ), playing = 1 } );

    end;

  end;
  ----------------------------------------------
  --запуск кат-сцены
  function public.PlayCutScene( name, vidname, timers, trg, mus, voc )

    private.cs_sub_timers = timers;

    trg = trg or "";
    mus = mus or "";
    voc = voc or "";

    if mus ~= "" then
      public.PlayAudio( "mus", mus );
    end;

    if voc ~= "" then
      public.PlayAudio( "voc", voc );
    end;

    local obj_name = "cs_"..name;

    local EndTrg  =  function () private.StopCutScene( trg, obj_name, voc, 0 ); end;
    local SkipTrg  = function () private.StopCutScene( trg, obj_name, voc, 1 ); end;

    ObjCreate( obj_name, "anim" );

    ObjSet( obj_name, { res = vidname, pos_x = -171, pos_y = 0, pos_z = 1000, input=1, playing=1, animfunc = 'DoAnim', inputrect_init = 1, inputrect_w = 1366, inputrect_h = 768 } );

    interface.DialogVideoShow( obj_name, 1, SkipTrg, 3.5 );
    AnimPlay( obj_name, "DoAnim", EndTrg );

    ObjAttach( "tmr_common_cutscene", "cmn_timers" );

    ObjSet("tmr_common_cutscene", { endtrig = function () private.PlayCutSceneSub(name, 1 ); end, time = private.cs_sub_timers[1], playing = 1 } );

  end;
  --------------------------------------------------------------------
  function private.StopCutScene( trg, obj_name, voc, skip )

    if skip == 1 then

      public.StopAllMus();

      if voc ~= "" then
        SndStop( voc, 0.5 );
      end;

    end;

    AnimStop( obj_name );

    interface.DialogVideoSubtitleHide();
    interface.DialogVideoHide();

    if trg ~= "" then
      trg();
    end;

    private.cs_sub_timers = {};

    local trg_after = function ()
      ObjDelete(obj_name);
      ObjDetach( "tmr_common_cutscene" );
    end;

    ObjSet( "tmr_common_cutscene", { endtrig = trg_after, time = 0.7, playing = 1 } );

  end;
  --------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** Audio *** () end ************************************************************************************
--*********************************************************************************************************************
--------------------------------------------------------------------
  private.audio = {};
  private.audio.env = {};    --таблица проигрываемых енвов
  private.audio.mus = "";    --проигрываемая музыка
  --------------------------------------------------------------------
  function public.PlayAudio( type, sound, need_loop )

    if ( type == "snd" ) then

      PlaySfx( sound, 0, "", 0.1 );

    elseif ( type == "env" ) then

      if ( not private.audio.env[ sound ] ) then

        private.audio.env[ sound ] = 1;

        PlayEnv( sound, 1, 1);

      end;

    elseif ( type == "mus" ) then

      public.StopAllMus();

      need_loop = need_loop or 0;

      private.audio.mus = sound;

      PlaySoundtrack( sound, need_loop, "", 0.1 );

    elseif ( type == "vid_mus" ) then

      public.StopAllMus()

      private.audio.mus = sound;

      PlaySfxTrack( sound, 0, 0 );

    elseif ( type == "voc" ) then

      PlayVoice( sound, 0, "", 0 ); 

    end;

  end;
  --------------------------------------------------------------------
  function public.StopAllEnv( sound )

    sound = sound or "";

    for key, value in pairs(private.audio.env) do

      if ( key ~= sound ) then

        private.audio.env[ key ] = nil;

        SndStop( key, 1 );

      end;

    end;

  end;
  --------------------------------------------------------------------
  function public.StopAllMus()

    if ( private.audio.mus ~= "" ) then

      SndStop( private.audio.mus, 0.5 );

      private.audio.mus = "";

    end;

  end;
  --------------------------------------------------------------------
  function public.PauseAllEnv()

    for key, value in pairs(private.audio.env) do

      if ( value ~= 0 ) then

        private.audio.env[ key ] = 0;

        SndStop( key, 1 );

      end;

    end;

  end;
  --------------------------------------------------------------------
  function public.UnPauseAllEnv()

    for key, value in pairs(private.audio.env) do

      if ( value == 0 ) then

        private.audio.env[ key ] = 1;

        PlayEnv( key, 1, 1);

      end;

    end;

  end;
  --------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** BBT *** () end **************************************************************************************
--*********************************************************************************************************************
  --------------------------------------------------------------------
  private.wrongapply_bbt_lock = false;   --блочим вывод ббт во время WrongApply

  function public.WrongApply()

    if not ( ng_global.gamemode == 3 and ng_global.custom_gamemode.texts == 0 ) then

      interface.BBTShow( "bbt_wrongapply" );

      private.wrongapply_bbt_lock = true;

      ObjAttach( "tmr_common_wrongapply_bbt_lock", "cmn_timers" );

      ObjSet( "tmr_common_wrongapply_bbt_lock", {
        endtrig = function () private.wrongapply_bbt_lock = false; ObjDetach( 'tmr_common_wrongapply_bbt_lock' ); end,
        time = 0.3,
        playing = 1
      } );

    end;

    --public.PlayAudio( "snd", "assets/levels/common/audio/aud_take_stuff_2" );

  end;
  --------------------------------------------------------------------
  function public.ShowBbt( bbt_text )

    if not ( ng_global.gamemode == 3 and ng_global.custom_gamemode.texts == 0 ) and ( not private.wrongapply_bbt_lock ) then

      bbt_text = bbt_text or "";

      bbt_text = "bbt_"..bbt_text;

      interface.BBTShow( bbt_text );

    end;

  end;
  --------------------------------------------------------------------
  function public.ShowDlgBbt( bbt_text )

    bbt_text = bbt_text or "";

    bbt_text = "bbt_"..bbt_text;

    interface.BBTShow( bbt_text );

  end;
  --------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** Note *** () end *************************************************************************************
--*********************************************************************************************************************
  --------------------------------------------------------------------
  private.note = "";       --открытая записка
  private.note_mup = "";   --функция клика открытой записки
  --------------------------------------------------------------------
  function public.ShowNote( note_obj_2 )

    local cur_room = GetCurrentRoom();
    if common.IsInSubRoom() then
      cur_room = common.GetCurrentSubRoom();
    end;

    private.note = note_obj_2;

    interface.BBTShow( "bbt_"..note_obj_2 );
    public.PlayAudio( "snd", "assets/levels/common/audio/aud_paperzoom" );

    ObjAttach( "spr_common_note_back", cur_room );

    if cmn.GetObjectPrefix( cur_room ) ~= "zz" then
      ObjSet( "spr_common_note_back", { pos_x = 512, pos_y = 384, scale_x = 23, scale_y = 13, alp = 0, pos_z = ObjGet( note_obj_2 ).pos_z - 1 } );
    else
      ObjSet( "spr_common_note_back", { pos_x = 0, pos_y = 0, scale_x = 23, scale_y = 13, alp = 0, pos_z = ObjGet( note_obj_2 ).pos_z - 1 } );
    end;

    ObjAnimate( "spr_common_note_back", "alp", 0, 0, "", { 0, 0, 0,   0.3, 0, 0.5 } );
    ObjAnimate( note_obj_2,             "alp", 0, 0, "", { 0, 0, 0,   0.3, 0, 1 } );

    ObjSet( note_obj_2, { input = 1 } );

  end;
  --------------------------------------------------------------------
  function public.HideNote( hide_anm )

    if ( private.note ~= "" ) then

      hide_anm = hide_anm or 1;

      local note_obj_2 = private.note;

      if hide_anm == 1 then

        private.note_mup = ObjGet( note_obj_2 ).event_mup;

        local note_obj_2_alp = ObjGet( note_obj_2 ).alp;
        local note_back_alp  = ObjGet( "spr_common_note_back" ).alp;

        local func_after = function ()
          ObjSet( note_obj_2, { input = 0, event_mup = private.note_mup, event_menter = function () SetCursor( CURSOR_HAND ); end } );
          private.note = "";
          private.note_mup = "";
        end;

        SetCursor( CURSOR_DEFAULT );

        ObjSet( note_obj_2, { event_mup = "", event_menter = function () SetCursor( CURSOR_DEFAULT ); end } );

        ObjAnimate( "spr_common_note_back", "alp", 0, 0, function () ObjDetach( 'spr_common_note_back' ); end, { 0, 0, note_back_alp,    0.3, 0, 0 } );

        ObjAnimate( note_obj_2,             "alp", 0, 0, func_after,                                           { 0, 0, note_obj_2_alp,   0.3, 0, 0 } );

      else

        if ( private.note_mup == "" ) then

          private.note_mup = ObjGet( note_obj_2 ).event_mup;

        end;

        ObjStopAnimate( 'spr_common_note_back', 8 );
        ObjSet( "spr_common_note_back", { alp = 0 } );
        ObjDetach( 'spr_common_note_back' );

        ObjStopAnimate( note_obj_2, 8 );
        ObjSet( note_obj_2, { alp = 0, input = 0, event_mup = private.note_mup, event_menter = function () SetCursor( CURSOR_HAND ); end } );

        private.note = "";
        private.note_mup = "";

      end;

    end;

  end;
  --------------------------------------------------------------------
  function public.GetCurrentNote()

    return private.note;

  end;
  --------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** Tutorial *** () end**********************************************************************************
--*********************************************************************************************************************
  public.tutorial = {}
  public.tutorial.current = "";
  -------------------------------------------------------------------------------------
  function public.tutorial.TutorialShow( prg_name, input, pos_x, pos_y, arrows )

    if ( not cmn.IsEventDone ( prg_name ) ) then

      if ( ng_global.gamemode < 1 ) or ( ng_global.gamemode == 3 and ng_global.custom_gamemode.tutorial == 1 ) then

        public.tutorial.current = prg_name;

        local str_text = "str_"..prg_name;

        if ( prg_name ~= "tutor_enable" ) then

          ObjSet("txt_int_tutorial_buttons_left", { text = "str_int_tutorial_ok" });
          ObjSet("txt_int_tutorial_buttons_right", { text = "str_int_tutorial_skip" });

          ObjSet("spr_int_tutorial_buttons_left_text", { scale_x = 0.5 });
          ObjSet("spr_int_tutorial_buttons_right_text", { scale_x = 0.5 });

          ObjSet("obj_int_tutorial_buttons_center",  { active = 0, visible = 0, input = 0 });

          ObjSet("obj_int_tutorial_buttons_left",  { event_mdown = function () int_tutorial.MouseDown('ok'); end, pos_x = -137 });
          ObjSet("obj_int_tutorial_buttons_right", { event_mdown = function () int_tutorial.MouseDown('skip'); end, pos_x = 137 });

        end;

        if ( ObjGet( "obj_tutorial_"..prg_name ) ) then

          --DbgTrace("***block on "..prg_name );

          ObjSet( "obj_tutorial_"..prg_name, { input = 1 } );

        end;

        interface.TutorialShow( str_text, 1, pos_x, pos_y, arrows );

      else

        ng_global.progress["std"][ prg_name ].done = 1;

      end;

    end;

  end;
  -------------------------------------------------------------------------------------
--*********************************************************************************************************************
--***function *** Achievements *** () end**********************************************************************************
--*********************************************************************************************************************
  public.pause_achiev = 0;  --флаг, нужно ли запаузить отображение ачивок, например на время проигрывания видео
  public.paused_achiev_tab = {};  --список ачивок которые нада показывать не сразу, например после видео
  ------------------------------------------------
  function public.PauseAchiev(num)

    public.pause_achiev = num;


    if ( num == 0 ) then

      for i = 1, #public.paused_achiev_tab, 1 do

        interface_impl.ShowAchiev( public.paused_achiev_tab[i] );

      end;

      public.paused_achiev_tab = {};

    end;

  end;
  ------------------------------------------------
  function public.CheckAchiev(name)

    if IsCollectorsEdition() or IsSurveyEdition() then

      if name == "mg" then
        public.CompleteAchiev("one_mg_without_skip");
        public.CompleteAchiev("three_mg_without_skip");
        public.CompleteAchiev("seven_mg_without_skip");
        public.CompleteAchiev("fifteen_mg_without_skip");
        public.CompleteAchiev("all_mg_without_skip");
      elseif name == "ho" then
        public.CompleteAchiev("one_ho_without_hint");
        public.CompleteAchiev("three_ho_without_hint");
        public.CompleteAchiev("five_ho_without_hint");
        public.CompleteAchiev("ten_ho_without_hint");
        public.CompleteAchiev("all_ho_without_hint");
      end;

    end;

  end;
  ------------------------------------------------
  function public.CompleteAchiev(name)

    if IsCollectorsEdition() or IsSurveyEdition() then

      ng_global.achiev[name][1] = ng_global.achiev[name][1] + 1;
      achiev_state = ng_global.achiev[name][1];

      if ( public.pause_achiev == 0 ) then

        interface_impl.ShowAchiev(name);

      else

        public.paused_achiev_tab[#public.paused_achiev_tab + 1] = name;

      end;

      ----------
      --узнаем сколько ачивок уже открыто
      local local_arr = game.rm_achievements_array;
      local local_count = 0;

      if (local_arr) then

        for i = 1, #local_arr, 1 do

          if ng_global.achiev[""..local_arr[i]..""][1] >= ng_global.achiev[""..local_arr[i]..""][3] then

            local_count = local_count + 1;

          end;

        end;

      end;

      --если собраны все ачивки
      if local_count >= 25 then

        --даем ачивку за все ачивки
        ng_global.achiev["collector"][1] = ng_global.achiev["collector"][1] + 1;
        achiev_state = ng_global.achiev["collector"][1];
        interface_impl.ShowAchiev("collector");

      end;

    end;

  end;
  ------------------------------------------------
  function public.StartTimePassing( room_name )

    if IsCollectorsEdition() or IsSurveyEdition() then

      local ind = 0;

      ObjAttach( "tmr_common_achiev", room_name );

      if (ng_global.start_room) then

        for i = 1, #ng_global.start_room, 1 do

          if ng_global.start_room[i][1] == room_name then

            ind = i;
            break;

          end;

        end;

      else 

        --ng_global.start_room[1][1] = room_name;
        --ind = 1;

      end;

      if cmn.GetObjectPrefix( room_name ) == "ho" then

        if ind == 0 then
          public.num_currentho = true;
        else
          public.num_currentho = false;
        end;

      end;

      if ind ~= 0 then

        ng_global.start_room[ ind ][ 2 ] = ng_global.start_room[ ind ][ 2 ] + 1;

      else

        if (ng_global.start_room) then
          ng_global.start_room[ #ng_global.start_room + 1 ] = {room_name, 1};
        else
          ng_global.start_room[ 1 ] = {room_name, 1};
        end;
        
        ObjSet("tmr_common_achiev", {playing = true, time = 600, endtrig = function () ObjSet('tmr_common_achiev', {playing = false}); end});

      end;

    end;


  end;
  ------------------------------------------------
  function public.EndTimePassing( room_name )

    if IsCollectorsEdition() or IsSurveyEdition() then

      local ind = 0;
      local start_len = 0;

      if (ng_global.start_room) then

        start_len = #ng_global.start_room;

        for i = 1, start_len, 1 do

          if ng_global.start_room[i][1] == room_name then

            ind = i;
            break;

          end;

        end;

      else 

        ng_global.start_room[1][1] = room_name;
        ind = 1;
        start_len = 1;

      end;

      --DbgTrace("start_len "..start_len.." ind "..ind);

      if ( start_len ~= 0 ) and ( ind ~= 0 ) then

        local prefix = cmn.GetObjectPrefix( room_name );
        local rm_nme = cmn.GetObjectName( room_name );

        --DbgTrace("prefix "..prefix.." rm_nme "..rm_nme);
        
        if not ( prefix == "mg" and ng_global.progress[ prg.current ][ "win_"..rm_nme ].skip == 1 ) then

          public.StopwatchHoClose();

          if ( ng_global.start_room[ ind ][ 2 ] == 1 ) then

            local tme = ObjGet("tmr_common_achiev").time;
            --DbgTrace("tme "..tme);

            if ( ( prefix == "mg" ) or ( prefix == "ho" ) ) and ( ( 600 - tme ) <= 60 ) then

              public.CompleteAchiev("one_"..prefix.."_less_one_min");

            end;

            if prefix == "ho" then

              if ( tme == 0 ) and ( cmn.GetObjectPrefix(GetCurrentRoom()) == "ho" ) then

                public.CompleteAchiev("one_ho_more_ten_min");

              elseif ( 600 - tme ) <= 180 then

                ng_global.ho_count = ng_global.ho_count + 1;

                if ( ng_global.ho_count == 10 ) and ( ng_global.achiev["ten_ho_three_min"][1] == 0 ) then

                  public.CompleteAchiev("ten_ho_three_min");

                elseif ( ng_global.ho_count == 5 ) and ( ng_global.achiev["five_ho_three_min"][1] == 0 ) then

                  public.CompleteAchiev("five_ho_three_min");

                elseif ( ng_global.ho_count == 3 ) and ( ng_global.achiev["three_ho_three_min"][1] == 0 ) then

                  public.CompleteAchiev("three_ho_three_min");

                end;

              elseif ( 600 - tme ) > 180 then

                ng_global.ho_count = 0;

              end;

            end;

          end;

        end;

        ObjSet("tmr_common_achiev", {playing = false});

        table.remove(ng_global.start_room, ind);

      end;

    end;


  end;
  -----Быстрые клики в ХО-------------------------------------
  ------------------------------------------------------------

  --Для старта таймера
  function public.StopwatchHoStart()

    if IsCollectorsEdition() or IsSurveyEdition() then
    
      local ho_name = GetCurrentRoom();
      local name_cut = cmn.GetObjectName( ho_name );
      local tmr_name = "tmr_"..name_cut.."_object_achiev";

      if not ObjGet( tmr_name ) then

        ObjCreate( tmr_name, "timer" );
        ObjAttach( tmr_name, ho_name );

      end;
      
      ObjSet( tmr_name, 
      { 
        time = 0,
        infinite = 1,
        playing = 1
      } );

    end;

  end;

  -------------------------------------------------------
  --Приостановка для анализа массива засеченных значений времени после клика по объекту
  function public.StopwatchHoEnd()

    if IsCollectorsEdition() or IsSurveyEdition() then

        local name_full = GetCurrentRoom();
        local name_cut  = cmn.GetObjectName( name_full );
        local tmr_name = "tmr_"..name_cut.."_object_achiev";
              
        local time = ObjGet( tmr_name ).time;

        ObjSet( tmr_name, 
        { 
          playing = 0,
          time = 0
        } );

        if public.achiev.stopwatch then

          table.insert( public.achiev.stopwatch, time );

        else

          public.achiev.stopwatch = {};
          public.achiev.stopwatch[ 1 ] = time;

        end;  

        ----------------------------------------------------------------------------------------
        ----Подсчет подбора за { 3, 5, 10 } сек------------------------------------------------------------
        local s_element = public.achiev.stopwatch;
        --0
        if #s_element > 2 then

          --1
          for i = 0, #s_element, 1 do

            local count = { 0, 0, 0 };
            local get_ach = { false, false, false };
            local exit = false;
            --2
            for j = 1, 3 do

              if s_element[ i + j ] then
                count[ 1 ] = count[ 1 ] + s_element[ i + j ];
              else
                exit = true;
                break;
              end;
            end;

            if exit then

            else

              if count[ 1 ] <= 3 and ( ng_global.achiev["three_item_ho"][1] == 0 ) then

                DbgTrace( "GET ACHIEVEMETS - 3 SEC" );
                public.CompleteAchiev("three_item_ho");
           
              end;

            end;

            for j = 1, 5 do
              if s_element[ i + j ] then
                count[ 2 ] = count[ 2 ] + s_element[ i + j ];
              else
                exit = true;
                break;
              end;
            end;

            if exit then

            else

              if count[ 2 ] <= 5 and ( ng_global.achiev["five_item_ho"][1] == 0 ) then

                DbgTrace( "GET ACHIEVEMETS - 5 SEC" );
                public.CompleteAchiev("five_item_ho");
           
              end;

            end;

            for j = 1, 10 do
              if s_element[ i + j ] then
                count[ 3 ] = count[ 3 ] + s_element[ i + j ];
              else
                exit = true;
                break;
              end;
            end;

            if exit then

            else

              if count[ 3 ] <= 10 and ( ng_global.achiev["ten_item_ho"][1] == 0 ) then

                DbgTrace( "GET ACHIEVEMETS - 10 SEC" );
                public.CompleteAchiev("ten_item_ho");

              end;
            end;
            
            --2

          end;
          --1
        
        else

          --

        end;
        --0

        ----------------------------------------------------------------------------------------
        ----------------------------------------------------------------------------------------
        local ho_name = cmn.GetObjectName( GetCurrentRoom() );

        local ho_stage = ng_global.progress[ prg.current ][ "win_"..ho_name ].stage;

        if ( ( not ho_stage ) and ( interface_impl.taskpanel_countdown ) and ( interface_impl.taskpanel_countdown > 0 ) ) or
           ( ( ho_stage ) and ( ho_stage[1] <= ho_stage[2] ) ) or
           ( (interface.itempanel) and ( interface.itempanel.countdown ) and ( interface.itempanel.countdown > 0 ) ) then

          ObjSet( tmr_name, 
          { 
            time = 0,
            infinite = 1,
            playing = 1
          } );

        end;

    end;

  end;

  --Выход из ХО

  function public.StopwatchHoClose()

    if IsCollectorsEdition() or IsSurveyEdition() then

      local name_full = GetCurrentRoom();
      if name_full then
        local name_cut  = cmn.GetObjectName( name_full );
        if name_cut then        

          local tmr_name = "tmr_"..name_cut.."_object_achiev";

          public.achiev.stopwatch = {};

          ObjSet( tmr_name, 
          { 
            playing = 0,
            time = 0
          } );   
        end;

      end;
    
    end;

  end;
  ------------------------------------------------
--*********************************************************************************************************************
--***function *** MISC *** () end**********************************************************************************
--*********************************************************************************************************************
  public.go_acievements = false;
  --------------------------------------------------------------------
  function public.Tutorial11_Click()

    public.go_acievements = true;
    public.Tutorial_Click( "empty" );

    int_achiev.GotoAchievements();

    for i = 1, 3, 1 do

      if (ObjGet("spr_int_achiev_"..i).pos_x > -182 ) then
        int_achiev.AchMouseLeave( i );
      end;

    end;

  end;
  --------------------------------------------------------------------
  function public.ShowCursor( cur )

    if ( ng_global.gamemode == 2 ) or ( ng_global.gamemode == 3 and ng_global.custom_gamemode.icon == 0 ) then

      SetCursor( CURSOR_DEFAULT );

    else

      SetCursor( cur );

    end;

  end;
  --------------------------------------------------------------------
  --------------------------------------------------------------------
  function public.ApplyObj( item, area )

    if common.ApplyObj( item, area ) and
       interface.GetCurrentComplexInv() == "" and
       cmn.GetCurrentNote() == "" then
      
      return true;
    
    end;

    return false;

  end;
  --------------------------------------------------------------------
  --------------------------------------------------------------------
  function public.SetPreviousRoom( room )

    cmn.previousroom = room;

  end;
  --------------------------------------------------------------------
  --------------------------------------------------------------------