function OnSceneLoad(screen)
    LoadData(screen)
    DefaultOnSceneLoad('data/Scenes/Minigames/23_flock.lua', 'quest', 'data/Scenes/23_Stateroom_Main.lua')
    
    pf = play_field;
    g_timer = pf:GetTimer();    
    
    minigame_completed = false;
    
    OBJECTS_AMOUNT = 3;
    CreateObjects();
    
    monkey_applied          = false;
    flock_applied           = false;
    boar_wool_applied       = false;
    wolf_wool_applied       = false;
    butterfly_nut_applied   = false;
    staple_01_unscrewed     = false;
    staple_02_unscrewed     = false;
    
    RegisterToolApplyInfo('22_butterfly_nut',
                          'staple',
                          nil,
                          nil,
                          ButterflyNutOnApply,
                          ButterflyNutOnApplied);
                          
    RegisterToolApplyInfo('13_flock',
                          {'area_circle_01', 'area_circle_02', 'area_circle_03'},
                          nil,
                          nil,
                          FlockOnApply,
                          FlockOnApplied);
                          
    RegisterToolApplyInfo('20_boar_wool',
                          {'area_circle_01', 'area_circle_02', 'area_circle_03'},
                          nil,
                          nil,
                          BoarWoolOnApply,
                          BoarWoolOnApplied);
                          
    RegisterToolApplyInfo('20_wolf_wool',
                          {'area_circle_01', 'area_circle_02', 'area_circle_03'},
                          nil,
                          nil,
                          WolfWoolOnApply,
                          WolfWoolOnApplied);
                          
    RegisterToolApplyInfo('23_monkey',
                          'monkey',
                          nil,
                          nil,
                          MonkeyOnApply,
                          MonkeyOnApplied);
    
    RegisterActiveObject('staple_01',   function(obj_name)
                                            play_field:GetObject('staple_01'):GetAnimation():Play();
                                            staple_01_unscrewed = true;
                                            OpenCoverIfNeeded(true);
                                            
                                            PlaySound('23_OpenButterflyNuts1')
                                        end,
                                        function(obj_name)
                                            local anim = play_field:GetObject('staple_01'):GetAnimation();
                                            anim:SetFrame(anim:GetFrames() - 1);
                                            staple_01_unscrewed = true;
                                            OpenCoverIfNeeded();
                                        end);
                                
    RegisterActiveObject('staple_02',   function(obj_name)
                                            play_field:GetObject('staple_02'):GetAnimation():Play();
                                            staple_02_unscrewed = true;
                                            OpenCoverIfNeeded(true);
                                            
                                            PlaySound('23_OpenButterflyNuts2')
                                        end,
                                        function(obj_name)
                                            local anim = play_field:GetObject('staple_02'):GetAnimation();
                                            anim:SetFrame(anim:GetFrames() - 1);
                                            staple_02_unscrewed = true;
                                            OpenCoverIfNeeded();
                                        end);
    
    if not butterfly_nut_applied then
        ShowMonolog('C_23_HINT_BUTTERFLY_NUT_APPLY', 'C_23_HINT_BUTTERFLY_NUT_APPLY');
--    elseif not game_state.cover_open then
    --    ShowMonolog('C_23_HINT_BUTTERFLY_NUT_USE', 'C_23_HINT_BUTTERFLY_NUT_USE');
    elseif not (monkey_applied and flock_applied and boar_wool_applied and wolf_wool_applied) then
        ShowMonolog('C_23_HINT_NOT_ALL_APPLY', 'C_23_HINT_NOT_ALL_APPLY');
    else
        SetFlockPositions() -- needed to keep persistent
    end
    
    if HasGameState('MiniGameCompleted', '23_flock') then
        SkipMiniGame();
    end
end

function CreateObjects()
    Objects = {}
    Objects.__index =  Objects;
    function Objects:SetInplace()
        self.Red:SetVisible(false);
        self.Green:ChangeOpacity(0, 0.4, 0.3);
        self.Inplace = true;
        AddGameState(game_state.scene_path .. self.Index, 'true')
        
        PlaySound('23_GreenLight');
    end
                
    for i = 1, OBJECTS_AMOUNT do
        Objects[i] = {}
        setmetatable(Objects[i], Objects);
        Objects[i].Name = 'flock_0' .. i;
        Objects[i].Entity = pf:GetObject(Objects[i].Name);
        Objects[i].Index = i;
        Objects[i].SrcPos = Vector(Objects[i].Entity:GetX(), Objects[i].Entity:GetY());
        Objects[i].Target = pf:GetObject('area_0' .. i);
        Objects[i].Inplace = false;
        Objects[i].Red = pf:GetObject('light_red_0' .. i);
        Objects[i].Green = pf:GetObject('light_green_0' .. i);        
        Objects[i].Green:SetOpacity(0);
    end
    
    pf:GetObject('staple_02'):SetOpacity(0);
    pf:GetObject('staple_02'):GetAnimation():SetMode(HGEANIM_FWD);
    pf:GetObject('staple_02'):GetAnimation():Stop();
    pf:GetObject('staple_01'):GetAnimation():SetMode(HGEANIM_FWD);
    pf:GetObject('staple_01'):GetAnimation():Stop();
    pf:GetObject('monkey'):SetOpacity(0.01);
    for i = 1, OBJECTS_AMOUNT do
        pf:GetObject('flock_0' .. i):SetOpacity(0.01);
    end
end

function GetObjectByName(obj_name)
    for i = 1, OBJECTS_AMOUNT do
        if Objects[i].Name == obj_name then
            return Objects[i];
        end
    end
    return nil;
end

function SetFlockPositions()
    for i = 1, OBJECTS_AMOUNT do
        if HasGameState(game_state.scene_path .. i) then
            Objects[i].Entity:SetXY(Objects[i].Target:GetX(), Objects[i].Target:GetY());
            Objects[i].Entity:SetOpacity(1);
            Objects[i]:SetInplace();
        end
    end
end

---------------------------------------------------------------
-- Tools funcs
function ButterflyNutOnApply(tool_name)
    play_field:GetObject('staple'):ChangeOpacity(1, 0, 0.5);
    play_field:GetObject('staple_02'):ChangeOpacity(0, 1, 0.5);
    ShowMonolog('C_23_HINT_BUTTERFLY_NUT_USE', 'C_23_HINT_BUTTERFLY_NUT_USE')
    butterfly_nut_applied = true;
    
    PlaySound('23_PlaceButterflyNut');
end

function ButterflyNutOnApplied(tool_name)
    play_field:GetObject('staple_02'):SetOpacity(1);
    play_field:GetObject('staple'):SetVisible(false);
    ShowMonolog('C_23_HINT_BUTTERFLY_NUT_USE', 'C_23_HINT_BUTTERFLY_NUT_USE')
    butterfly_nut_applied = true;
end

-- common flock functions
function CommonOnApply(tool_name, object_name, index)
    -- area - area where tool was applied
    local area = play_field:GetObject(object_name);
    area:SetVisible(false);
    -- save where tool was applied to keep persistent
    AddGameState(game_state.scene_path .. '_area_' .. index, string.sub(object_name, 14)); -- 14 - area_circle_0 - length
    
    local obj = GetObjectByName('flock_0' .. index);
    obj.SrcPos = Vector(area:GetX(), area:GetY());
    
    obj.Entity:SetXY(obj.SrcPos.x, obj.SrcPos.y);
    obj.Entity:ChangeOpacity(0, 1, 0.5);
    CustomToolApply(tool_name); -- needed to stop RegisterToolApplyInfo when it has several targets, and we need only one
end

function CommonOnApplied(tool_name, object_name, index)
    if HasGameState(game_state.scene_path .. '_area_' .. index) then
        -- restore previously saved flock position
        num = GetGameState(game_state.scene_path .. '_area_' .. index):Get(0);
    
        local area = play_field:GetObject('area_circle_0' .. num);
        area:SetVisible(false);

        local obj = GetObjectByName('flock_0' .. index);
        obj.SrcPos = Vector(area:GetX(), area:GetY());

        obj.Entity:SetXY(obj.SrcPos.x, obj.SrcPos.y);
        obj.Entity:SetOpacity(1);
    end
end

function FlockOnApply(tool_name, object_name)
    if object_name then
        -- due to several targets, that are the same to several tools, we need only process issue when object_name ~= nil
        CommonOnApply(tool_name, object_name, 2);
        flock_applied = true;
        SetMiniGame();
    end
end

function FlockOnApplied(tool_name, object_name)
    if not object_name then
        -- due to several targets, that are the same to several tools, we need only process issue when object_name == nil,
        -- that is tool has no more targets (we set it by call to CustomToolApply)
        CommonOnApplied(tool_name, object_name, 2);
        flock_applied = true;
        SetMiniGame();
    end
end

function WolfWoolOnApply(tool_name, object_name)
    if object_name then
        CommonOnApply(tool_name, object_name, 3);
        wolf_wool_applied = true;
        SetMiniGame();
    end
end

function WolfWoolOnApplied(tool_name, object_name)
    if not object_name then
        CommonOnApplied(tool_name, object_name, 3);
        wolf_wool_applied = true;
        SetMiniGame();
    end
end

function BoarWoolOnApply(tool_name, object_name)
    if object_name then
        CommonOnApply(tool_name, object_name, 1);
        boar_wool_applied = true;
        SetMiniGame();
    end
end

function BoarWoolOnApplied(tool_name, object_name)
    if not object_name then
        CommonOnApplied(tool_name, object_name, 1);
        boar_wool_applied = true;
        SetMiniGame();
    end
end

function MonkeyOnApply(tool_name)
    PlaySound('23_GreenLight');
    
    play_field:GetObject('monkey'):ChangeOpacity(0, 1, 0.5);
    monkey_applied = true;
    SetMiniGame();
end

function MonkeyOnApplied(tool_name)
    play_field:GetObject('monkey'):SetOpacity(1);
    monkey_applied = true;
    SetMiniGame();
end
---------------------------------------------------------------

function SetMiniGame()
    if monkey_applied and flock_applied and boar_wool_applied and wolf_wool_applied  then
        game_state.level_mode = 'mini_game';
        play_field:GetLevelScreen():GetPanel():SetMode(PM_MINIGAME)
        
        ShowMonolog('C_23_HINT_ALL_APPLY', 'C_23_HINT_ALL_APPLY');
    end
end

function OpenCoverIfNeeded(b_delay)
    if staple_01_unscrewed and staple_02_unscrewed then
        game_state.cover_open = true;
        
        if b_delay then
            TimerDoString("pf:GetObject('cover'):ChangeOpacity(1, 0, 0.4);"..
                          "ShowMonolog('C_23_HINT_OPEN_COVER', 'C_23_HINT_OPEN_COVER');", 2, g_timer);
        else
            pf:GetObject("cover"):SetOpacity(0);
        end
    end
end

---------------------------------------------------------------
-- Drag functions
function StartDrag(obj)
    DragObject = obj;
    game_state.custom_cursors[DragObject.Name] = 'CursorHand';
    game_state.ignore_on_highlight[DragObject.Name] = true;
    DragObject.Entity:SetZ(DragObject.Entity:GetZ() + 10)
    
    DragDeltaX = GetMousePos().x - DragObject.Entity:GetX()
    DragDeltaY = GetMousePos().y - DragObject.Entity:GetY()
    
    game_state.disable_default_zoom_exit = true
end

function UpdateDrag()
    if DragObject then
        local mouse_x = GetMousePos().x - DragDeltaX
        local mouse_y = GetMousePos().y - DragDeltaY
        DragObject.Entity:SetXY(mouse_x, mouse_y)
    end
end

function StopDrag()
    if DragObject then
        game_state.custom_cursors[DragObject.Name] = nil;
        game_state.ignore_on_highlight[DragObject.Name] = nil;
        pf:IgnoreOnTestPoint(DragObject.Name);
        local x = DragObject.Entity:GetX();
        local y = DragObject.Entity:GetY();
        local obj = pf:FindObjectByPos(Vector(x, y))
        pf:DoNotIgnoreOnTestPoint(DragObject.Name);
        
        local dx, dy;
        
        if obj and obj:GetName() == DragObject.Target:GetName() then
            dx = DragObject.Target:GetX() - x
            dy = DragObject.Target:GetY() - y
            DragObject:SetInplace();
        else
            dx = DragObject.SrcPos.x - x
            dy = DragObject.SrcPos.y - y
        end
        DragObject.Entity:Move(dx, dy, 0.2);
    
        DragObject.Entity:SetZ(DragObject.Entity:GetZ() - 10)
        DragObject = nil;
        DragDeltaX = nil
        DragDeltaY = nil
        IsComplete();
    end
    
    game_state.disable_default_zoom_exit = false
end

---------------------------------------------------------------

function IsComplete()
    for i = 1, OBJECTS_AMOUNT do
        if not Objects[i].Inplace then
            return false;
        end
    end
    
    minigame_completed = true;
    FinishMiniGame();
    return true;
end

function SkipMiniGame()
    for i = 1, OBJECTS_AMOUNT do
        Objects[i].Red:SetVisible(false);
        Objects[i].Entity:SetXY(Objects[i].Target:GetX(), Objects[i].Target:GetY());
    end
    FinishMiniGame();
end

function FinishMiniGame()
    for i = 1, OBJECTS_AMOUNT do
        Objects[i].Green:ChangeOpacity(0.4, 1, 0.3)
    end
    for i = 1, 3 do
        if HasGameState(game_state.scene_path .. '_area_' .. i) then
            RemoveGameState(game_state.scene_path .. '_area_' .. i);
        end
    end
    ---------------------------------------
    if not HasGameState('MiniGameCompleted', '23_flock') then
        AddGameState('MiniGameCompleted', '23_flock');
    end
    if not HasGameState('ClosedScene', game_state.scene_path) then
        AddGameState('ClosedScene', game_state.scene_path);
    end
    ---------------------------------------
--    TimerDoString('RegisterCompleteMiniGame()', 1, g_timer);
    TimerDoString('StartLevel(game_state.parent_scene)', 1, g_timer);
end
--[[
function RegisterCompleteMiniGame()
    StartLevel(game_state.parent_scene);
end
]]

function OnSceneFree(screen)
    DefaultOnSceneFree()
    FreeData(screen)
end

function OnUpdate(dt)
    DefaultOnUpdate(dt)
end

function OnAllItemsFound()
    DefaultOnAllItemsFound()
end

function OnLose()
    DefaultOnLose()
end

function OnExit()
    DefaultOnExit()
end

function OnClose()
    DefaultOnClose()
end

function OnObjectMouseEnter(object)
    DefaultOnObjectMouseEnter(object)
end

function OnObjectMouseLeave(object)
    DefaultOnObjectMouseLeave(object)
end

function OnObjectMouseDown(object)
    local is_wrong_click = not DefaultOnObjectMouseDown(object)
    local obj_name = object:GetName()
    local pf = play_field
    
    if obj_name == 'cover' then
        if not butterfly_nut_applied then
            ShowMonolog('C_23_HINT_BUTTERFLY_NUT_APPLY', 'C_23_HINT_BUTTERFLY_NUT_APPLY');
        elseif not game_state.cover_open then
            ShowMonolog('C_23_HINT_BUTTERFLY_NUT_USE', 'C_23_HINT_BUTTERFLY_NUT_USE');
        end
    end
    
    if obj_name == 'staple' then
        ShowMonolog('C_23_HINT_BUTTERFLY_NUT_APPLY', 'C_23_HINT_BUTTERFLY_NUT_APPLY');
    end
     
    if monkey_applied
        and flock_applied
        and boar_wool_applied
        and wolf_wool_applied
    then
        local obj = GetObjectByName(obj_name);
        if obj and not minigame_completed and not obj.Inplace then
            StartDrag(obj);
        end
    else
        if obj_name == 'monkey'
            or obj_name == 'area_01'
            or obj_name == 'area_02'
            or obj_name == 'area_03'
            or obj_name == 'area_circle_01'
            or obj_name == 'area_circle_02'
            or obj_name == 'area_circle_03'
        then
            ShowMonolog('C_23_HINT_NOT_ALL_APPLY', 'C_23_HINT_NOT_ALL_APPLY');
        end
    end

    DefaultOnObjectMouseDownProcessed(is_wrong_click);
end

function OnObjectMouseUp(object)
    DefaultOnObjectMouseUp(object)
    if DragObject and not minigame_completed then
        StopDrag();
    end
end

function OnObjectFound(object)
    DefaultOnObjectFound(object)
end

function OnToolFound(tool)
    DefaultOnToolFound(tool)
end

function OnToolApply(tool, object)
    DefaultOnToolApply(tool, object)
end

function OnObjectReachPanel(object)
    DefaultOnObjectReachPanel(object)
end

function OnButtonPress(title)
    DefaultOnButtonPress(title)
end

function OnMouseMove(previous_pos, current_pos)
    DefaultOnMouseMove(previous_pos, current_pos)
    
    if DragObject and not minigame_completed then
        UpdateDrag();
    end
end

function OnSetTool(tool)
    DefaultOnSetTool(tool)
end

function LevelLoaded(level)
end

function OnSceneDestroy(playfield)
    DefaultOnSceneDestroy(playfield)
end

--------------------------------------------------------------------------------
-- CLEAR_ON_SAVE_BEGIN
-- Do not edit code listed below (generated by the editor on each save)
function LoadData(screen)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/minigame_background.jpg',0,0,1024,768,1,0)
	anim:SetHotSpot(512,384)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('background',anim,512,384,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/makaka.jpg',0,0,135,141,1,0)
	anim:SetHotSpot(67,70)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('monkey',anim,474,196,101,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/light_green.png',0,0,107,107,1,0)
	anim:SetHotSpot(53,53)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('light_green_01',anim,265,495,101,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/light_green.png',0,0,107,107,1,0)
	anim:SetHotSpot(53,53)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('light_green_02',anim,483,495,101,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/light_green.png',0,0,107,107,1,0)
	anim:SetHotSpot(53,53)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('light_green_03',anim,700,495,101,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/light_red.png',0,0,107,107,1,0)
	anim:SetHotSpot(53,53)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('light_red_01',anim,265,495,102,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/light_red.png',0,0,107,107,1,0)
	anim:SetHotSpot(53,53)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('light_red_02',anim,483,495,102,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/light_red.png',0,0,107,107,1,0)
	anim:SetHotSpot(53,53)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('light_red_03',anim,700,495,102,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/kryshka.png',0,0,908,598,1,0)
	anim:SetHotSpot(454,299)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('cover',anim,520,320,120,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/volos_03_wolf.png',0,0,70,36,1,0)
	anim:SetHotSpot(35,18)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('flock_03',anim,813,223,103,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/volos_02_pig.png',0,0,70,36,1,0)
	anim:SetHotSpot(35,18)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('flock_01',anim,819,310,103,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/volos_01_monkey.png',0,0,70,36,1,0)
	anim:SetHotSpot(35,18)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('flock_02',anim,825,403,103,0,1,1)
	local anim = CreateAnimation('data/Texture/Scenes/Common/area.png',0,0,8,8,1,0)
	anim:SetHotSpot(4,4)
	anim:SetBlendMode(2)
	anim:SetColor('0x01FFFFFF')
	screen:CreateObject('area_01',anim,268,379,101,0,20,10)
	local anim = CreateAnimation('data/Texture/Scenes/Common/area.png',0,0,8,8,1,0)
	anim:SetHotSpot(4,4)
	anim:SetBlendMode(2)
	anim:SetColor('0x01FFFFFF')
	screen:CreateObject('area_02',anim,470,381,101,0,20,10)
	local anim = CreateAnimation('data/Texture/Scenes/Common/area.png',0,0,8,8,1,0)
	anim:SetHotSpot(4,4)
	anim:SetBlendMode(2)
	anim:SetColor('0x01FFFFFF')
	screen:CreateObject('area_03',anim,680,381,101,0,20,10)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/animation.png',0,0,232,117,22,11)
	anim:SetHotSpot(116,59)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('staple_01',anim,138,126,122,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/animation.png',0,0,232,117,22,11)
	anim:SetHotSpot(116,59)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('staple_02',anim,111,419,122,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/23_flock/aaa.png',0,0,133,66,1,0)
	anim:SetHotSpot(66,33)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('staple',anim,129,436,123,0,1,1)
	local anim = CreateAnimation('data/Texture/Scenes/Common/area_circle.png',0,0,128,128,1,0)
	anim:SetHotSpot(64,64)
	anim:SetBlendMode(2)
	anim:SetColor('0x01FFFFFF')
	screen:CreateObject('area_circle_01',anim,817,226,105,0,0.75,0.75)
	local anim = CreateAnimation('data/Texture/Scenes/Common/area_circle.png',0,0,128,128,1,0)
	anim:SetHotSpot(64,64)
	anim:SetBlendMode(2)
	anim:SetColor('0x01FFFFFF')
	screen:CreateObject('area_circle_02',anim,822,314,105,0,0.75,0.75)
	local anim = CreateAnimation('data/Texture/Scenes/Common/area_circle.png',0,0,128,128,1,0)
	anim:SetHotSpot(64,64)
	anim:SetBlendMode(2)
	anim:SetColor('0x01FFFFFF')
	screen:CreateObject('area_circle_03',anim,828,411,105,0,0.75,0.75)
end

function FreeData(screen)
end
-- CLEAR_ON_SAVE_END
