-- OT-MMO: ventana de crafteo de las estaciones de Refugio. Solo muestra y pide: el servidor -- (server/scripts/crafteo/crafteo.lua) valida, quita materiales y crea el objeto. Opcode extendido 103: -- «R|profesion|nombre|nivel|xp|xpNivel|xpSiguiente|r1~r2~...» receta: id^nombre^nivel^resultado^cantidad^ingredientes^xp^equipo -- El cliente envía «F|receta|veces». local OPCODE = 103 -- Nombres en español de los materiales (los de Tibia vienen en inglés). local NOMBRES = { [5880] = 'Mineral de hierro', [5901] = 'Madera', [3736] = 'Hierba estrella', [3115] = 'Hueso', [3110] = 'Lingote de hierro', [5941] = 'Mango', [5878] = 'Cuero', [3577] = 'Carne' } crafteoController = Controller:new() local ventana = nil local recetas = {} local nivelOficio = 1 local elegida = nil local function nombreDe(id) if NOMBRES[id] then return NOMBRES[id] end local t = g_things.getThingType(id, ThingCategoryItem) return t and t:getName() ~= '' and t:getName() or 'objeto' end local function puede(r) if nivelOficio < r.nivel then return false end for _, i in ipairs(r.ing) do if i.tiene < i.necesita then return false end end return true end local function mostrar(r) if not ventana or not r then return end elegida = r local d = ventana.detalle d.marco.resultado:setItemId(r.resultado) d.marco.resultado:setItemCount(r.cantidad) d.nombre:setText(r.nombre) local bloqueada = nivelOficio < r.nivel d.requisito:setText(string.format('Nivel %d · +%d de experiencia', r.nivel, r.xp)) d.requisito:setColor(bloqueada and OtmmoTheme.color.errorText or OtmmoTheme.color.text2) d.calidad:setText(r.equipo and 'Sale con calidad: común, poco común, rara o épica. Mejora con tu nivel.' or '') d.ingredientes:destroyChildren() for _, i in ipairs(r.ing) do local fila = g_ui.createWidget('FilaIngrediente', d.ingredientes) fila.icono:setItemId(i.id) fila.nombre:setText(nombreDe(i.id)) fila.cuenta:setText(string.format('%d / %d', i.tiene, i.necesita)) fila.cuenta:setColor(i.tiene >= i.necesita and OtmmoTheme.color.ok or OtmmoTheme.color.errorText) end local ok = puede(r) ventana.botones.uno:setEnabled(ok) ventana.botones.cinco:setEnabled(ok) end local function abrir(partes) nivelOficio = tonumber(partes[4]) or 1 local xp, xpNivel, xpSig = tonumber(partes[5]) or 0, tonumber(partes[6]) or 0, tonumber(partes[7]) or 1 recetas = {} for _, fila in ipairs((partes[8] or ''):split('~')) do local f = fila:split('^') if #f >= 8 then local r = { id = tonumber(f[1]), nombre = f[2], nivel = tonumber(f[3]), resultado = tonumber(f[4]), cantidad = tonumber(f[5]), xp = tonumber(f[7]), equipo = f[8] == '1', ing = {} } for _, par in ipairs(f[6]:split(',')) do local id, necesita, tiene = par:match('(%d+):(%d+):(%d+)') if id then r.ing[#r.ing + 1] = { id = tonumber(id), necesita = tonumber(necesita), tiene = tonumber(tiene) } end end recetas[#recetas + 1] = r end end if not ventana then ventana = g_ui.displayUI('crafteo') OtmmoVentanas.recordar(ventana, 'crafteo') -- posición entre sesiones (fase 4) end ventana:setText(partes[3] or 'Crafteo') ventana:show() ventana:raise() ventana:focus() ventana.oficio:setText(string.format('%s · nivel %d', partes[3] or '', nivelOficio)) local frac = xpSig > xpNivel and math.max(0, math.min(1, (xp - xpNivel) / (xpSig - xpNivel))) or 1 ventana.barra.fill:setWidth(math.max(1, math.floor((ventana.barra:getWidth() - 2) * frac))) ventana.xpTexto:setText(string.format('%d / %d', xp, xpSig)) local lista = ventana.lista lista:destroyChildren() local foco = nil for _, r in ipairs(recetas) do local fila = g_ui.createWidget('FilaReceta', lista) fila.icono:setItemId(r.resultado) fila.nombre:setText(r.nombre) fila.nivel:setText(nivelOficio >= r.nivel and ('Nivel ' .. r.nivel) or ('Requiere nivel ' .. r.nivel)) if nivelOficio < r.nivel then fila.nombre:setColor(OtmmoTheme.color.textDisabled) fila.icono:setOpacity(0.4) elseif not puede(r) then fila.nivel:setText('Nivel ' .. r.nivel .. ' · faltan materiales') end fila.onFocusChange = function(w, focused) if focused then mostrar(r) end end if elegida and elegida.id == r.id then foco = fila end end local primero = foco or lista:getFirstChild() if primero then lista:focusChild(primero, KeyboardFocusReason) end end local function onOpcode(protocol, opcode, buffer) local partes = buffer:split('|') if partes[1] == 'R' then abrir(partes) end end function fabricar(veces) local protocol = g_game.getProtocolGame() if protocol and elegida then protocol:sendExtendedOpcode(OPCODE, string.format('F|%d|%d', elegida.id, veces)) end end function cerrar() if ventana then ventana:hide() end end function crafteoController:onInit() ProtocolGame.registerExtendedOpcode(OPCODE, onOpcode) end function crafteoController:onTerminate() ProtocolGame.unregisterExtendedOpcode(OPCODE) if ventana then ventana:destroy() ventana = nil end end function crafteoController:onGameEnd() cerrar() end