diff -ru a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt 2026-04-04 15:57:52.000000000 -0400 +++ b/CMakeLists.txt 2026-10-13 00:31:21.341598230 -0400 @@ -376,6 +376,7 @@ # only ship the English language. target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_BINARY_DIR}/baseset@/baseset") target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_BINARY_DIR}/lang/english.lng@/lang/english.lng") + target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_BINARY_DIR}/lang/brazilian_portuguese.lng@/lang/brazilian_portuguese.lng") target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_SOURCE_DIR}/bin/ai@/ai") target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_SOURCE_DIR}/bin/game@/game") # Documentation files for the in-game text file viewer diff -ru a/os/emscripten/cmake/FindLibLZMA.cmake b/os/emscripten/cmake/FindLibLZMA.cmake --- a/os/emscripten/cmake/FindLibLZMA.cmake 2026-04-04 15:57:52.000000000 -0400 +++ b/os/emscripten/cmake/FindLibLZMA.cmake 2026-10-13 00:31:21.341168151 -0400 @@ -2,7 +2,7 @@ # someone patched their SDK. Test out if the SDK supports LibLZMA. include(CheckCXXSourceCompiles) set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) -set(CMAKE_REQUIRED_FLAGS "--use-port=contrib.liblzma") +set(CMAKE_REQUIRED_FLAGS "--use-port=${CMAKE_SOURCE_DIR}/os/emscripten/ports/liblzma.py") check_cxx_source_compiles(" #include @@ -13,8 +13,8 @@ if (LIBLZMA_FOUND) add_library(LibLZMA::LibLZMA INTERFACE IMPORTED) set_target_properties(LibLZMA::LibLZMA PROPERTIES - INTERFACE_COMPILE_OPTIONS "--use-port=contrib.liblzma" - INTERFACE_LINK_LIBRARIES "--use-port=contrib.liblzma" + INTERFACE_COMPILE_OPTIONS "--use-port=${CMAKE_SOURCE_DIR}/os/emscripten/ports/liblzma.py" + INTERFACE_LINK_LIBRARIES "--use-port=${CMAKE_SOURCE_DIR}/os/emscripten/ports/liblzma.py" ) else() message(WARNING "You are using an emscripten SDK without LibLZMA support. Many savegames won't be able to load in OpenTTD. Please copy liblzma.py to your ports/contrib folder in your local emsdk installation.") diff -ru a/os/emscripten/ports/liblzma.py b/os/emscripten/ports/liblzma.py --- a/os/emscripten/ports/liblzma.py 2026-04-04 15:57:52.000000000 -0400 +++ b/os/emscripten/ports/liblzma.py 2026-10-13 00:34:07.576596165 -0400 @@ -1,3 +1,4 @@ +# fredygames.com: loaded by path (--use-port=.../liblzma.py), so the port is named "liblzma". import os import logging @@ -9,14 +10,14 @@ LICENSE = 'LGPL-2.1' def get(ports, settings, shared): - ports.fetch_project('contrib.liblzma', f'https://github.com/tukaani-project/xz/releases/download/v{VERSION}/xz-{VERSION}.tar.xz', sha512hash=HASH) + ports.fetch_project('liblzma', f'https://github.com/tukaani-project/xz/releases/download/v{VERSION}/xz-{VERSION}.tar.xz', sha512hash=HASH) def create(final): logging.info('building port: contrib.liblzma') - ports.clear_project_build('contrib.liblzma') + ports.clear_project_build('liblzma') - source_path = os.path.join(ports.get_dir(), 'contrib.liblzma', f'xz-{VERSION}', 'src', 'liblzma') + source_path = os.path.join(ports.get_dir(), 'liblzma', f'xz-{VERSION}', 'src', 'liblzma') ports.write_file(os.path.join(source_path, 'config.h'), config_h) ports.install_headers(os.path.join(source_path, 'api'), pattern='lzma.h') ports.install_headers(os.path.join(source_path, 'api', 'lzma'), pattern='*.h', target='lzma') @@ -27,7 +28,7 @@ include_dirs_rel = ['../common', 'api', 'check', 'common', 'delta', 'lz', 'lzma', 'rangecoder', 'simple'] include_dirs = [os.path.join(source_path, p) for p in include_dirs_rel] - ports.build_port(source_path, final, 'contrib.liblzma', flags=build_flags, exclude_files=exclude_files, includes=include_dirs) + ports.build_port(source_path, final, 'liblzma', flags=build_flags, exclude_files=exclude_files, includes=include_dirs) return [shared.cache.get_lib('liblzma.a', create, what='port')] diff -ru a/os/emscripten/pre.js b/os/emscripten/pre.js --- a/os/emscripten/pre.js 2026-04-04 15:57:52.000000000 -0400 +++ b/os/emscripten/pre.js 2026-10-13 00:31:36.689492260 -0400 @@ -1,24 +1,7 @@ -Module.arguments.push('-mnull', '-snull', '-vsdl'); -Module['websocket'] = { url: function(host, port, proto) { - /* openttd.org hosts a WebSocket proxy for the content service. */ - if (host == "content.openttd.org" && port == 3978 && proto == "tcp") { - return "wss://bananas-server.openttd.org/"; - } - - /* Everything else just tries to make a default WebSocket connection. - * If you run your own server you can setup your own WebSocket proxy in - * front of it and let people connect to your server via the proxy. You - * are best to add another "if" statement as above for this. */ - - if (location.protocol === 'https:') { - /* Insecure WebSockets do not work over HTTPS, so we force - * secure ones. */ - return 'wss://'; - } else { - /* Use the default provided by Emscripten. */ - return null; - } -} }; +/* fredygames.com: SDL sound instead of none; music stays off (OpenMSX is MIDI). */ +Module.arguments.push('-mnull', '-ssdl', '-vsdl'); +/* fredygames.com: the web build plays offline (network.cpp), so no WebSocket proxy for the + * content service or for game servers is configured here. */ Module.preRun.push(function() { personal_dir = '/home/web_user/.openttd'; @@ -28,6 +11,9 @@ FS.mkdir(personal_dir); FS.mount(IDBFS, {}, personal_dir); + /* fredygames.com: the first start (no openttd.cfg yet) picks the language from the page. */ + if (Module.openttdLang) ENV.LANG = Module.openttdLang; + Module.addRunDependency('syncfs'); FS.syncfs(true, function (err) { Module.removeRunDependency('syncfs'); @@ -73,17 +59,6 @@ }); } - window.openttd_server_list = function() { - add_server = Module.cwrap("em_openttd_add_server", null, ["string"]); - - /* Add servers that support WebSocket here. Examples: - * add_server("localhost"); - * add_server("localhost:3979"); - * add_server("127.0.0.1:3979"); - * add_server("[::1]:3979"); - */ - } - var leftButtonDown = false; document.addEventListener("mousedown", e => { if (e.button == 0) { @@ -112,15 +87,4 @@ } } - /* https://github.com/emscripten-core/emscripten/pull/12995 implements this - * properly. Till that time, we use a polyfill. */ - SOCKFS.websocket_sock_ops.createPeer_ = SOCKFS.websocket_sock_ops.createPeer; - SOCKFS.websocket_sock_ops.createPeer = function(sock, addr, port) - { - let func = Module['websocket']['url']; - Module['websocket']['url'] = func(addr, port, (sock.type == 2) ? 'udp' : 'tcp'); - let ret = SOCKFS.websocket_sock_ops.createPeer_(sock, addr, port); - Module['websocket']['url'] = func; - return ret; - } }); diff -ru a/src/core/random_func.cpp b/src/core/random_func.cpp --- a/src/core/random_func.cpp 2026-04-04 15:57:52.000000000 -0400 +++ b/src/core/random_func.cpp 2026-10-13 00:51:20.582757024 -0400 @@ -112,7 +112,8 @@ return -1; } - crypto.getRandomValues(Module.HEAPU8.subarray(buf, buf + bytes)); + /* fredygames.com: Emscripten 4+ no longer exports HEAPU8 on Module; the runtime variable is in scope. */ + crypto.getRandomValues(HEAPU8.subarray(buf, buf + bytes)); return 1; }, buf.data(), buf.size()); if (res > 0) return; diff -ru a/src/network/network.cpp b/src/network/network.cpp --- a/src/network/network.cpp 2026-04-04 15:57:52.000000000 -0400 +++ b/src/network/network.cpp 2026-10-13 00:31:21.339885081 -0400 @@ -1289,6 +1289,11 @@ /* Network is available */ _network_available = NetworkCoreInitialize(); +#ifdef __EMSCRIPTEN__ + /* fredygames.com: the web build plays offline. Without this, the online content service, + * the server list and the game coordinator would connect to openttd.org. */ + _network_available = false; +#endif _network_dedicated = false; _network_game_info = {}; diff -ru a/src/openttd.cpp b/src/openttd.cpp --- a/src/openttd.cpp 2026-04-04 15:57:52.000000000 -0400 +++ b/src/openttd.cpp 2026-10-13 00:31:21.340458492 -0400 @@ -1163,6 +1163,7 @@ ShowErrorMessage(GetEncodedString(STR_WARNING_FALLBACK_SOUNDSET), {}, WL_CRITICAL); BaseSounds::ini_set = BaseSounds::GetUsedSet()->name; } +#ifndef __EMSCRIPTEN__ /* fredygames.com: offline build, nothing is ever transmitted. */ if (_settings_client.network.participate_survey == PS_ASK) { /* No matter how often you go back to the main menu, only ask the first time. */ static bool asked_once = false; @@ -1171,6 +1172,7 @@ ShowNetworkAskSurvey(); } } +#endif UpdateSocialIntegration(GM_MENU); break;