#!/usr/bin/env python3 """Mudancas do Mini Grand Prix para o fredygames (ver build-mini-grand-prix.sh). Uso: python3 -I patch.py . 1. Os 24 circuitos levam nomes ficticios (o jogo usava nomes reais de autodromos): src/game/track.js (name), src/game/track-meta.js (details/cnDetails/cn); o subtitulo deixa de mostrar as coordenadas reais. Os tracados, as voltas e as distancias nao mudam. 2. Sem rede: o celular como controle (WebSocket e fetch('/ips'), que so funcionavam com o server.js do autor) sai: ws-client.js nao abre WebSocket e showQrPanel nao busca nada. 3. Sempre em ingles (o jogo tem uma opcao de interface em chines): o idioma nao le mais o localStorage e o botao de idioma some. 4. CSP que bloqueia qualquer requisicao fora da propria pagina. """ import re import sys from pathlib import Path root = Path(sys.argv[1]) # id -> (nome do circuito, lugar fictício mostrado no subtítulo) NAMES = { 'sunshine': ('Jade Harbor Circuit', 'Jade Harbor'), 'rainbow': ('Azure Cove Circuit', 'Azure Cove'), 'galaxy': ('Misty Pines Circuit', 'Misty Pines'), 'yasmarina': ('Pearl Marina Circuit', 'Pearl Marina'), 'lasvegas': ('Neon Strip Circuit', 'Neon Strip'), 'baku': ('Old Quarter Circuit', 'Old Quarter'), 'jeddah': ('Coral Corniche Circuit', 'Coral Corniche'), 'australia': ('Lakeside Park Circuit', 'Lakeside Park'), 'silverstone': ('Ironfield Circuit', 'Ironfield'), 'hockenheim': ('Blackwood Stadium Circuit', 'Blackwood Stadium'), 'bahrain': ('Dune Ridge Circuit', 'Dune Ridge'), 'brazil': ('Green Hills Circuit', 'Green Hills'), 'miami': ('Palm Stadium Circuit', 'Palm Stadium'), 'canada': ('Island Basin Circuit', 'Island Basin'), 'spain': ('Terracotta Circuit', 'Terracotta'), 'hungary': ('Valley Twist Circuit', 'Valley Twist'), 'austria': ('Alpine Ridge Circuit', 'Alpine Ridge'), 'netherlands': ('Seaside Banking Circuit', 'Seaside Banking'), 'singapore': ('Harbor Lights Circuit', 'Harbor Lights'), 'austin': ('Prairie Hill Circuit', 'Prairie Hill'), 'malaysia': ('Rainforest Circuit', 'Rainforest'), 'mexico': ('High Plateau Circuit', 'High Plateau'), 'qatar': ('Sand Oasis Circuit', 'Sand Oasis'), 'italy': ('Grand Park Circuit', 'Grand Park'), } # nome antigo em track.js (em ordem de aparicao no arquivo) -> id OLD_TRACK_NAMES = { 'Shanghai Circuit': 'sunshine', 'Monte Carlo Circuit': 'rainbow', 'Spa Circuit': 'galaxy', 'Yas Marina Circuit': 'yasmarina', 'Las Vegas Circuit': 'lasvegas', 'Baku Circuit': 'baku', 'Jeddah Circuit': 'jeddah', 'Melbourne Circuit': 'australia', 'Silverstone Circuit': 'silverstone', 'Hockenheim Circuit': 'hockenheim', 'Sakhir Circuit': 'bahrain', 'Miami Circuit': 'miami', 'Montréal Circuit': 'canada', 'Barcelona Circuit': 'spain', 'Hungaroring Circuit': 'hungary', 'Austrian Circuit': 'austria', 'Zandvoort Circuit': 'netherlands', 'Interlagos Circuit': 'brazil', 'Austin Circuit': 'austin', 'Sepang Circuit': 'malaysia', 'Mexico City Circuit': 'mexico', 'Lusail Circuit': 'qatar', 'Monza Circuit': 'italy', 'Marina Bay Circuit': 'singapore', } assert set(OLD_TRACK_NAMES.values()) == set(NAMES) and len(NAMES) == 24 def sub1(text, old, new, count=1): if text.count(old) != count: sys.exit(f'patch.py: esperava {count}x {old!r}, achei {text.count(old)}x') return text.replace(old, new) # 1. nomes dos circuitos p = root / 'src/game/track.js' s = p.read_text(encoding='utf-8') for old, tid in OLD_TRACK_NAMES.items(): s = sub1(s, f"name: '{old}'", f"name: '{NAMES[tid][0]}'") p.write_text(s, encoding='utf-8') p = root / 'src/game/track-meta.js' lines = p.read_text(encoding='utf-8').split('\n') done = set() for i, line in enumerate(lines): m = re.match(r"^(\s+)(\w+):(\s*)\{ flag: '([^']+)', details: '([^']*)', cnDetails: '([^']*)', (lat:[^}]*?), region: '(\w+)', cn: '([^']*)' \},?$", line) if not m: continue ind, tid, sp, flag, details, cn_details, latlon, region, cn = m.groups() place = NAMES[tid][1] rest = details.split(' · ', 1)[1] comma = ',' if line.rstrip().endswith(',') else '' lines[i] = f"{ind}{tid}:{sp}{{ flag: '{flag}', details: '{place} · {rest}', cnDetails: '{place} · {rest}', {latlon}, region: '{region}', cn: '{place}' }}{comma}" done.add(tid) assert done == set(NAMES), set(NAMES) - done p.write_text('\n'.join(lines), encoding='utf-8') # texto da interface que citava o primeiro circuito pelo pais p = root / 'src/i18n.js' s = p.read_text(encoding='utf-8') s = sub1(s, "'Start a new {n}-round season from Australia'", "'Start a new {n}-round season from the first round'") # 3. sempre em ingles s = sub1(s, "try { lang = localStorage.getItem(LANG_KEY) === 'zh' ? 'zh' : 'en'; } catch { /* 隐私模式 */ }", "// Fredygames: interface sempre em ingles.") s = sub1(s, " try { localStorage.setItem(LANG_KEY, lang); } catch { /* 隐私模式 / 无 localStorage */ }\n", "") p.write_text(s, encoding='utf-8') p = root / 'src/main.js' s = p.read_text(encoding='utf-8') s = sub1(s, "if (btnLang) btnLang.onclick = () => setLang(isZh() ? 'en' : 'zh');", "if (btnLang) btnLang.style.display = 'none';") p.write_text(s, encoding='utf-8') # o subtitulo do circuito mostrava as coordenadas reais do autodromo p = root / 'src/ui/menus.js' s = p.read_text(encoding='utf-8') s = sub1(s, "${trackDetails(track.id)}
${track.lat.toFixed(4)}°, ${track.lon.toFixed(4)}°", "${trackDetails(track.id)}") p.write_text(s, encoding='utf-8') # 2. sem rede p = root / 'src/gamepad/ws-client.js' s = p.read_text(encoding='utf-8') s = sub1(s, "export function initGamepadClient() {\n if (location.protocol === 'file:') return;\n connect();\n}", "export function initGamepadClient() {\n // Fredygames: sem controle por celular (nao ha servidor); nada de WebSocket.\n}") s = sub1(s, " ws = new WebSocket(`${proto}//${location.host}/ws`);", " return;") p.write_text(s, encoding='utf-8') p = root / 'src/ui/menus.js' s = p.read_text(encoding='utf-8') s = sub1(s, " const resp = await fetch('/ips');\n const data = await resp.json();\n", " const data = { urls: [] }; // Fredygames: sem servidor de controle por celular\n") p.write_text(s, encoding='utf-8') # 4. CSP p = root / 'index.html' s = p.read_text(encoding='utf-8') csp = ("default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; " "connect-src 'self'; font-src 'self'; frame-src 'none'; form-action 'none'; base-uri 'none'") s = sub1(s, ' \n', ' \n \n') p.write_text(s, encoding='utf-8')