-- private variables local background local clientVersionLabel local bgEffectEvent = nil local toggleState = true -- controls which effect is active local timeLoopBackgroundEffect = 5000 -- 5 seconds -- OT-MMO: login «El Último Faro» (23-oct). Arte del kit VALDREN_Login_Kit (ver data/images/login/ORIGEN.txt). -- Coordenadas en píxeles del arte (fondo.png, 1920x1039 = pixel del kit sin la banda oscura de 41 px de arriba). local ARTE_W, ARTE_H = 1920, 1039 local LINTERNA_X, LINTERNA_Y = 1600, 160 -- centroide del brillo de la linterna, medido en el arte local FOCO_X, FOCO_Y = 0.75, 0.35 -- recorte: la linterna tiende al 75 % del ancho; sobra vertical 35/65 local HAZ_LARGO, HAZ_ALTO = 1700, 520 -- haz.png (850x260) dibujado a x2 local AURA = 190 local REFLEJO_X, REFLEJO_Y, REFLEJO_W, REFLEJO_H = 1120, 494, 520, 60 local LOGO_W, LOGO_H = 628, 335 -- logo.png con 14 px de margen para su sombra local TICK = 40 -- 25 fps: el haz va difuminado, no hace falta más local faroEvent = nil local escala, origenX, origenY = 1, 0, 0 local enterGameWin = nil local ultimoAviso = 0 -- «Reducir movimiento»: el navegador lo escribe en /reducir-movimiento.txt (browser/shell.html, matchMedia). -- En escritorio no existe el archivo; g_settings 'login-faro-quieto' = true lo fuerza a mano en cualquier build. local function sinMovimiento() if g_settings.getBoolean('login-faro-quieto') then return true end local ok, txt = pcall(g_resources.readFileContents, '/reducir-movimiento.txt') return ok and type(txt) == 'string' and txt:sub(1, 1) == '1' end local function capa(id) return background:getChildById(id) end local function ponerEn(w, x, y, ancho, alto) w:setSize({ width = math.floor(ancho + 0.5), height = math.floor(alto + 0.5) }) w:setMarginLeft(math.floor(x + 0.5)) w:setMarginTop(math.floor(y + 0.5)) end -- Coloca una capa de tamaño (w, h) del arte con su centro en el punto (ax, ay) del arte. local function centrarEnArte(w, ax, ay, ancho, alto) ponerEn(w, origenX + (ax - ancho / 2) * escala, origenY + (ay - alto / 2) * escala, ancho * escala, alto * escala) end local function quieto() capa('haz'):setRotation(0) capa('haz'):setOpacity(0.55) capa('aura'):setOpacity(0.75) capa('reflejo'):setOpacity(0.12) end local function fotograma() local t = g_clock.millis() local dos = 2 * math.pi -- 23-oct: más visible («nada cambia ni se mueve»): ±10° en 9 s, pulso 2,6 s, reflejo más marcado local barrido = math.sin(dos * t / 9000) capa('haz'):setRotation(10 * barrido) capa('haz'):setOpacity(0.6 + 0.4 * (0.5 + 0.5 * math.sin(dos * t / 9000 + 1.2))) capa('aura'):setOpacity(0.3 + 0.7 * (0.5 + 0.5 * math.sin(dos * t / 2600))) local ola = math.sin(dos * t / 4000) capa('reflejo'):setOpacity(0.05 + 0.3 * (0.5 + 0.5 * ola)) capa('reflejo'):setMarginLeft(math.floor(origenX + (REFLEJO_X - REFLEJO_W / 2 + 18 * ola) * escala + 0.5)) if t - ultimoAviso > 2000 then -- ¿cambió «reducir movimiento»? ultimoAviso = t if sinMovimiento() then pararFaro() quieto() end end end function pararFaro() if faroEvent then removeEvent(faroEvent) faroEvent = nil end end function arrancarFaro() pararFaro() do return end -- 23-oct: sin fondo ni faro animado (el usuario los quitó); solo queda el logo if not background or not background:isVisible() or sinMovimiento() then if background then quieto() end return end faroEvent = cycleEvent(fotograma, TICK) end local function ventanaLogin() if enterGameWin and enterGameWin:isDestroyed() then enterGameWin = nil end if not enterGameWin then enterGameWin = rootWidget:getChildById('enterGame') if enterGameWin then connect(enterGameWin, { onVisibilityChange = colocarLogo, onGeometryChange = colocarLogo }) end end return enterGameWin end -- Logo + subtítulo encima de la ventana de login; el grupo (logo + ventana) queda centrado en pantalla. -- La ventana baja medio bloque con margin-top (con centerIn, el margen superior desplaza el centro). function colocarLogo() if not background then return end local logo, marca = capa('logo'), capa('marca') local win = ventanaLogin() local visible = win and win:isVisible() and background:isVisible() if not visible then logo:hide(); marca:show() return end local W, H = background:getWidth(), background:getHeight() local alto = win:getHeight() local ancho = math.min(460, W - 24) local libre = H - alto - 32 - 16 - 24 -- márgenes arriba/abajo, subtítulo y separación ancho = math.min(ancho, libre * LOGO_W / LOGO_H) local bloque = 0 if ancho >= 160 then local h = ancho * LOGO_H / LOGO_W bloque = h + 16 -- logo y separación con la ventana local arriba = (H - alto - bloque) / 2 ponerEn(logo, (W - ancho) / 2, arriba, ancho, h) logo:show(); marca:hide() else logo:hide(); marca:show() -- no cabe: queda la marca de arriba a la izquierda end local margen = math.floor(bloque / 2 + 0.5) if win:getMarginTop() ~= margen then win:setMarginTop(margen) end end function colocar() if not background then return end colocarLogo() -- 23-oct: sin capas del faro; solo el logo encima de la ventana de login end -- public functions function init() background = g_ui.displayUI('background') background:lower() clientVersionLabel = background:getChildById('clientVersionLabel') clientVersionLabel:setText(g_app.getName() .. ' ' .. g_app.getVersion() .. '\n' .. 'Rev ' .. g_app.getBuildRevision() .. ' (' .. g_app.getBuildCommit() .. ')\n' .. 'Built on ' .. g_app.getBuildDate() .. '\n' .. g_app.getBuildCompiler() .. ' - ' .. g_app.getBuildArch()) if not g_game.isOnline() then addEvent(function() g_effects.fadeIn(clientVersionLabel, 1500) end) end connect(g_game, { onGameStart = hide }) connect(g_game, { onGameEnd = show }) background.onGeometryChange = colocar addEvent(colocar) -- la ventana de login (client_entergame) se crea después de este módulo startBackgroundEffectLoop() -- start the background effect loop arrancarFaro() if g_game.isOnline() then hide() end end function terminate() disconnect(g_game, { onGameStart = hide }) disconnect(g_game, { onGameEnd = show }) pararFaro() if enterGameWin and not enterGameWin:isDestroyed() then disconnect(enterGameWin, { onVisibilityChange = colocarLogo, onGeometryChange = colocarLogo }) enterGameWin:setMarginTop(0) end enterGameWin = nil g_effects.cancelFade(background:getChildById('clientVersionLabel')) if bgEffectEvent then removeEvent(bgEffectEvent) bgEffectEvent = nil end background:destroy() background = nil clientVersionLabel = nil end function hide() background:hide() pararFaro() -- en el juego no se anima nada del login if bgEffectEvent then removeEvent(bgEffectEvent) bgEffectEvent = nil end end function show() background:show() startBackgroundEffectLoop() colocar() arrancarFaro() end function hideVersionLabel() background:getChildById('clientVersionLabel'):hide() end function setVersionText(text) clientVersionLabel:setText(text) end function getBackground() return background end -- OT-MMO: sin partículas en el fondo (guía A.10: nada de brillos ni decoración gratuita). function startBackgroundEffectLoop() if bgEffectEvent then removeEvent(bgEffectEvent) bgEffectEvent = nil end end