script_name("ObjEditor")
script_author("Milei")

local imgui  = require 'mimgui'
local ffi    = require 'ffi'
local bit    = require 'bit'
local inicfg = require 'inicfg'
local new    = imgui.new
local sampev = require 'samp.events'

-- ===== Configuración =====
local SLOT_PREVIEW = 9          -- slot de la vista previa del editor
local MAX_SLOTS    = 9          -- proyectos activos usan slots 0..8
local ARCHIVO_INI  = "obj_proyectos.ini"

local ALPHA_MIN = 0.55

-- ===== Variables del editor =====
local ventana   = new.bool(false)
local panelProy = new.bool(false)
local nombre    = new.char[64]("")
local modelo    = new.int(19078)
local hueso     = new.int(0)
local pos       = new.float[3](0.0, 0.0, 0.0)
local rot       = new.float[3](0.0, 0.0, 0.0)
local escala    = new.float[3](1.0, 1.0, 1.0)
local paso      = new.float(0.01)
local uniforme  = new.bool(true)

-- Colores de material
local usarCol1  = new.bool(false)
local usarCol2  = new.bool(false)
local color1    = new.float[4](1.0, 1.0, 1.0, 1.0)
local color2    = new.float[4](1.0, 1.0, 1.0, 1.0)

-- Opacidad / visibilidad
local opacidad  = new.float(100.0)   -- 0..100
local visible   = new.bool(true)

-- Fake skin
local fakeSkinId  = new.int(0)
local fakeSkinOn  = false
local skinReal    = nil
local RPC_SETSKIN = 153

local previewOn = false
local editando  = 0

local ultimoEnvio = {}
local data = { proyectos = {} }

local huesos = {
    "Columna", "Cabeza", "Brazo izq.", "Brazo der.", "Mano izq.", "Mano der.",
    "Muslo izq.", "Muslo der.", "Pie izq.", "Pie der.", "Pantorrilla der.",
    "Pantorrilla izq.", "Antebrazo izq.", "Antebrazo der.", "Clavícula izq.",
    "Clavícula der.", "Cuello", "Mandíbula"
}
local huesosC = new['const char*'][#huesos](huesos)

local function msg(t) sampAddChatMessage("{00FF00}[Obj]{FFFFFF} " .. t, -1) end

-- ===== Helpers para conversion INI =====
local function parseFloats(str)
    if not str or str == "" then return nil end
    local t = {}
    for num in string.gmatch(str, "[^,]+") do
        table.insert(t, tonumber(num) or 0.0)
    end
    return #t > 0 and t or nil
end

-- ===== Archivo INI =====
local function guardarArchivo()
    local cfg = {
        General = {
            fakeSkin_id = fakeSkinId[0],
            fakeSkin_activo = fakeSkinOn,
            total_proyectos = #data.proyectos
        }
    }
    for i, p in ipairs(data.proyectos) do
        local sec = "Proyecto_" .. i
        cfg[sec] = {
            nombre   = p.nombre or "",
            modelo   = p.modelo or 19078,
            hueso    = p.hueso or 0,
            pos      = string.format("%.3f,%.3f,%.3f", p.pos[1] or 0, p.pos[2] or 0, p.pos[3] or 0),
            rot      = string.format("%.1f,%.1f,%.1f", p.rot[1] or 0, p.rot[2] or 0, p.rot[3] or 0),
            escala   = string.format("%.3f,%.3f,%.3f", p.escala[1] or 1, p.escala[2] or 1, p.escala[3] or 1),
            uniforme = p.uniforme and true or false,
            col1     = p.col1 and string.format("%.2f,%.2f,%.2f,%.2f", p.col1[1], p.col1[2], p.col1[3], p.col1[4]) or "",
            col2     = p.col2 and string.format("%.2f,%.2f,%.2f,%.2f", p.col2[1], p.col2[2], p.col2[3], p.col2[4]) or "",
            opacidad = p.opacidad or 100.0,
            visible  = p.visible ~= false,
            activo   = p.activo == true
        }
    end
    inicfg.save(cfg, ARCHIVO_INI)
end

local function cargarArchivo()
    local cfg = inicfg.load(nil, ARCHIVO_INI)
    if not cfg then return end

    if cfg.General then
        fakeSkinId[0] = tonumber(cfg.General.fakeSkin_id) or 0
        fakeSkinOn = cfg.General.fakeSkin_activo == true or cfg.General.fakeSkin_activo == "true"
    end

    data.proyectos = {}
    local total = tonumber(cfg.General and cfg.General.total_proyectos) or 0

    for i = 1, math.max(total, 100) do
        local sec = cfg["Proyecto_" .. i]
        if sec and sec.nombre then
            local p = {
                nombre   = sec.nombre,
                modelo   = tonumber(sec.modelo) or 19078,
                hueso    = tonumber(sec.hueso) or 0,
                pos      = parseFloats(sec.pos) or {0.0, 0.0, 0.0},
                rot      = parseFloats(sec.rot) or {0.0, 0.0, 0.0},
                escala   = parseFloats(sec.escala) or {1.0, 1.0, 1.0},
                uniforme = sec.uniforme == true or sec.uniforme == "true",
                col1     = parseFloats(sec.col1),
                col2     = parseFloats(sec.col2),
                opacidad = tonumber(sec.opacidad) or 100.0,
                visible  = sec.visible == true or sec.visible == "true" or sec.visible == nil,
                activo   = sec.activo == true or sec.activo == "true"
            }
            table.insert(data.proyectos, p)
        end
    end
end

-- ===== Attach local =====
local RPC_ATTACH = 113

local function miId()
    local _, id = sampGetPlayerIdByCharHandle(PLAYER_PED)
    return id
end

local function curvaAlpha(op)
    if op <= 0.005 then return 0 end
    return ALPHA_MIN + (1 - ALPHA_MIN) * math.min(1, op)
end

local function colorFinal(c, op)
    op = op or 1.0
    if type(c) ~= "table" then
        if op >= 0.999 then return 0 end
        c = { 1.0, 1.0, 1.0, 1.0 }
    end
    local function b(v) return math.floor(math.max(0, math.min(1, v or 1)) * 255 + 0.5) end
    local a = curvaAlpha((c[4] or 1.0) * op)
    return bit.bor(bit.lshift(b(a), 24), bit.lshift(b(c[3]), 16), bit.lshift(b(c[2]), 8), b(c[1]))
end

local function enviarAttach(slot, d, forzar)
    if d and d.visible == false then d = nil end

    local firma = "nil"
    local c1, c2 = 0, 0
    if d then
        local op = (tonumber(d.opacidad) or 100) / 100
        c1, c2 = colorFinal(d.col1, op), colorFinal(d.col2, op)
        firma = string.format("%d|%d|%.3f|%.3f|%.3f|%.1f|%.1f|%.1f|%.3f|%.3f|%.3f|%d|%d",
            d.modelo, d.hueso, d.pos[1], d.pos[2], d.pos[3], d.rot[1], d.rot[2], d.rot[3],
            d.escala[1], d.escala[2], d.escala[3], c1, c2)
    end

    if not forzar and ultimoEnvio[slot] == firma then return end
    ultimoEnvio[slot] = firma

    local bs = raknetNewBitStream()
    raknetBitStreamWriteInt16(bs, miId())
    raknetBitStreamWriteInt32(bs, slot)
    raknetBitStreamWriteBool(bs, d ~= nil)
    if d then
        raknetBitStreamWriteInt32(bs, d.modelo)
        raknetBitStreamWriteInt32(bs, d.hueso + 1)
        for i = 1, 3 do raknetBitStreamWriteFloat(bs, d.pos[i]) end
        for i = 1, 3 do raknetBitStreamWriteFloat(bs, d.rot[i]) end
        for i = 1, 3 do raknetBitStreamWriteFloat(bs, d.escala[i]) end
        raknetBitStreamWriteInt32(bs, c1)
        raknetBitStreamWriteInt32(bs, c2)
    end
    raknetEmulRpcReceiveBitStream(RPC_ATTACH, bs)
    raknetDeleteBitStream(bs)
end

-- ===== Fake skin =====
local ponerTodosRef
local aplicandoSkin = false

local function emularSkin(id)
    local bs = raknetNewBitStream()
    raknetBitStreamWriteInt32(bs, miId())
    raknetBitStreamWriteInt32(bs, id)
    aplicandoSkin = true
    raknetEmulRpcReceiveBitStream(RPC_SETSKIN, bs)
    aplicandoSkin = false
    raknetDeleteBitStream(bs)
    lua_thread.create(function()
        wait(300)
        if ponerTodosRef then ponerTodosRef() end
    end)
end

local function activarFakeSkin()
    local id = fakeSkinId[0]
    if id < 0 or id > 311 or id == 74 then msg("{FF5555}ID de skin invalido.") return end
    if not skinReal then skinReal = getCharModel(PLAYER_PED) end
    fakeSkinOn = true
    emularSkin(id)
    guardarArchivo()
    msg("Fake skin " .. id .. " activada (solo vos la ves).")
end

local function quitarFakeSkin()
    fakeSkinOn = false
    if skinReal then emularSkin(skinReal) end
    guardarArchivo()
    msg("Fake skin desactivada.")
end

-- ===== Datos del editor =====
local function capturar(n)
    return {
        nombre = n, modelo = modelo[0], hueso = hueso[0],
        pos = { pos[0], pos[1], pos[2] },
        rot = { rot[0], rot[1], rot[2] },
        escala = { escala[0], escala[1], escala[2] },
        uniforme = uniforme[0],
        col1 = usarCol1[0] and { color1[0], color1[1], color1[2], color1[3] } or nil,
        col2 = usarCol2[0] and { color2[0], color2[1], color2[2], color2[3] } or nil,
        opacidad = opacidad[0],
        visible = visible[0]
    }
end

local function aplicar(p)
    imgui.StrCopy(nombre, p.nombre or "")
    modelo[0] = p.modelo; hueso[0] = p.hueso
    for i = 0, 2 do
        pos[i] = p.pos[i + 1]; rot[i] = p.rot[i + 1]; escala[i] = p.escala[i + 1]
    end
    uniforme[0] = p.uniforme and true or false
    usarCol1[0] = type(p.col1) == "table"
    usarCol2[0] = type(p.col2) == "table"
    for i = 0, 3 do
        color1[i] = usarCol1[0] and (p.col1[i + 1] or 1.0) or 1.0
        color2[i] = usarCol2[0] and (p.col2[i + 1] or 1.0) or 1.0
    end
    opacidad[0] = tonumber(p.opacidad) or 100.0
    visible[0] = p.visible ~= false
end

local function resetColores()
    usarCol1[0], usarCol2[0] = false, false
    for i = 0, 3 do color1[i] = 1.0; color2[i] = 1.0 end
    opacidad[0] = 100.0
    visible[0] = true
end

local function editSlot()
    local p = data.proyectos[editando]
    if p and p.activo and p.slot then return p.slot end
    return SLOT_PREVIEW
end

local function actualizar(forzar)
    if previewOn then enviarAttach(editSlot(), capturar(""), forzar) end
end

local function slotLibre()
    local usados = {}
    for _, p in ipairs(data.proyectos) do
        if p.activo and p.slot then usados[p.slot] = true end
    end
    for s = 0, MAX_SLOTS - 1 do
        if not usados[s] then return s end
    end
end

local function soltarEdicion()
    local p = data.proyectos[editando]
    if p and p.activo and p.slot then
        enviarAttach(p.slot, p, true)
    elseif previewOn then
        enviarAttach(SLOT_PREVIEW, nil, true)
    end
    previewOn = false
end

-- ===== Proyectos =====
local function activarProyecto(i)
    local p = data.proyectos[i]
    local s = slotLibre()
    if not s then
        msg("{FF5555}Llegaste al maximo de " .. MAX_SLOTS .. " proyectos activos. Desactiva uno.")
        return
    end
    p.activo, p.slot = true, s
    if editando == i and previewOn then
        enviarAttach(SLOT_PREVIEW, nil, true)
        enviarAttach(s, capturar(""), true)
    else
        enviarAttach(s, p, true)
    end
    guardarArchivo()
    msg("Proyecto '" .. p.nombre .. "' activado.")
end

local function desactivarProyecto(i)
    local p = data.proyectos[i]
    if p.slot then enviarAttach(p.slot, nil, true) end
    p.activo, p.slot = false, nil
    if editando == i then previewOn = false end
    guardarArchivo()
    msg("Proyecto '" .. p.nombre .. "' desactivado.")
end

local function editarProyecto(i)
    if editando ~= i then soltarEdicion() end
    editando = i
    local p = data.proyectos[i]
    aplicar(p)
    previewOn = true
    actualizar(true)
    msg("Editando '" .. p.nombre .. "'. Toca Guardar proyecto para aplicar cambios.")
end

local function borrarProyecto(i)
    local p = data.proyectos[i]
    if p.activo and p.slot then enviarAttach(p.slot, nil, true) end
    if editando == i then
        if not p.activo and previewOn then enviarAttach(SLOT_PREVIEW, nil, true) end
        previewOn = false; editando = 0
    elseif editando > i then
        editando = editando - 1
    end
    table.remove(data.proyectos, i)
    guardarArchivo()
    msg("Proyecto '" .. p.nombre .. "' borrado.")
end

local function alternarVisible(i)
    local p = data.proyectos[i]
    p.visible = (p.visible == false)
    if editando == i then visible[0] = p.visible end
    if p.activo and p.slot then
        if editando == i and previewOn then enviarAttach(p.slot, capturar(""), true)
        else enviarAttach(p.slot, p, true) end
    end
    guardarArchivo()
    msg("Proyecto '" .. p.nombre .. "' " .. (p.visible and "visible." or "oculto."))
end

local function guardarProyecto()
    local n = ffi.string(nombre):gsub("^%s+", ""):gsub("%s+$", "")
    if n == "" then msg("{FF5555}Pone un nombre antes de guardar.") return end

    local idx
    for i, p in ipairs(data.proyectos) do
        if p.nombre == n then idx = i break end
    end

    if (idx and idx ~= editando) or (not idx and editando > 0) then
        local wasPreview = previewOn
        soltarEdicion()
        previewOn = wasPreview
    end

    local nuevo = capturar(n)
    if idx then
        local viejo = data.proyectos[idx]
        nuevo.activo, nuevo.slot = viejo.activo, viejo.slot
        data.proyectos[idx] = nuevo
        msg("Proyecto '" .. n .. "' actualizado.")
    else
        nuevo.activo = false
        table.insert(data.proyectos, nuevo)
        idx = #data.proyectos
        msg("Proyecto '" .. n .. "' guardado.")
    end
    editando = idx

    if nuevo.activo and nuevo.slot then
        if previewOn then enviarAttach(SLOT_PREVIEW, nil, true) end
        enviarAttach(nuevo.slot, nuevo, true)
        previewOn = true
    elseif previewOn then
        enviarAttach(SLOT_PREVIEW, capturar(""), true)
    end
    guardarArchivo()
end

-- ===== Interfaz =====
imgui.OnInitialize(function()
    imgui.GetIO().IniFilename = nil
end)

local ejes = { "X", "Y", "Z" }
local mainPos, mainSize = imgui.ImVec2(0, 0), imgui.ImVec2(420, 760)

imgui.OnFrame(function() return ventana[0] end, function()
    local sw, sh = getScreenResolution()
    imgui.SetNextWindowPos(imgui.ImVec2(sw / 2 - 150, sh / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
    imgui.SetNextWindowSize(imgui.ImVec2(420, 760), imgui.Cond.FirstUseEver)
    imgui.Begin("Editor de Objetos By Milei", ventana)
    mainPos, mainSize = imgui.GetWindowPos(), imgui.GetWindowSize()

    local ed = data.proyectos[editando]
    if ed then
        imgui.TextColored(imgui.ImVec4(1.0, 0.85, 0.3, 1.0), "Editando: " .. ed.nombre)
    else
        imgui.TextDisabled("Proyecto nuevo (sin guardar)")
    end

    -- Generar
    imgui.Text("Generar objeto")
    imgui.Separator()
    if imgui.InputInt("ID Objeto", modelo) then actualizar() end
    if imgui.Combo("Hueso", hueso, huesosC, #huesos) then actualizar(true) end

    if imgui.Button("Generar", imgui.ImVec2(120, 25)) then previewOn = true; actualizar(true) end
    imgui.SameLine()
    if imgui.Button("Eliminar", imgui.ImVec2(120, 25)) then
        if ed and ed.activo then desactivarProyecto(editando)
        else enviarAttach(SLOT_PREVIEW, nil, true); previewOn = false end
    end
    imgui.SameLine()
    if imgui.Button("Nuevo", imgui.ImVec2(120, 25)) then
        soltarEdicion()
        editando = 0
        imgui.StrCopy(nombre, "")
        for i = 0, 2 do pos[i] = 0; rot[i] = 0; escala[i] = 1 end
        resetColores()
    end

    -- Editar
    imgui.Spacing()
    imgui.Text("Editar objeto")
    imgui.Separator()
    imgui.SliderFloat("Sensibilidad", paso, 0.001, 0.1, "%.3f")

    if imgui.DragFloat3("Posición (X Y Z)", pos, paso[0], -5.0, 5.0, "%.3f") then
        actualizar()
    end

    if imgui.Button("Resetear valores", imgui.ImVec2(-1, 22)) then
        for i = 0, 2 do pos[i] = 0; rot[i] = 0; escala[i] = 1 end
        resetColores()
        actualizar(true)
    end

    imgui.Spacing()
    imgui.Text("Rotación")
    for i = 0, 2 do
        imgui.PushIDInt(i)
        imgui.PushItemWidth(170)
        local tmp = new.float(rot[i])
        if imgui.DragFloat("Rot " .. ejes[i + 1], tmp, paso[0] * 100, -360.0, 360.0, "%.1f") then
            rot[i] = tmp[0]
            actualizar()
        end
        imgui.PopItemWidth()

        imgui.SameLine()
        if imgui.Button("-90") then rot[i] = rot[i] - 90; actualizar(true) end
        imgui.SameLine()
        if imgui.Button("+90") then rot[i] = rot[i] + 90; actualizar(true) end
        imgui.SameLine()
        if imgui.Button("0") then rot[i] = 0; actualizar(true) end
        imgui.PopID()
    end

    imgui.Spacing()
    imgui.Text("Tamaño")
    if imgui.Checkbox("Tamaño uniforme (mismo en X, Y y Z)", uniforme) then
        if uniforme[0] then escala[1] = escala[0]; escala[2] = escala[0]; actualizar(true) end
    end
    if uniforme[0] then
        local tmp = new.float(escala[0])
        if imgui.DragFloat("Tamaño", tmp, paso[0], 0.01, 10.0, "%.3f") then
            for i = 0, 2 do escala[i] = tmp[0] end
            actualizar()
        end
    else
        if imgui.DragFloat3("Tamaño (X Y Z)", escala, paso[0], 0.01, 10.0, "%.3f") then
            actualizar()
        end
    end

    -- Color
    imgui.Spacing()
    imgui.Text("Color de texturas")
    imgui.Separator()
    local colFlags = imgui.ColorEditFlags.AlphaBar
    local mats = { { usarCol1, color1 }, { usarCol2, color2 } }
    for idx, m in ipairs(mats) do
        imgui.PushIDInt(100 + idx)
        if imgui.Checkbox("Material " .. idx, m[1]) then actualizar(true) end
        if m[1][0] then
            imgui.SameLine()
            imgui.PushItemWidth(-1)
            if imgui.ColorEdit4("##col", m[2], colFlags) then
                actualizar()
            end
            imgui.PopItemWidth()
        end
        imgui.PopID()
    end

    -- Opacidad
    imgui.Spacing()
    imgui.Text("Opacidad")
    imgui.Separator()
    if imgui.SliderFloat("Opacidad", opacidad, 0.0, 100.0, "%.0f%%") then
        actualizar()
    end

    if imgui.Button("0%", imgui.ImVec2(60, 22)) then opacidad[0] = 0; actualizar(true) end
    imgui.SameLine()
    if imgui.Button("50%", imgui.ImVec2(60, 22)) then opacidad[0] = 50; actualizar(true) end
    imgui.SameLine()
    if imgui.Button("100%", imgui.ImVec2(60, 22)) then opacidad[0] = 100; actualizar(true) end

    if imgui.Button(visible[0] and "Ocultar objeto" or "Mostrar objeto", imgui.ImVec2(-1, 22)) then
        visible[0] = not visible[0]
        actualizar(true)
    end
    if not visible[0] then
        imgui.TextColored(imgui.ImVec4(1.0, 0.5, 0.3, 1.0), "Objeto oculto (guardá para que quede así)")
    end

    -- Fake skin
    imgui.Spacing()
    imgui.Text("Fake Skin (solo visible para vos)")
    imgui.Separator()
    imgui.PushItemWidth(150)
    imgui.InputInt("ID Skin", fakeSkinId)
    imgui.PopItemWidth()
    imgui.SameLine()
    if imgui.Button("Aplicar skin", imgui.ImVec2(100, 22)) then activarFakeSkin() end
    imgui.SameLine()
    if imgui.Button("Quitar", imgui.ImVec2(-1, 22)) then quitarFakeSkin() end
    if fakeSkinOn then
        imgui.TextColored(imgui.ImVec4(0.3, 1.0, 0.3, 1.0),
            "Activa: " .. fakeSkinId[0] .. "  (real: " .. tostring(skinReal or "?") .. ")")
    end

    -- Guardado
    imgui.Spacing()
    imgui.Text("Guardado")
    imgui.Separator()
    imgui.InputText("Nombre", nombre, ffi.sizeof(nombre))
    if imgui.Button("Guardar proyecto", imgui.ImVec2(-1, 25)) then guardarProyecto() end
    imgui.Spacing()
    if imgui.Button(panelProy[0] and "Ocultar proyectos" or "Proyectos guardados", imgui.ImVec2(-1, 25)) then
        panelProy[0] = not panelProy[0]
    end

    imgui.End()

    -- ===== Panel derecho: proyectos =====
    if panelProy[0] then
        imgui.SetNextWindowPos(imgui.ImVec2(mainPos.x + mainSize.x + 5, mainPos.y), imgui.Cond.Always)
        imgui.SetNextWindowSize(imgui.ImVec2(320, mainSize.y), imgui.Cond.Always)
        imgui.Begin("Proyectos guardados", panelProy,
            imgui.WindowFlags.NoMove + imgui.WindowFlags.NoResize + imgui.WindowFlags.NoCollapse)

        local activos = 0
        for _, p in ipairs(data.proyectos) do if p.activo then activos = activos + 1 end end
        imgui.Text(string.format("Activos: %d / %d", activos, MAX_SLOTS))
        imgui.SameLine()
        if imgui.SmallButton("Activar todos") then
            for i, p in ipairs(data.proyectos) do
                if not p.activo then
                    if not slotLibre() then
                        msg("{FF5555}Se llego al maximo de " .. MAX_SLOTS .. " proyectos activos.")
                        break
                    end
                    activarProyecto(i)
                end
            end
        end
        imgui.SameLine()
        if imgui.SmallButton("Desactivar todos") then
            for i, p in ipairs(data.proyectos) do if p.activo then desactivarProyecto(i) end end
        end

        imgui.Separator()

        if #data.proyectos == 0 then
            imgui.TextDisabled("Todavía no guardaste ningún proyecto.")
        end

        local borrar
        for i, p in ipairs(data.proyectos) do
            imgui.PushIDInt(i)
            if p.activo then
                imgui.TextColored(imgui.ImVec4(0.3, 1.0, 0.3, 1.0), "[ON] " .. p.nombre)
            else
                imgui.Text(p.nombre)
            end
            if p.visible == false then
                imgui.SameLine()
                imgui.TextColored(imgui.ImVec4(1.0, 0.5, 0.3, 1.0), "(oculto)")
            end
            imgui.TextDisabled(string.format("ID %d - %s - %d%%", p.modelo, huesos[p.hueso + 1] or "?",
                math.floor((tonumber(p.opacidad) or 100) + 0.5)))
            if type(p.col1) == "table" then
                imgui.SameLine()
                imgui.ColorButton("##c1", imgui.ImVec4(p.col1[1], p.col1[2], p.col1[3], p.col1[4]), 0, imgui.ImVec2(14, 14))
            end
            if type(p.col2) == "table" then
                imgui.SameLine()
                imgui.ColorButton("##c2", imgui.ImVec4(p.col2[1], p.col2[2], p.col2[3], p.col2[4]), 0, imgui.ImVec2(14, 14))
            end

            if p.activo then
                if imgui.Button("Desactivar", imgui.ImVec2(70, 22)) then desactivarProyecto(i) end
            else
                if imgui.Button("Activar", imgui.ImVec2(70, 22)) then activarProyecto(i) end
            end
            imgui.SameLine()
            if imgui.Button(p.visible == false and "Mostrar" or "Ocultar", imgui.ImVec2(70, 22)) then alternarVisible(i) end
            imgui.SameLine()
            if imgui.Button("Editar", imgui.ImVec2(70, 22)) then editarProyecto(i) end
            imgui.SameLine()
            if imgui.Button("Borrar", imgui.ImVec2(70, 22)) then borrar = i end
            imgui.Separator()
            imgui.PopID()
        end
        if borrar then borrarProyecto(borrar) end

        imgui.End()
    end
end)

-- ===== Poner todos los activos =====
local function ponerTodos()
    for _, p in ipairs(data.proyectos) do
        if p.activo and p.slot then enviarAttach(p.slot, p, false) end
    end
    if previewOn then enviarAttach(editSlot(), capturar(""), false) end
end

ponerTodosRef = ponerTodos

-- ===== Main =====
function main()
    while not isSampAvailable() do wait(100) end
    cargarArchivo()
    sampRegisterChatCommand("obj", function() ventana[0] = not ventana[0] end)
    sampRegisterChatCommand("fskin", function(arg)
        local id = tonumber(arg)
        if id then fakeSkinId[0] = id; activarFakeSkin() else quitarFakeSkin() end
    end)
    msg("Cargado. Usa /obj para abrir el panel.")

    while not sampIsLocalPlayerSpawned() do wait(500) end
    wait(1000)

    local n = 0
    for _, p in ipairs(data.proyectos) do
        if p.activo then
            local s = slotLibre()
            if s then p.slot = s; n = n + 1 else p.activo = false end
        end
    end
    ponerTodos()
    if n > 0 then msg(n .. " proyecto(s) restaurado(s).") end

    skinReal = getCharModel(PLAYER_PED)
    if fakeSkinOn then emularSkin(fakeSkinId[0]) end

    local estabaMuerto = false

    function sampev.onSetPlayerSkin(playerid, skinId)
        if aplicandoSkin then return end
        if playerid == miId() then
            skinReal = skinId
            if fakeSkinOn then
                lua_thread.create(function() wait(200); emularSkin(fakeSkinId[0]) end)
                return false
            end
        end
    end

    function sampev.onSetPlayerAttachedObject(playerid, index, create, model, bone, offset, rotation, scale, color1, color2)
        local myId = miId()
        if playerid == myId and index >= 0 and index < MAX_SLOTS then
            local ocupado = false
            for _, p in ipairs(data.proyectos) do
                if p.activo and p.slot == index then
                    ocupado = true
                    break
                end
            end
            if ocupado then return false end
        end
    end

    sampRegisterChatCommand("objrefresh", function()
        ponerTodos()
        msg("Objetos restaurados.")
    end)

    while true do
        wait(100)

        if isCharDead(PLAYER_PED) or not sampIsLocalPlayerSpawned() then
            estabaMuerto = true
        elseif estabaMuerto then
            estabaMuerto = false
            wait(1500)
            ponerTodos()
            if fakeSkinOn then emularSkin(fakeSkinId[0]) end
        end
    end
end

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: