require("libs.global_stuff")
local JSONs = require("libs.JSON")

local Enum = GetEnums()
local MAX_LINES = 32

--// CheckBoxes

function CBTexture(state)
    if state then 
        return GetTextureId("NtUI/other/check_box_fill_3.png")
    else 
        return GetTextureId("NtUI/other/check_box_3.png")
    end 
end

function CBSwitch(img)
    CBSet(img,not CBIsEnable(img))
end

function CBSet(img,state)
    img.textureId = CBTexture(state)
end

function CBIsEnable(img) 
    return img.textureId == CBTexture(true)
end 


--// Image Buttons
function IButtonColor(state)
    if state then 
        return Enum.WHITE
    else 
        return Enum.COLOR_OFF
    end 
end

function IButtonSwitch(img,border_size)
    IButtonSet(img, not IButtonIsEnable(img),border_size)
end

function IButtonSet(img,state,border_size)
    img.color = IButtonColor(state)
    if state then
        img.border = Enum.COLOR_ROUNDED_LOW
        img.thick = border_size or 2
    else
        img.border = 0
    end
end 

function IButtonIsEnable(img)
    return img.color == IButtonColor(true)
end


--// Scroll
function ScrollColor(state)
    if state then 
        return Enum.COLOR_SCROLL_ON
    else 
        return Enum.COLOR_SCROLL_OFF
    end 
end

function ScrollIsEnable(img)
    return img.color == ScrollColor(true)
end

function ScrollSet(img, state)
    img.color = ScrollColor(state)
end


--// JustButton
function ToJustButton(img)
    img.textureId = GetTextureId("NtUI/other/input_box.png")
    IButtonSet(img,false)
    img.color = Enum.COLOR_HEADER
end 
function ToJustArrow(img,start,options,con,bonus)

    --options.icons[icon_count]
    if img.textureId ~= GetTextureId("panorama/images/control_icons/arrow_dropdown_png.vtex_c") then
        img.textureId = GetTextureId("panorama/images/control_icons/arrow_dropdown_png.vtex_c")
        if start and options then
            for i,v in ipairs(options) do 
                if i > start then
                    v.button.visible = false
                    v.discription.visible = false
                    v.key_bg.visible = false
                    v.key_show.visible = false
                    v.draw_procent.visible = false
                    for z,x in ipairs(options.icons) do
                        if x.textureName == v.option_name.text then
                            x.visible = false
                        end
                    end 
                    if v.just_list then
                        for i,v in ipairs(v.just_list) do
                            v.visible = false
                        end
                    end
                end
            end
            options.bg.h = options.bg.h - 25*con*(#options-start+(bonus or 0))
        end
        return false
    else
        img.textureId = GetTextureId("panorama/images/control_icons/arrow_dropdown_up_png.vtex_c")
        if start and options then
            for i,v in ipairs(options) do 
                if i > start then
                    v.button.visible = not v.just_button or not v.just_list
                    v.discription.visible = true
                    if v.key.text ~= "" then
                        v.key_bg.visible = true
                        if v.is_procent or v.is_big_number or v.is_mid_number then
                            v.draw_procent.visible = true
                        else
                            v.key_show.visible = false
                        end
                    end
                    for z,x in ipairs(options.icons) do
                        if x.textureName == v.option_name.text then
                            x.visible = true
                        end
                    end 
                    if v.just_list then
                        for i,v in ipairs(v.just_list) do
                            v.visible = true
                        end
                    end
                end
            end
            options.bg.h = options.bg.h + 25*con*(#options-start+(bonus or 0))
        end
        return true
    end
end 


--// Simple
function ColorSwitch(img,color)
	if img.color == Enum.WHITE then
		img.color = color
	else
		img.color = Enum.WHITE
	end
end

--// Discriptions
--//= Main
function DiscriptionMainDrawImages(info_tables,image,con)
    local linesIcons = ""

    for k in string.gmatch(info_tables[3],'%S+') do
        if k:sub(1,1)=="@" then
            k = k:gsub("[.]","")
            local star = k:sub(2,6)
            if star == "item_" then
                image.help_tips.icons[#image.help_tips.icons+1] = DrawRound(0,0,20*con,16*con,Enum.WHITE,GetTextureId2(k:gsub("@","")),true,4*con)
                linesIcons = linesIcons.." @  "
            else
                image.help_tips.icons[#image.help_tips.icons+1] = DrawRound(0,0,16*con,16*con,Enum.WHITE,GetTextureId2(k:gsub("@",""),star == "npc_d"),true,4*con)
                linesIcons = linesIcons.." @  "
            end
            image.help_tips.icons[#image.help_tips.icons].textureName = star
        else
            linesIcons = linesIcons..k.." "
        end
    end
    return linesIcons
end

function DiscriptionMainProcessText(linesIcons,F14,con)
    local lines = ""
    local helper = {}
    local miss = 0
    local line_size = 234*con
    for word in linesIcons:gmatch("[%z\1-\127\194-\244][\128-\191]*") do
        lines = lines..word
        if lines == "." or lines == "," or lines == "，" then lines = "" end
        local sizes = dota.GetTextSize(F14,lines).x
        if word:byte() == 42 then
            if lines ~= "*" then --or #helper== miss then
                helper[#helper+1] = lines:sub(1, -2)
                miss = #helper
            end
            lines = ""
        elseif word:byte() == 32 or (sizes > 236*con) then
            if lines == " " or lines == " " then lines = "" end
            if sizes > line_size-36*con then
                helper[#helper+1] = lines
                lines = ""
            elseif helper[#helper] and #helper ~= miss and dota.GetTextSize(F14,helper[#helper]).x+sizes < line_size-15*con then
                if lines ~= "- " then
                    helper[#helper] = helper[#helper]..lines
                    miss = #helper
                    lines = ""
                end
            end
        end
    end
    if lines ~= "" then helper[#helper+1] = lines end
    return helper
end 

function DisciptionMainProcessPositions(helper,image,F14,con)
    local icon_count = 0
    local last_line
    local findextra = false
    for a = 1,MAX_LINES do
        local z = helper[a]
        if z then

            if z:find("Extra:") then
                findextra = true
            end
            if findextra then image.help_tips.discr[a].color = Enum.COLOR_EXTRA end

            image.help_tips.discr[a].x = image.help_tips.header.x
            image.help_tips.discr[a].y = image.help_tips.header.y + image.help_tips.y_*a + 10*con
            image.help_tips.discr[a].text = z
            image.help_tips.discr[a].visible = true

            local icon_txt = ""
            for word in z:gmatch("[%z\1-\127\194-\244][\128-\191]*") do
                if word=="@" then
                    icon_count = icon_count+1
                    if image.help_tips.icons[icon_count] then
                        image.help_tips.icons[icon_count].y = image.help_tips.discr[a].y+0
                        image.help_tips.icons[icon_count].x = image.help_tips.discr[a].x+dota.GetTextSize(F14,icon_txt).x-2
                        if image.help_tips.icons[icon_count].textureName and image.help_tips.icons[icon_count].textureName == "item_" then
                            image.help_tips.icons[icon_count].x = image.help_tips.icons[icon_count].x - 2
                        end
                    end
                end
                icon_txt = icon_txt..word
            end
        else
            image.help_tips.discr[a].visible = false
            if not last_line then
                last_line = a
            end
        end
    end
    return icon_count,last_line
end


--//= Help

function DiscriptionHelpDrawImages(string_array,image,con,visible,option_name)    
    local help_new = ""
    -- local img = false
    for k in string_array:gmatch('%S+') do
        if k:sub(1,1)=="@" then
            if k:sub(1,6) ~= "@NtUI/" and k:sub(1,6) ~= "@panor" then
                k = k:gsub("[.]","")
            end
            local star = k:sub(2,6)
            if star == "item_" then
                image.help_tips.icons[#image.help_tips.icons+1] = DrawRound(0,0,20*con,16*con,Enum.WHITE,GetTextureId2(k:gsub("@","")), visible,4*con)
                help_new = help_new.." @  "
            else
                image.help_tips.icons[#image.help_tips.icons+1] = DrawRound(0,0,16*con,16*con,Enum.WHITE,GetTextureId2(k:gsub("@",""),star == "npc_d"), visible,4*con)
                help_new = help_new.." @ "
            end
            image.help_tips.icons[#image.help_tips.icons].textureName = option_name
            -- img = (help_new ~= " @  " and help_new ~= " @ ") -- первую картинку скип
        else
            help_new = help_new..k.." "
        end
    end
    return help_new
end 

function DiscriptionHelpProcessText(image,help_new,icon_count,count,F14,con)
    local icon_txt = ""
    for word in help_new:gmatch("[%z\1-\127\194-\244][\128-\191]*") do
        if word=="@" then
            icon_count = icon_count+1
            if image.help_tips.icons[icon_count] then
                image.help_tips.icons[icon_count].y = image.help_tips[count].discription.y-1
                image.help_tips.icons[icon_count].x = image.help_tips[count].discription.x+dota.GetTextSize(F14,icon_txt).x-4
            end
        end
        icon_txt = icon_txt..word
    end
    return icon_count
end


--//= Option Manager
function DrawOptionManagerImage(fName,category,first,last,pos_y,combo_count,img_size,con,window)

    local start = category:sub(2,6)
    local kef = img_size/(20*con)
    local x = last.x+last.w+5*con*kef
    
    local nextLine = math.ceil(combo_count/9)-1

    if (combo_count - 1) % 9 == 0 then
        x = first.x+first.w+2
    end

    local down_y = window and 5*con or 7*con
    local y__ = (img_size + math.min(down_y,down_y*kef))*nextLine

    local img

    if start == "item_" then
        img = DrawRect(x,pos_y-2+y__,img_size+2*con,img_size,Enum.WHITE,GetTextureId2(category:gsub("@","")),category~="@item_recipe")
        img.textureName = fName..category
    elseif start == "npc_d" then
        img = DrawRect(x,pos_y-2+y__,img_size,img_size,Enum.WHITE,GetTextureId2(category:gsub("@","")))
        img.textureName = fName..category
    else
        local plus = 0
        if x ~= first.x+first.w+2 and not string.find(last.textureName, "item_") then
            plus = 2*con
        end
        img = DrawRect(x+plus,pos_y-2+y__,img_size,img_size,Enum.WHITE,GetTextureId2(category:gsub("@","")))
        img.textureName = fName..category
    end

    RoundedImage(img,6*con,Enum.COLOR_ROUNDED_LOW,2)
    return img
end 


--//= Procent or Number Box
function IsProcentOrNumber(arr)
    return arr.procent or arr.only_number or arr.big_number or arr.mid_number
end 

function ProcentText(val,obj)
    if obj.is_on_off then
        return math.fmod(val,2) == 0 and "OFF" or "ON"    
    elseif obj.is_only_2 then
        return math.fmod(val,2) == 0 and "1" or "2"
    elseif obj.is_procent then 
        return (tonumber(val)*10).."%"
    elseif obj.is_mid_number then 
        return  (tonumber(val*10)).."↕"
    elseif obj.is_big_number then 
        return  tonumber(val*100)    
    else 
        return  tonumber(val).."↕"
    end
   -- return is_procent and (tonumber(val)*10).."%" or tonumber(val).."↕"
end

function ProcentGenerate(val,change,cycle)
    if tonumber(val) then 
        local new_val = tonumber(val) + change        
        if cycle and new_val > 9 then new_val = 0 end
        return string.byte( math.min( math.max(new_val,0), 9) )
    end
    return val
end

function ValidIsNumberBox(arr,bind,def)
    if IsProcentOrNumber(arr) and not tonumber(bind) then 
        if def and tonumber(def) then 
            return def or "0" 
        else 
            return "0"
        end
    else 
        return bind 
    end
end


--// Engine 
function FunctionPreCatch()
	local particle_list = {}
	local hero = dota.GetLocalHero()
	particle_list[#particle_list+1] = dota.CreateParticle("materials/NtUI/particles/illusions.vpcf",0, hero)
	particle_list[#particle_list+1] = dota.CreateParticle("materials/NtUI/particles/radius_main.vpcf",0, hero)
    particle_list[#particle_list+1] = dota.CreateParticle("materials/NtUI/particles/visiblebyenemy_ring_wave.vpcf",0, hero)
    particle_list[#particle_list+1] = dota.CreateParticle("materials/NtUI/particles/vby_onmi.vpcf",0, hero)
    
	particle_list[#particle_list+1] = dota.CreateParticle("materials/NtUI/particles/visible_enemy.vpcf",0, hero)
	particle_list[#particle_list+1] = dota.CreateParticle("materials/NtUI/particles/generic_timer.vpcf",0, hero)
	particle_list[#particle_list+1] = dota.CreateParticle("materials/NtUI/particles/new_rect.vpcf",0, hero)
	particle_list[#particle_list+1] = dota.CreateParticle("particles/ui_mouseactions/range_finder_tower_aoe.vpcf",2,hero)
	for i,v in ipairs(particle_list) do
		particle_list[i] = DestroyParticle(particle_list[i])
	end
end

function GameMode()
	return dota.GameRules.GetInstance():GetGameMode()
end


CFG = {}
CFG.path = dota.GetLuaPath().."etc/CFG.json"

function array_to_string(file)
	local text = ""
    for fil in file:lines() do
        text = text..fil
    end
    return text
end

function CFG:Full()
    local file = io.open(CFG.path, "r")	
	if file then
        local result = JSONs:decode( file:read "*a" )
        file:close()
        return result or {}
    end
    return {}
end 

function CFG:Read(script,var,defoult)
    local result = CFG:Full()
    if result[script] and result[script][var] ~=nil then 
        return result[script][var]
    end
    return defoult
end

function CFG:Write(script,var,value)
    local full = CFG:Full()
    if not full[script] then
        full[script] = {}
    end
    full[script][var] = value
    local file = io.open(CFG.path, "w")	
    if file then
        file:write(JSONs:encode(full))
        file:close()
    end
    return value
end



function ManualTranslation()
    return {
		russian = {
		
            ["General"] = "Общее",
            ["improved"] = "Улучшен",
            ["added"] = "Добавлен(ы)",
            ["fixed"] = "Исправлен(ы)",
            ["Update"] = "Обновление",
            ["updated"] = "Обновлен",
            ["reworked"] = "Переделан",
            ["changed"] = "Изменен",
            ["auto"] = "авто",
            ["in"] = "в",
            ["with"] = "с",
            ["and"] = "и",
            ["for"] = "для",
            ["from"] = "от/из",
            ["function"] = "функция",
            ["functions"] = "функции",
            ["now"] = "теперь",
            ["u"] = "ты",
            ["can"] = "можешь",
            ["it"] = "это",
            ["is"] = "",
            ["delay"] = "делей",
            ["some"] = "некоторые(x)",
            ["feedback"] = "обратная связь",
            ["enable"] = "включено",
            ["disable"] = "отключено",
            ["version"] = "версия",
            ["vs"] = "против",
            ["mechanic"] = "механика",
            ["performance"] = "производительность",
            ["spells"] = "скиллы",
            ["items"] = "предметы",
            ["dodge"] = "додж",
            ["more"] = "больше",
            ["crashes"] = "вылеты",
            ["combo"] = "комбо",
            ["range"] = "радиус",
            ["ally"] = "союзники",
            ["enemy"] = "враги",
            ["support"] = "поддерживает",
            ["like"] = "как",
            ["dont"] = "не",
            ["use"] = "использует",
            ["on"] = "на",
            ["better"] = "лучше",
            ["silence"] = "сало",
            ["to"] = "к",
            ["work"] = "работает",
            ["evade"] = "уворот",
            ["stats"] = "статистика",

            ["if"] = "если",
            ["target"] = "цель",
            ["targets"] = "цели",
            ["when"] = "когда",
            ["think"] = "думаю",
            ["change"] = "измениять",
            ["logic"] = "логика",
            ["has"] = "",
            ["died"] = "погиб(ла)",
            ["new"] = "новый(ая)",
            ["cast"] = "каст",
            ["enemies"] = "врагов",
            ["checks"] = "проверяет",
            ["the"] = "",
            ["before"] = "до",
            ["dodging"] = "доджить",
            ["list"] = "список",
            ["removed"] = "убран(о)",
            ["spell"] = "способность",
            ["bug"] = "баг",
            ["bugs"] = "баги",
            ["search"] = "поиск",
            ["lethal"] = "смертельный",

            ["under"] = "под",
            ["cursor"] = "курсор(у)",
            ["move"] = "двигаться",
            ["speed"] = "скорость",
            ["accuracy"] = "точность",
            ["didnt"] = "не",
            ["heroes"] = "героев",
            ["flying"] = "летающих",
            ["manage"] = "управлять",
            ["also"] = "так-же",
            ["problems"] = "проблемы",
            ["was"] = "были",
            ["etc"] = "так далее",
            ["only"] = "только",
            ["script"] = "скрипт",
            ["supports"] = "поддерживает",
            ["will"] = "будет",
            ["check"] = "проверять",
            ["or"] = "или",
            ["prediction"] = "предикт",
            ["option"] = "опция",
            ["BaseCombo"] = "Базовое комбо",
            ["rare"] = "редкий",
            ["won't"] = "не будет",
            ["moved"] = "перемещена",

            ["UI"] = "Визуальные",
            ["Items"] = "Предметы",
            ["Common"] = "Общее",

		},
		schinese = {
            ["@npc_dota_hero_keeper_of_the_light"] = "@npc_dota_hero_keeper_of_the_light",
            ["General"] = "常规",
            ["improved"] = "已提升",
            ["added"] = "已添加",
            ["fixed"] = "已修复",
            ["Update"] = "更新",
            ["updated"] = "已更新",
            ["reworked"] = "已重做",
            ["changed"] = "已改变",
            ["auto"] = "自动",
            ["in"] = "in",
            ["with"] = "with",
            ["and"] = "和",
            ["for"] = "为了",
            ["from"] = "从",
            ["function"] = "功能",
            ["functions"] = "功能",
            ["now"] = "现在",
            ["u"] = "你",
            ["can"] = "可以",
            ["it"] = "它",
            ["delay"] = "延迟",
            ["some"] = "一些",
            ["feedback"] = "反馈",
            ["enable"] = "开启",
            ["disable"] = "关闭",
            ["version"] = "版本",
            ["vs"] = "针对",
            ["mechanic"] = "机械",
            ["performance"] = "性能",
            ["spells"] = "技能",
            ["items"] = "物品",
            ["dodge"] = "躲闪",
            ["more"] = "更多",
            ["crashes"] = "闪退",
            ["combo"] = "连招",
            ["range"] = "范围",
            ["ally"] = "友方",
            ["enemy"] = "敌方",
            ["support"] = "支持",
            ["like"] = "像",
            ["dont"] = "不要",
            ["use"] = "使用",
            ["on"] = "在之上",
            ["better"] = "更好",
            ["silence"] = "沉默",
            ["to"] = "去",
            ["work"] = "工作",
            ["evade"] = "躲避",
            ["stats"] = "状态",

            ["if"] = "如果",
            ["target"] = "目标",
            ["targets"] = "多个目标",
            ["when"] = "什么时候",
            ["think"] = "认为",
            ["change"] = "更改",
            ["logic"] = "逻辑",
            ["has"] = "有",
            ["died"] = "死亡",
            ["new"] = "新",
            ["cast"] = "释放",
            ["enemies"] = "敌人",
            ["checks"] = "检查",
            ["the"] = "the",
            ["before"] = "之前",
            ["dodging"] = "躲避",
            ["list"] = "列表",
            ["removed"] = "移除",
            ["spell"] = "技能",
            ["bug"] = "bug",
            ["bugs"] = "多个bug",
            ["extra"] = "额外",
            ["search"] = "搜索",
            ["prediction"] = "预测",
            ["BaseCombo"] = "基础连招",
            ["rare"] = "罕见",
            ["running"] = "在跑",
            ["won't"] = "不会",
            ["option"] = "选项",
            ["damage"] = "法术伤害",
            ["dmg"] = "法术伤害",
            ["moved"] = "已移动",

            ["UI"] = "用户界面",
            ["Items"] = "物品",
            ["Common"] = "通用",

            }
	}
end 



function stringvalue(set)
	if tostring(set) == "true" then
		return "true"
	else
		return "false"
	end
end

function split(str, pat)
    local t = {}
    local fpat = "(.-)" .. pat
    local last_end = 1
    local s, e, cap = str:find(fpat, 1)
    while s do
       if s ~= 1 or cap ~= "" then
          table.insert(t,cap)
       end
       last_end = e+1
       s, e, cap = str:find(fpat, last_end)
    end
    if last_end <= #str then
       cap = str:sub(last_end)
       table.insert(t, cap)
    end
    return t
 end


 function smoothColorTransition(currentColor, speed)

    local endR, endG, endB, endA = 0x99, 0x99, 0x99, 0xAA  -- темно-серый с полупрозрачностью 0x999999AA

    local function getColorComponents(rgb)
        local r = bit.rshift(rgb, 24) % 0x100
        local g = bit.rshift(rgb, 16) % 0x100
        local b = bit.rshift(rgb, 8) % 0x100
        local a = rgb % 0x100
        return r, g, b, a
    end

    -- Функция для преобразования компонентов обратно в шестнадцатеричное значение
    local function toHexColor(r, g, b, a)
        return bit.lshift(r, 24) + bit.lshift(g, 16) + bit.lshift(b, 8) + a
    end

    -- Извлекаем компоненты текущего цвета
    local currentR, currentG, currentB, currentA = getColorComponents(currentColor)

    if currentR == endR and currentG == endG and currentB == endB and currentA == endA then
        return currentColor
    end

    -- Плавное изменение каждого компонента цвета с учетом скорости
    currentR = currentR + (endR - currentR) * speed
    currentG = currentG + (endG - currentG) * speed
    currentB = currentB + (endB - currentB) * speed
    currentA = currentA + (endA - currentA) * speed

    currentR = math.min(255, math.max(0, currentR))
    currentG = math.min(255, math.max(0, currentG))
    currentB = math.min(255, math.max(0, currentB))
    currentA = math.min(255, math.max(0, currentA))

    return toHexColor(currentR, currentG, currentB, currentA)
end



local ApplyAlpha = function(color, alpha)
    -- Проверяем входные значения
    alpha = math.min(1, math.max(0, alpha)) -- clamp 0..1
    local new_alpha = math.floor(alpha * 50)
    
    return bit.bor(bit.band(color, 0xFFFFFF00), new_alpha)
end

-- Класс для управления падающими элементами (снежинки или лепестки)
SeasonalFall = {
    panel = nil, -- таблица для хранения всех элементов
    elements = {}, -- таблица для хранения всех элементов
    start_x = 0, -- ширина области
    start_y = 0, -- высота области
    end_x = 0,
    end_y = 0,
    con = 0,
    rect = nil,
    elementCount = 50, -- количество элементов
    season = "winter", -- текущий сезон
    init = false,

    -- Новые параметры для летнего солнца
    sun = {
        x = 0, y = 0,
        color = 0xFFFFAA55
    },
    rays = {},
    last_update_time = 0
}

-- Конструктор класса
function SeasonalFall:new(panel, elementCount, con, season)
    local obj = {
        panel = panel,
        elements = {},
        start_x = panel.x,
        start_y = panel.y,
        end_x = panel.x + panel.w - 20 * con,
        end_y = panel.y + panel.h,
        elementCount = elementCount or 50,
        season = season or "winter",
        rect = DrawRound(panel.x, panel.y, panel.w, panel.h, 0xffc0cb50, 0, false, 10 * con),
        con = con,

         -- Инициализация солнца
         sun = {
            x = panel.x + panel.w * 0.5,
            y = panel.y - 0,
            color = 0xFFFFAA55
        },
        rays = {},
        last_update_time = 0
    }
    setmetatable(obj, self)
    self.__index = self
    return obj
end

-- Инициализация
function SeasonalFall:InitElements()
    if self.init then return end

    local color
    local texture

    if self.season == "winter" then
        self.panel.textureId = GetTextureId2("NtUI/vgui/hud/portraitbackground_motion_swoops.png")
        self.rect.textureId = GetTextureId2("panorama/images/front_page/frosted_edges_png.vtex_c")
        self.rect.color = 0xffffff50
        self.rect.visible = true
        texture = GetTextureId2("panorama/images/events/frostivus/2023/snowflake_gold_png.vtex_c")
        color = 0xeeeeff45
    elseif self.season == "spring" then
        self.panel.textureId = GetTextureId2("panorama/images/battlepass/spring2021/weeklyquests/hiddenbg_week01_psd.vtex_c")
        self.panel.color = 0x353535cc
        self.rect.visible = false

        texture = GetTextureId2("panorama/images/compendium/spring2016/tierglow_base_psd.vtex_c")
        color = 0xffaabb99
    else
        self.panel.textureId = GetTextureId2("panorama/images/battlepass/international2022/swag_bag/dota_plus_bg_png.vtex_c")
        self.panel.color = 0xffffffcc
        self.rect.visible = false
        -- Создаем лучи (каждый луч - отдельный объект линии)
        -- Улучшенные параметры лучей
        local ray_count = math.floor(self.elementCount * 1.5)
        for i = 1, ray_count do
            local ray_angle = math.pi * 2 * (i / ray_count)
            local ray_length = 180 * self.con * (0.9 + math.random() * 0.2)  -- +-10% вариация
            
            local ray = {
                base_length = ray_length,
                angle = ray_angle,
                speed = (0.03 + math.random() * 0.04) * (math.random() > 0.5 and 1 or -1),  -- Разные направления
                alpha = 0.15 + math.random() * 0.1,
                width = (0.5 + math.random() * 1.0) * self.con,
                flicker_speed = 0.5 + math.random() * 2.5,
                length_variation = 0.1 + math.random() * 0.1,
                line_obj = nil,
                segments = {}  -- Для сегментированных лучей
            }  
            -- Создаем основной луч (толстый)
            local endX = self.sun.x + math.cos(ray.angle) * ray.base_length
            local endY = self.sun.y + math.sin(ray.angle) * ray.base_length
            ray.line_obj = DrawLine(
                self.sun.x, self.sun.y, endX, endY,
                ApplyAlpha(self.sun.color, ray.alpha),
                ray.width
            )
            
            -- Создаем дополнительные тонкие лучи для эффекта свечения
            for j = 1, 2 do
                local thin_ray = {
                    angle_offset = (math.random() - 0.5) * 0.1,
                    length_factor = 0.8 + math.random() * 0.4,
                    alpha_factor = 0.3 + math.random() * 0.2,
                    width_factor = 0.3 + math.random() * 0.2,
                    obj = nil
                }
                
                local thin_endX = self.sun.x + math.cos(ray.angle + thin_ray.angle_offset) * (ray.base_length * thin_ray.length_factor)
                local thin_endY = self.sun.y + math.sin(ray.angle + thin_ray.angle_offset) * (ray.base_length * thin_ray.length_factor)
                
                thin_ray.obj = DrawLine(
                    self.sun.x, self.sun.y, thin_endX, thin_endY,
                    ApplyAlpha(self.sun.color, ray.alpha * thin_ray.alpha_factor),
                    ray.width * thin_ray.width_factor
                )
                
                table.insert(ray.segments, thin_ray)
            end
            
            table.insert(self.rays, ray)
        end
    end

    for i = 1, self.elementCount do
        local element = {
            x = math.random(self.start_x, self.end_x),
            y = math.random(self.start_y, self.end_y),
            speed = math.random(50, 150) / 100,
            drift = (math.random() * 2 - 1) * 0.1,
            size = {x=math.random(10 * self.con, 20 * self.con), y=math.random(10 * self.con, 20 * self.con)},
            -- rotation = math.random(0, 360),
            swayAmplitude = math.random(5, 15) / 10, -- амплитуда колебаний
            swayFrequency = math.random(1, 5) / 10, -- частота колебаний
            angle = math.random(0, 360),
            img = nil
        }
        if self.season == "summer" then

        end
        element.img = DrawRect(element.x, element.y, element.size.x, element.size.y, color, texture, true)
        table.insert(self.elements, element)
    end
    self.init = true
end

-- Обновление позиций снежинок
function SeasonalFall:UpdateElements()

    if self.season == "summer" then
        local current_time = dota.GetTick()
        local delta_time = (current_time - self.last_update_time) / 1000  -- В секундах
        self.last_update_time = current_time
        -- Обновляем солнце (пульсация)
        
        -- Обновляем лучи
        for i, ray in ipairs(self.rays) do
            -- Плавное изменение угла
            ray.angle = ray.angle + ray.speed * delta_time
            
            -- Динамическая длина с вариациями
            local length_variation = math.sin(current_time * 0.002 * ray.flicker_speed + i) * ray.length_variation
            local current_length = ray.base_length * (1 + length_variation)
            
            -- Мерцание прозрачности
            ray.alpha = 0.15 + 0.1 * math.sin(current_time * 0.001 * ray.flicker_speed + i * 10)
            
            -- Рассчитываем конечную точку с учетом границ
            local endX = self.sun.x + math.cos(ray.angle) * current_length
            local endY = self.sun.y + math.sin(ray.angle) * current_length
            
            -- Обновляем основной луч
            ray.line_obj.x0 = self.sun.x
            ray.line_obj.y0 = self.sun.y
            ray.line_obj.x1 = endX
            ray.line_obj.y1 = endY
            ray.line_obj.color = ApplyAlpha(self.sun.color, ray.alpha)
            ray.line_obj.width = ray.width
            ray.line_obj.visible = endY > self.panel.y
            
            -- Обновляем дополнительные лучи
            for _, segment in ipairs(ray.segments) do
                local seg_endX = self.sun.x + math.cos(ray.angle + segment.angle_offset) * (current_length * segment.length_factor)
                local seg_endY = self.sun.y + math.sin(ray.angle + segment.angle_offset) * (current_length * segment.length_factor)
                
                segment.obj.x0 = self.sun.x
                segment.obj.y0 = self.sun.y
                segment.obj.x1 = seg_endX
                segment.obj.y1 = seg_endY
                segment.obj.color = ApplyAlpha(self.sun.color, ray.alpha * segment.alpha_factor)
                segment.obj.width = ray.width * segment.width_factor
                segment.obj.visible = seg_endY > self.panel.y
            end
        end
        return
    end

    for _, element in ipairs(self.elements) do
        element.y = element.y + element.speed
        element.x = element.x + element.drift

        if self.season == "spring" then
            element.angle = element.angle + element.swayFrequency
            element.x = element.x + math.sin(math.rad(element.angle)) * element.swayAmplitude -- Качание больше вправо
            -- Эффект "зависания"
            if math.random() < 0.01 then -- 1% шанс на зависание
                element.speed = element.speed * 0.5
            elseif math.random() < 0.02 then -- 1% шанс на ускорение
                element.speed = element.speed * 1.5
            end
        end
        
        if element.y > self.end_y - 20 * self.con or element.x < self.start_x - 5*self.con or element.x > self.end_x + 10*self.con then
            element.y = self.start_y
            element.x = math.random(self.start_x, self.end_x)
            if self.season == "spring" then
                element.speed = math.random(50, 150) / 100 -- Новая скорость
                element.drift = (math.random() * 2 - 1) * 0.1 -- Новое смещение
                element.swayAmplitude = math.random(5, 15) / 10 -- Новая амплитуда колебаний
                element.swayFrequency = math.random(1, 5) / 10 -- Новая частота колебаний
            end
        end
        
        element.img.x = element.x
        element.img.y = element.y
        -- element.img.rotation = element.rotation
    end
end

function SeasonalFall:Start()
    self:InitElements() -- Инициализируем снежинки
    self:UpdateElements() -- Обновляем позиции снежинок
end