-- OT-MMO: ventana de raid (vault OT-MMO/raids/plan-raids.md; la primera raid, R1 El Primer Farero, en -- OT-MMO/raids/r1-primer-farero.md). Estilo VALDREN (game_viaje/valdren.otui). El servidor manda (server/scripts/raid/raid.lua): -- opcode 127 -- servidor -> cliente «I|clave|nombre|meta|jefe^muerto^mecanica;mecanica~...|restanteS|emblemas|estado|texto» abre -- «U|...» igual, solo si la ventana ya está abierta (tras cada jefe) · «C» la cierra -- estado: L libre · A atado a este progreso · X el grupo no puede entrar (texto = por qué) -- cliente -> servidor «E|clave» entrar (abre la sala de entrada, opcode 108) · «P|clave» pedir la ventana -- La plantilla de la raid larga (Ciudadela del Faro Muerto, 4 alas) sigue en probar() sin servidor. local ORO, CLARO, TEXTO, TEXTO2, BAJA, ROJO = '#C7A86B', '#E8D3A2', '#E2E5E6', '#9AA7AE', '#39444C', '#D9776A' local OPCODE = 127 raidController = Controller:new() local ventana = nil local clave = nil -- Datos de ejemplo de la plantilla: 4 alas de 3 jefes; los nombres de las alas son una propuesta de diseño. local EJEMPLO = { nombre = 'La Ciudadela del Faro Muerto', meta = 'Raid · 10 o 20 aventureros · nivel 100 · equipo de índice 130', alas = { { 'La Escollera', { { 'Primer jefe', true }, { 'Segundo jefe', true }, { 'Tercer jefe', false } } }, { 'El Claustro de Ceniza', { { 'Primer jefe', false }, { 'Segundo jefe', false }, { 'Tercer jefe', false } } }, { 'La Torre de las Nueve Voces', { { 'Primer jefe', false }, { 'Segundo jefe', false }, { 'Tercer jefe', false } } }, { 'La Linterna Apagada', { { 'Primer jefe', false }, { 'Segundo jefe', false }, { 'El Faro Muerto', false } } }, }, bloqueo = '2 / 12', renueva = 'Se renueva el martes a las 06:00. Los jefes muertos siguen muertos si sales y vuelves.', reglas = 'Las alas se abren en orden: hay un portal entre una y la siguiente.\nSin límite de intentos durante la semana.\n' .. '3 resurrecciones en combate por jefe.\nCuras de área al subgrupo de 5.', grupo = 'Grupo de raid · 17 / 20 · dos protectores, cinco sanadores', arte = 'ciudadela', plantilla = true, } local REGLAS = 'Sin límite de intentos durante la semana.\n3 resurrecciones en combate por jefe; si caen todos, se reinicia.\n' .. 'Dos subgrupos de 5: las torres y algunas zonas son de tu subgrupo.\nEl progreso es del grupo: entra con quien comparta el tuyo.' local function tiempo(s) s = math.max(0, math.floor(tonumber(s) or 0)) local d, h, m = math.floor(s / 86400), math.floor(s % 86400 / 3600), math.floor(s % 3600 / 60) if d > 0 then return string.format('%d d %d h', d, h) end return string.format('%d h %d min', h, m) end local function enviar(texto) local protocol = g_game.getProtocolGame() if protocol then protocol:sendExtendedOpcode(OPCODE, texto) end end -- Cada ala es una tarjeta: título, estado a la derecha y hasta tres líneas. En la plantilla las líneas son jefes con -- su marca (oro = muerto); en una raid de un ala, cada tarjeta es un jefe y las líneas, lo que hay que saber de él. local function pintar(d) ventana.nombre:setText(d.nombre) ventana:setText('Raid · ' .. d.nombre) ventana.meta:setText(d.meta) if modules.game_viaje and modules.game_viaje.rutaArte then ventana.arte:setImageSource(modules.game_viaje.rutaArte(d.arte or 'ciudadela')) end ventana.alas:destroyChildren() for _, a in ipairs(d.alas) do local w = g_ui.createWidget('RaidAla', ventana.alas) w.titulo:setText(a[1]) local muertos = 0 for _, j in ipairs(a[2]) do local f = g_ui.createWidget('RaidJefe', w.jefes) f.nombre:setText(j[1]) if a.jefe then f.estado:setBackgroundColor(a.muerto and ORO or BAJA) f.nombre:setColor(a.muerto and TEXTO2 or TEXTO) elseif j[2] then muertos = muertos + 1 f.estado:setBackgroundColor(ORO) f.nombre:setColor(TEXTO2) end end if a.jefe then w.meta:setText(a.muerto and 'Derrotado esta semana' or 'En pie') w.meta:setColor(a.muerto and ORO or TEXTO2) w.titulo:setColor(a.muerto and TEXTO2 or CLARO) else w.meta:setText(string.format('%d / %d', muertos, #a[2])) w.meta:setColor(muertos == #a[2] and ORO or TEXTO2) end end ventana.tBloqueo:setText(d.tBloqueo or 'Tu bloqueo de esta semana') ventana.bloqueo:setText(d.bloqueo) ventana.renueva:setText(d.renueva) ventana.reglas:setText(d.reglas) ventana.grupo:setText(d.grupo) ventana.grupo:setColor(d.grupoColor or TEXTO2) ventana.entrar:setText(d.boton or 'Entrar en la Ciudadela') ventana.entrar:setEnabled(d.puede == true) ventana.entrar:setTooltip(d.porque or '') end local function mostrar() ventana:show() ventana:raise() ventana:focus() end -- «I|clave|nombre|meta|jefes|restante|emblemas|estado|texto» local function leer(partes) local d = { nombre = partes[3] or 'Raid', meta = partes[4] or '', alas = {}, arte = partes[2] } local muertos, total = 0, 0 for _, j in ipairs((partes[5] or ''):split('~')) do local c = j:split('^') if c[1] and c[1] ~= '' then total = total + 1 local muerto = c[2] == '1' if muerto then muertos = muertos + 1 end local lineas = {} for _, l in ipairs((c[3] or ''):split(';')) do if l ~= '' then lineas[#lineas + 1] = { l, false } end end d.alas[#d.alas + 1] = { c[1], lineas, jefe = true, muerto = muerto } end end local estado, texto = partes[8] or 'L', partes[9] or '' d.tBloqueo = 'Tu progreso de esta semana' d.bloqueo = estado == 'A' and string.format('%d / %d', muertos, total) or 'Sin progreso' d.renueva = 'Se renueva en ' .. tiempo(partes[6]) .. '. Los jefes muertos siguen muertos si sales y vuelves.' d.reglas = REGLAS d.grupo = 'Emblemas del Umbral: ' .. (partes[7] or '0') d.puede = estado ~= 'X' if estado == 'X' then d.grupo = texto d.grupoColor = ROJO d.porque = texto else d.porque = 'El líder abre la sala de entrada; cada uno confirma «Listo» junto al portal.' end d.boton = 'Entrar en la raid' return d end local function onOpcode(protocol, opcode, buffer) if not ventana then return end local partes = buffer:split('|') local t = partes[1] if t == 'C' then ventana:hide() elseif (t == 'I' or t == 'U') and #partes >= 8 then if t == 'U' and not ventana:isVisible() then return end clave = partes[2] pintar(leer(partes)) if t == 'I' then mostrar() end end end function probar(d) clave = nil pintar(d or EJEMPLO) ventana.entrar:setEnabled(false) ventana.entrar:setTooltip('Plantilla: las raids aún no están abiertas.') mostrar() end function toggle() if ventana:isVisible() then ventana:hide() else probar() end end function cerrar() ventana:hide() end function entrar() if clave then enviar('E|' .. clave) ventana:hide() end end function raidController:onInit() g_ui.importStyle('/game_viaje/valdren') ventana = g_ui.displayUI('raid') ventana:hide() ProtocolGame.registerExtendedOpcode(OPCODE, onOpcode) end function raidController:onTerminate() ProtocolGame.unregisterExtendedOpcode(OPCODE) if ventana then ventana:destroy() end ventana = nil end function raidController:onGameEnd() if ventana then ventana:hide() end end