-- OT-MMO: cartel de zona al entrar (como en WoW) y nombre de la zona actual junto al minimapa. -- El servidor (server/scripts/zonas.lua, opcode 124) manda UNA vez la lista de zonas con «Z|[[x1,y1,x2,y2,z1,z2,prio, -- nombre,subtitulo,cartel],...]»; aqui se calcula en que zona se esta al moverse (gana la de mayor prioridad y, a igual -- prioridad, la de menor area) y el cartel solo sale al CAMBIAR de zona. Todo va protegido con pcall: un error en -- onPositionChange cortaria la cadena y el minimapa dejaria de seguir al jugador (paso el 22-oct). local OPCODE = 124 local ENTRADA, QUIETO, SALIDA = 500, 2000, 700 -- ms del fundido de entrada, el cartel quieto y el fundido de salida local PASO = 30 zonasController = Controller:new() local zonas = {} -- { x1, y1, x2, y2, z1, z2, prio, nombre, sub, cartel, area } local cartel = nil local actual = nil -- zona en la que se esta (tabla de `zonas`) o nil local ultimaPos = nil local animacion = nil local textoOriginal = nil local function mapa() return modules.game_interface.getMapPanel() end local function parar() removeEvent(animacion) animacion = nil end -- Fundido: 0 -> 1 en ENTRADA, quieto, 1 -> 0 en SALIDA. local function mostrar(nombre, sub) if not cartel then return end cartel.nombre:setText(nombre) cartel.sub:setText(sub or '') cartel.sub:setVisible((sub or '') ~= '') parar() cartel:setOpacity(0) cartel:show() local inicio = g_clock.millis() local total = ENTRADA + QUIETO + SALIDA local function paso() local e = g_clock.millis() - inicio if e >= total then cartel:hide() animacion = nil return end local o if e < ENTRADA then o = e / ENTRADA elseif e > ENTRADA + QUIETO then o = (total - e) / SALIDA else o = 1 end cartel:setOpacity(o) animacion = scheduleEvent(paso, PASO) end paso() end -- Nombre fijo junto al minimapa: el asa «Mapa» de arriba del marco (game_hud) pasa a llevar el nombre de la zona. local function etiqueta(texto) local raiz = g_ui.getRootWidget() local asa = raiz and raiz:recursiveGetChildById('moverMapa') if not asa then return false end if not textoOriginal then textoOriginal = asa:getText() end if texto and texto ~= '' then asa:setWidth(200) asa:setMarginTop(-7) -- sube el asa para no rozar la N de la brujula asa:setText(texto) else asa:setWidth(70) asa:setMarginTop(0) asa:setText(textoOriginal) end return true end local function zonaEn(pos) local mejor for _, z in ipairs(zonas) do if pos.x >= z[1] and pos.x <= z[3] and pos.y >= z[2] and pos.y <= z[4] and pos.z >= z[5] and pos.z <= z[6] then if not mejor or z[7] > mejor[7] or (z[7] == mejor[7] and z.area < mejor.area) then mejor = z end end end return mejor end local function evaluar(pos) if not pos or #zonas == 0 then return end ultimaPos = pos local z = zonaEn(pos) if z == actual then return end local misma = z and actual and z[8] == actual[8] and z[9] == actual[9] actual = z if not etiqueta(z and z[8] or nil) then scheduleEvent(function() etiqueta(actual and actual[8] or nil) end, 1500) -- el marco del minimapa aun no existe end if z and z[10] == 1 and not misma then mostrar(z[8], z[9]) elseif not z or z[10] ~= 1 then parar() if cartel then cartel:hide() end end end local function alMoverse(_, pos) local ok, err = pcall(evaluar, pos) if not ok then ultimoError = tostring(err) -- visible desde la terminal: modules.game_zonas.ultimoError g_logger.error('[game_zonas] ' .. tostring(err)) end end local function onOpcode(protocol, opcode, buffer) if buffer:sub(1, 2) ~= 'Z|' then return end local ok, datos = pcall(json.decode, buffer:sub(3)) if not ok or type(datos) ~= 'table' then return end zonas = {} for _, z in ipairs(datos) do z.area = (z[3] - z[1] + 1) * (z[4] - z[2] + 1) zonas[#zonas + 1] = z end actual = nil local jugador = g_game.getLocalPlayer() if jugador then alMoverse(nil, jugador:getPosition()) end end -- Para pruebas desde la terminal: modules.game_zonas.recibir('Z|[...]') function recibir(buffer) onOpcode(nil, OPCODE, buffer) end function zonasController:onInit() ProtocolGame.registerExtendedOpcode(OPCODE, onOpcode) end function zonasController:onTerminate() ProtocolGame.unregisterExtendedOpcode(OPCODE) parar() etiqueta(nil) if cartel then cartel:destroy() cartel = nil end end function zonasController:onGameStart() if not cartel then g_ui.importStyle('zonas') local m = mapa() cartel = g_ui.createWidget('CartelZona', m) cartel:addAnchor(AnchorTop, 'parent', AnchorTop) cartel:addAnchor(AnchorHorizontalCenter, 'parent', AnchorHorizontalCenter) cartel:setMarginTop(90) end actual = nil local protocol = g_game.getProtocolGame() if protocol then protocol:sendExtendedOpcode(OPCODE, 'P') end zonasController:registerEvents(LocalPlayer, { onPositionChange = alMoverse }) end function zonasController:onGameEnd() parar() actual = nil if cartel then cartel:hide() end etiqueta(nil) end