function OnSceneLoad(screen)
    LoadData(screen)

    local pf = play_field
    local level = pf:GetLevelScreen()
    custom_cursors = {}
    locked_objects = {}
    
    SetContinueMode(1)                              -- в этой миниигре будет работать кнопка "continue"
        
    OBJECTS_AMOUNT = 20
    Objects = {}    -- class for drag objects  

    margin = 70 -- margin window boder when drag
    delta = 30  -- +/- area to match slot
    top_z = 130 -- max object's z-order  
    
    -------------------------------------------------------------------------------------------------------------------------
    function Objects:RotateNote()
        local rot_time = 0.15;
        local orig_hot_x;
        local orig_hot_y;
        -- rotation implemntation during dragging in mouse point hot spot position
        if DragObject then
            local rot_anim = DragObject.Entity:GetAnimation();
            orig_hot_x = rot_anim:GetHotX();    -- save original hot spot
            orig_hot_y = rot_anim:GetHotY();
        
            local angle = -DragObject.Entity:GetAngle();    -- get angle to unwind to 0 angle to proper calculate new hot spot

            local delta_x = DragDeltaX * math.cos(angle) - DragDeltaY * math.sin(angle);    -- calc drag delta if as sprite wasn't
            local delta_y = DragDeltaX * math.sin(angle) + DragDeltaY * math.cos(angle);    -- rotate. (Rotate DragDelta point. Pivot - original hot spot)
        
            local targ_hot_x = orig_hot_x + delta_x;    -- new hot spot
            local targ_hot_y = orig_hot_y + delta_y;       
        
            rot_anim:SetHotSpot(targ_hot_x, targ_hot_y);
            DragObject.Entity:SetXY(DragObject.Entity:GetX() + DragDeltaX, DragObject.Entity:GetY() + DragDeltaY);  -- Correct sprite pos due to hot spot changed
        end
    
        self.Entity:Rotate(M_PI_OVER_2, rot_time)    -- rotate regardless hot spot change or not
        PlaySound("22_mg_rotate")
    
        if DragObject then  -- after rotation while dragging - restore hot spot
            -- transfer to func original values
            TimerDo(g_timer, rot_time, CorrectAfterRotation, DragObject.RightIndex, orig_hot_x, orig_hot_y, DragObject.Entity:GetX(), DragObject.Entity:GetY(), DragDeltaX, DragDeltaY);
        end
    
        self.Lock = true
        if not DragObject then  -- If dragging unlock in CorrectAfterRotation func
            TimerDo(g_timer, rot_time, Objects.UnlockObject, self);
            TimerDo(g_timer, rot_time, Objects.IsInplace, self) -- must check only when not dragging, when drag perform check in Stop Drag
        end
        self.AngleIndex = self.AngleIndex + 1
        if self.AngleIndex == 5 then
            self.AngleIndex = 1
        end
    end
    -------------------------------------------------------------------------------------------------------------------------
    function Objects:UnlockObject()
        self.Lock = false
    end
    -------------------------------------------------------------------------------------------------------------------------
    function Objects:StartDrag()
        DragObject = self
        top_z = top_z + 1
        DragObject.Entity:SetZ(top_z)
        DragDeltaX = GetMousePos().x - DragObject.Entity:GetX()
        DragDeltaY = GetMousePos().y - DragObject.Entity:GetY()
    end
    -------------------------------------------------------------------------------------------------------------------------
    function Objects:IsInplace()
        if self.AngleIndex == 1 then
            local delta_x = self.RightPos.x - self.Entity:GetX()
            local delta_y = self.RightPos.y - self.Entity:GetY()
            if math.abs(delta_x) < delta and math.abs(delta_y) < delta then
                self.Entity:Move(delta_x, delta_y, 0.2)
                self.Inplace = true;
                self.Entity:SetZ(100)
                self.Entity:GetAnimation():SetColor('0xFFFFFFFF')
                TimerDoString('IsCompleted()', 0.2, g_timer)
            end
        end
    end
    --------------------------------------------------------------------------------------------------------------------------

    g_screen = screen
    g_timer = screen:GetTimer()

    Objects.__index = Objects;
    for i = 1, OBJECTS_AMOUNT do
        CreateObjectInArray(i)
    end 
    
    g_screen:GetObject('complete_text'):SetVisible(false)
    g_screen:GetObject('complete_text'):SetOpacity(0)
        
    ShuffleNotes()
end

function ShuffleNotes()
    math.randomseed(os.clock())
    math.random()
    for i = 1, OBJECTS_AMOUNT do
        Objects[i].AngleIndex = math.random(4)
        Objects[i].Entity:SetAngle(M_PI_OVER_2 * (Objects[i].AngleIndex - 1))
        local x = math.random(margin, 1024 - margin)
        local y = math.random(margin, 768 - margin)
        Objects[i].Entity:SetXY(x, y)
    end
end

function CreateObjectInArray(index)
    Objects[index] = {}
    setmetatable(Objects[index], Objects);
    Objects[index].RightIndex = index
    Objects[index].Entity = g_screen:GetObject('piece_'..index)
    Objects[index].RightPos = Vector(Objects[index].Entity:GetX(), Objects[index].Entity:GetY());
    Objects[index].AngleIndex = 1   -- no rotation
    Objects[index].Inplace = false
    Objects[index].Lock = false
end

function GetObjectByName(obj_name)
    for i = 1, OBJECTS_AMOUNT do
        if obj_name == Objects[i].Entity:GetName() then
            return Objects[i]
        end
    end
    return nil
end
    
function CorrectAfterRotation(index, orig_hot_x, orig_hot_y, orig_mouse_x, orig_mouse_y, orig_drag_x, orig_drag_y)
    local rot_anim = Objects[index].Entity:GetAnimation();
    rot_anim:SetHotSpot(orig_hot_x, orig_hot_y);    -- restore hot spot
    
    local angle = -M_PI_OVER_2; -- angel that rotation occur
    
    -- calc rotated delta to set proper XY object coords
    local delta_x = orig_drag_x * math.cos(angle) - orig_drag_y * math.sin(angle);
    local delta_y = orig_drag_x * math.sin(angle) + orig_drag_y * math.cos(angle);
    Objects[index].Entity:SetXY(Objects[index].Entity:GetX() + delta_x, Objects[index].Entity:GetY() + delta_y);
    
    if DragObject then
        -- if we still dragging object set new DragDeltaXY
        DragDeltaX = orig_mouse_x - DragObject.Entity:GetX()
        DragDeltaY = orig_mouse_y - DragObject.Entity:GetY()
    end
    Objects[index]:UnlockObject();    -- now we can unlock object
end

function OnSceneFree()
    FreeData()
end

function OnScreenShown()
end

function ShowMiniGameHelp()
    CreateDialogMiniGameHelp('MINI_GAME_HELP_CHILDREN_PUZZLE')
end

function OnHiddenComics()
end

function OnUpdate(dt)
    UpdateDrag()
    DefaultOnUpdate(dt)
end

function OnLose()
end

function OnExit()
end

function OnObjectMouseEnter(object)
    DefaultOnObjectMouseEnter(object)
end

function OnObjectMouseLeave(object)
    DefaultOnObjectMouseLeave(object)
end

function UpdateDrag()
    if DragObject and not DragObject.Lock then
        local mouse_x = GetMousePos().x - DragDeltaX
        local mouse_y = GetMousePos().y - DragDeltaY
        if mouse_x < margin then
            mouse_x = margin
        elseif mouse_x > 1024 - margin then
            mouse_x = 1024 - margin
        end
        if mouse_y < margin then
            mouse_y = margin
        elseif mouse_y > 768 - margin then
            mouse_y = 768 - margin
        end
        DragObject.Entity:SetXY(mouse_x, mouse_y)
    end
end

function StopDrag()
    if DragObject then
        DragObject:IsInplace();
    
        DragObject = nil
        DragDeltaX = nil
        DragDeltaY = nil
    end
end

function IsCompleted()
    for i = 1, OBJECTS_AMOUNT do
        if not Objects[i].Inplace then
            return false
        end
    end
    MiniGameCompleted(1.0)
    TimerDoString('ShowCompleteText()', 0.5, g_timer)
    
    return true
end

function ShowCompleteText()
    g_screen:GetObject('complete_text'):SetVisible(true)
    g_screen:GetObject('complete_text'):ChangeOpacity(0., 1.0, 1.2)
end

function OnSkipMiniGame()
    if game_state.minigame_complete then
        return
    end
    
    for i = 1, OBJECTS_AMOUNT do
        Objects[i].Entity:Rotate(-(Objects[i].AngleIndex - 1) * M_PI_OVER_2, 1)
        Objects[i].Lock = true
        local delta_x = Objects[i].RightPos.x - Objects[i].Entity:GetX()
        local delta_y = Objects[i].RightPos.y - Objects[i].Entity:GetY()
        Objects[i].Entity:Move(delta_x, delta_y, 1)
        Objects[i].Entity:SetZ(100)
        TimerDoString('Objects[' .. i .. '].Entity:GetAnimation():SetColor("0xFFFFFFFF")', 1, g_timer)
        Objects[i].Inplace = true
    end
    MiniGameCompleted(1.5)
    TimerDoString('ShowCompleteText()', 1.0, g_timer)
end

function OnObjectMouseDown(object)
    obj_name = object:GetName()
    local pf = play_field
    local is_wrong_click = true

--  is_wrong_click = DefaultOnObjectMouseDown(object);
    obj = GetObjectByName(obj_name)
    if obj and obj_name ~= 'background' and not obj.Inplace and not obj.Lock then
        obj:StartDrag();
    end
    
    return is_wrong_click;
end

function OnObjectMouseUp(object)
    StopDrag()
end

function OnObjectRightMouseDown(object)
    obj_name = object:GetName()
    
    obj = GetObjectByName(obj_name)
    if obj and not obj.Inplace and not obj.Lock then
        obj:RotateNote();
    end    
end

function OnObjectRightMouseUp(object)
end

function OnObjectFound(object)
    DefaultOnObjectFound();
end

function OnToolFound(tool)
end

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

function OnButtonPress(title)
    DefaultMinigameOnButtonPress(title)
end

function OnMouseMove(previous_pos, current_pos)
end

function OnSetTool(tool)
end

function OnMinigameCompleted()
end

function OnLostFocus()
    DefaultMinigameOnLostFocus()
end

function OnGainFocus()
    DefaultMinigameOnGainFocus()
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/22_beach_puzzle/background.jpg',0,0,1024,768,1,0)
	anim:SetHotSpot(512,384)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('background',anim,512,384,95,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_1.png',0,0,232,166,1,0)
	anim:SetHotSpot(116,83)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_1',anim,219,134,101,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_2.png',0,0,194,220,1,0)
	anim:SetHotSpot(97,110)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_2',anim,354,161,102,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_3.png',0,0,306,178,1,0)
	anim:SetHotSpot(153,89)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_3',anim,528,140,103,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_4.png',0,0,184,226,1,0)
	anim:SetHotSpot(92,113)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_4',anim,697,164,104,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_5.png',0,0,234,182,1,0)
	anim:SetHotSpot(117,91)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_5',anim,833,142,105,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_6.png',0,0,188,292,1,0)
	anim:SetHotSpot(94,146)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_6',anim,197,287,106,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_7.png',0,0,294,188,1,0)
	anim:SetHotSpot(147,94)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_7',anim,356,282,107,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_8.png',0,0,216,272,1,0)
	anim:SetHotSpot(108,136)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_8',anim,526,282,108,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_9.png',0,0,280,178,1,0)
	anim:SetHotSpot(140,89)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_9',anim,695,291,109,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_10.png',0,0,190,284,1,0)
	anim:SetHotSpot(95,142)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_10',anim,855,289,110,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_11.png',0,0,232,176,1,0)
	anim:SetHotSpot(116,88)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_11',anim,219,439,111,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_12.png',0,0,210,282,1,0)
	anim:SetHotSpot(105,141)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_12',anim,352,439,112,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_13.png',0,0,306,202,1,0)
	anim:SetHotSpot(153,101)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_13',anim,528,438,113,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_14.png',0,0,202,294,1,0)
	anim:SetHotSpot(101,147)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_14',anim,695,445,114,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_15.png',0,0,234,186,1,0)
	anim:SetHotSpot(117,93)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_15',anim,833,442,115,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_16.png',0,0,182,220,1,0)
	anim:SetHotSpot(91,110)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_16',anim,194,562,116,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_17.png',0,0,284,176,1,0)
	anim:SetHotSpot(142,88)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_17',anim,357,585,117,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_18.png',0,0,194,210,1,0)
	anim:SetHotSpot(97,105)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_18',anim,523,568,118,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_19.png',0,0,298,158,1,0)
	anim:SetHotSpot(149,79)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_19',anim,697,594,119,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/piece_20.png',0,0,170,210,1,0)
	anim:SetHotSpot(85,105)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFDDDDDD')
	screen:CreateObject('piece_20',anim,864,567,120,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/22_beach_puzzle/complete_text.jpg',0,0,848,623,1,0)
	anim:SetHotSpot(424,311)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('complete_text',anim,526,360,12,0,1,1)
end

function FreeData(screen)
end
-- CLEAR_ON_SAVE_END
