function OnSceneLoad(screen)
	LoadData(screen)
    DefaultOnSceneLoad('data/Scenes/Minigames/04_puzzle.lua', 'mini_game', 'data/Scenes/03_Dupens_House_Exit_Carriage.lua')
    
    g_screen = screen
    g_timer = screen:GetTimer()
    
    OBJECTS_AMOUNT = 25
        
    skip_minigame = false
    
    Objects = {}
    for i = 1, OBJECTS_AMOUNT do
		Objects[i] = {}
		Objects[i].Entity = g_screen:GetObject('Pazl_'..i)
		Objects[i].Inplace = false
		Objects[i].Lock = false
		Objects[i].RightIndex = i
		Objects[i].AngleIndex = math.random(4)
    end
    
    Slots = {}
    for i = 1, OBJECTS_AMOUNT do
        Slots[i] = {}
        Slots[i].Pos = Vector(Objects[i].Entity:GetX(), Objects[i].Entity:GetY())
    end
    
    for i = 1, OBJECTS_AMOUNT do
	    local margin = 120
        local x = math.random(margin, 1024 - margin)
        local y = math.random(margin, 768 - margin)
		Objects[i].Entity:SetXY(x, y)
		Objects[i].Entity:SetAngle(M_PI_OVER_2 * (Objects[i].AngleIndex - 1))
		Objects[i].Entity:SetZ(100 + i)
    end
        
	delta = 50
	top_z = 140.0
    
    LoadGame()
    
    if IsComplete() then
		GoToMap()
	end
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 LoadGame()
    for i = 1, OBJECTS_AMOUNT do
		if HasGameState('MINI_GAME_04_PUZZLE_STATE', "0"..i) then
			Objects[i].Entity:SetXY(Slots[i].Pos.x, Slots[i].Pos.y)
			Objects[i].Entity:SetAngle(0)
			Objects[i].Inplace = true
			Objects[i].Entity:SetZ(100)
			Objects[i].Entity:GetAnimation():SetColor("0x80FFFFBB")
		end
	end
end

function CheckPuzzlePiecePos(DragObject)
    local x, y = MouseHolder:GetX(), MouseHolder:GetY()
    local new_x, new_y = x, y
    local pun_rad = 230.0
    local change = false
    local delta_y  = 10
    local bottom_y = 768 - RETURN_ZONE_HEIGHT - delta_y
    -- Square zone bottom
    if y > bottom_y then
        new_y = bottom_y
       	change = true
    end
    -- Round zone in right corner
    local r = math.sqrt((1024 - x) ^ 2 + (768 - y) ^ 2)
    if DragObject and r < pun_rad then
		local a = math.atan( (768 - y) / (1024 - x) )
       	new_x = 1024 - pun_rad * math.cos(a)
        if new_y ~= bottom_y then new_y = 768 - pun_rad * math.sin(a) end
       	change = true
    end
    -- Round zone in left corner
    pun_rad = 210.0
    r = math.sqrt(x ^ 2 + (768 - y) ^ 2)
    if DragObject and r < pun_rad then
		local a = math.atan( (768 - y) / x )
       	new_x = pun_rad * math.cos(a)
        if new_y ~= bottom_y then new_y = 768 - pun_rad * math.sin(a) end
       	change = true
    end
    
    if change then MouseHolder:SetXY(new_x, new_y) end
    return change
end

function RotateNote(obj)
    local rot_time = 0.15;
        
    obj.Entity:Rotate(M_PI_OVER_2, rot_time)    -- rotate regardless hot spot change or not
    obj.Lock = true
        
    TimerDoString('IsInplace(' .. obj.RightIndex .. ')', rot_time + 0.01, g_timer)
    TimerDoString('UnlockObject('.. obj.RightIndex ..')', rot_time + 0.01, g_timer)
        
    obj.AngleIndex = obj.AngleIndex + 1
    if obj.AngleIndex == 5 then
        obj.AngleIndex = 1
    end
end

function UnlockObject(index)
    Objects[index].Lock = false
end

function OnUpdate(dt)
    DefaultOnUpdate(dt)
end

function StartDrag(obj)
    if not DragObject then
	    DragObject = obj
	    top_z = top_z + 1
	    DragObject.Entity:SetZ(top_z)
        SetCursor('CursorHand')
    
        game_state.disable_default_zoom_exit = true
    end
end

function UpdateDrag()
    if DragObject then
        DragObject.Entity:SetXY(MouseHolder:GetX(), MouseHolder:GetY())
    end
end

function StopDrag()
	if DragObject then
        SetCursor('CursorDefault')
        
        if not DragObject.Lock then
            UnlockObject(DragObject.RightIndex)
            IsInplace(DragObject.RightIndex)
        end
		
		DragObject = nil
		DragDeltaX = nil
        DragDeltaY = nil
        
        game_state.disable_default_zoom_exit = false
	end
end

function IsInplace(index)
    Objects[index].Entity:SetAngle((Objects[index].AngleIndex - 1) * M_PI_OVER_2)

    if Objects[index].AngleIndex == 1 then
        local delta_x = Slots[Objects[index].RightIndex].Pos.x - Objects[index].Entity:GetX()
        local delta_y = Slots[Objects[index].RightIndex].Pos.y - Objects[index].Entity:GetY()
        if math.abs(delta_x) < delta and math.abs(delta_y) < delta then
            Objects[index].Entity:Move(delta_x, delta_y, 0.2)
            Objects[index].Inplace = true
            Objects[index].Entity:SetZ(100)
            Objects[index].Entity:GetAnimation():SetColor('0x80FFFFBB')
            
            if not HasGameState('MINI_GAME_04_PUZZLE_STATE', "0"..Objects[index].RightIndex) then
                AddGameState('MINI_GAME_04_PUZZLE_STATE', "0"..Objects[index].RightIndex)
            end
        end
    end
    
    TimerDoString('IsComplete()', 0.2 + 0.01, g_timer)
end

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

function OnSceneFree(screen)
    DefaultOnSceneFree()
    FreeData(screen)
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)
    if not DragObject then
        DefaultOnObjectMouseLeave(object)
    end
end

function FinishGame()
	for i = 1, OBJECTS_AMOUNT do
	    Objects[i].Entity:GetAnimation():SetColor("0xFFFFFFFF")
	    Objects[i].Entity:ChangeOpacity(0.0, 1.0, 2.0)
	end
	
    SetLevelCompletedState('DupensHouse')
	TimerDoString('GoToMap()', 2.5, g_screen:GetTimer())
end

function OnObjectMouseDown(object)
    local is_wrong_click = not DefaultOnObjectMouseDown(object)
    local obj_name = object:GetName()
    	
	if not DragObject then
        local Element = GetObjectByName(obj_name)
        
        if Element and not Element.Inplace and not Element.Lock then
            StartDrag(Element)
        end
    end
	
    DefaultOnObjectMouseDownProcessed(is_wrong_click)
end

function OnObjectMouseUp(object)
    --DefaultOnObjectMouseUp(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
        RotateNote(obj)
    end    
end

function OnObjectRightMouseUp(object)
end

function SkipMiniGame()
	if skip_minigame == false then
		for i = 1, OBJECTS_AMOUNT do
			if Objects[i].Inplace == false then
				local af = CreateAnimationEffector()
				af:AttachTo(Objects[i].Entity);
				af:SetMode(_ANIM_FWD);
				af:SetKey(_TRACK_A, 0.0, Objects[i].Entity:GetAngle());
				af:SetKey(_TRACK_A, 0.5, 0)
				af:SetKey(_TRACK_X, 0.0, Objects[i].Entity:GetX());
				af:SetKey(_TRACK_X, 0.5, Slots[i].Pos.x)
				af:SetKey(_TRACK_Y, 0.0, Objects[i].Entity:GetY());
				af:SetKey(_TRACK_Y, 0.5, Slots[i].Pos.y)
				af:Play();
				
				if(HasGameState('MINI_GAME_04_PUZZLE_STATE', "0"..Objects[i].RightIndex) == false) then
					AddGameState('MINI_GAME_04_PUZZLE_STATE', "0"..Objects[i].RightIndex);
				end
				
				Objects[i].Inplace = true
			end
		end
		
        TimerDoString('FinishGame()', 0.5, g_screen:GetTimer());
		skip_minigame = true;
	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 then
        CheckPuzzlePiecePos(DragObject)
    end
    
    UpdateDrag()
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/04_puzzle/Pazl1.jpg',0,0,1024,768,1,0)
	anim:SetHotSpot(512,384)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Background',anim,512,384,99,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_01.png',0,0,209,138,1,0)
	anim:SetHotSpot(104,69)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_1',anim,179,92,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_02.png',0,0,256,149,1,0)
	anim:SetHotSpot(128,74)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_2',anim,342,97,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_03.png',0,0,186,133,1,0)
	anim:SetHotSpot(93,66)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_3',anim,484,89,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_04.png',0,0,273,260,1,0)
	anim:SetHotSpot(136,130)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_4',anim,532,153,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_05.png',0,0,245,192,1,0)
	anim:SetHotSpot(122,96)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_5',anim,745,119,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_06.png',0,0,158,173,1,0)
	anim:SetHotSpot(79,86)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_6',anim,867,109,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_07.png',0,0,144,177,1,0)
	anim:SetHotSpot(72,88)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_7',anim,147,224,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_08.png',0,0,335,154,1,0)
	anim:SetHotSpot(167,77)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_8',anim,268,182,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_09.png',0,0,275,218,1,0)
	anim:SetHotSpot(137,109)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_9',anim,703,274,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_10.png',0,0,216,200,1,0)
	anim:SetHotSpot(108,100)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_10',anim,836,209,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_11.png',0,0,335,240,1,0)
	anim:SetHotSpot(167,120)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_11',anim,242,307,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_12.png',0,0,411,183,1,0)
	anim:SetHotSpot(205,91)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_12',anim,524,330,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_13.png',0,0,158,155,1,0)
	anim:SetHotSpot(79,77)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_13',anim,865,322,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_14.png',0,0,163,230,1,0)
	anim:SetHotSpot(81,115)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_14',anim,156,476,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_15.png',0,0,246,150,1,0)
	anim:SetHotSpot(123,75)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_15',anim,309,432,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_16.png',0,0,269,162,1,0)
	anim:SetHotSpot(134,81)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_16',anim,408,410,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_17.png',0,0,178,202,1,0)
	anim:SetHotSpot(89,101)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_17',anim,566,448,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_18.png',0,0,229,160,1,0)
	anim:SetHotSpot(114,80)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_18',anim,732,436,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_19.png',0,0,197,265,1,0)
	anim:SetHotSpot(98,132)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_19',anim,845,472,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_20.png',0,0,307,244,1,0)
	anim:SetHotSpot(153,122)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_20',anim,228,553,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_21.png',0,0,358,203,1,0)
	anim:SetHotSpot(179,101)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_21',anim,511,573,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_22.png',0,0,214,124,1,0)
	anim:SetHotSpot(107,62)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_22',anim,680,551,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_23.png',0,0,252,195,1,0)
	anim:SetHotSpot(126,97)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_23',anim,818,577,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_24.png',0,0,346,125,1,0)
	anim:SetHotSpot(173,62)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_24',anim,342,612,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Minigames/04_puzzle/Pazl_25.png',0,0,216,93,1,0)
	anim:SetHotSpot(108,46)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('Pazl_25',anim,724,628,100,0,1,1)
end

function FreeData(screen)
end
-- CLEAR_ON_SAVE_END
