import { t, setLanguage, currentLang } from './i18n.js'; import { Assets, Sprite, NineSliceSprite, Container, TilingSprite, Text, wordWrap, fragmentGPUTemplate, Graphics } from 'pixi.js'; import { loginUser, registerUser, verifyEmailUser, resendOTPCode, requestPasswordResetUser, resetPasswordUser, refreshAccessTokenUser } from './api/auth.js'; import { initDropdowns, updateTranslations } from './ui/dropdowns.js'; import { initForms, formState, setOtpMode, setResetPasswordMode, startVisualCountdown, setRegisterMode } from './ui/forms.js'; import { fetchSectorsList, joinSectorUser } from './api/sectors.js'; import { app, initPixi, setupResize, triggerResize } from './core/pixi-app.js'; import { buildLoginScene, LOGIN_COLORS } from './scenes/login-scene.js'; import { buildLobbyBase, createSectorTabPixi, createSectorCardPixi, buildOnboardingModalPixi } from './scenes/lobby-scene.js'; let globalSheet = null; let background = null; let uiContainer = null; let lobbyPixiContainer = null; let sectorPixiContainer = null; let sectorTabsPixiContainer = null; let footerBackground = null; let footerPattern = null; let footerBackgroundContainer = null; let onboardingPixiContainer = null; let onboardingPixiRefs = null; let selectedSectorId = null; let selectedOnboardingGender = 'male'; async function initGame() { await initPixi('pixi-container'); try { const assetsToLoad = { background: 'src/raw-assets/backgrounds/Background_A.png', uiAtlas: 'src/assets/ui-atlas.json' }; const backgroundTexture = await Assets.load(assetsToLoad.background); const uiSpritesheet = await Assets.load(assetsToLoad.uiAtlas); await document.fonts.load('16px "UI Font"'); await document.fonts.load('16px "Logo Font"'); updateTranslations(); buildScene(backgroundTexture, uiSpritesheet); document.getElementById('username').placeholder = t('ph_username_reg'); document.getElementById('email').placeholder = t('ph_email'); document.getElementById('password').placeholder = t('ph_password'); document.getElementById('btn-register').textContent = t('btn_register'); await checkAuthOnStartup(); } catch (error) { console.error("Fehler beim Laden der Assets:", error); } } function buildScene(bgTexture, sheet) { globalSheet = sheet; // --- Hintergrund --- background = new Sprite(bgTexture); app.stage.addChild(background); // --- Haupt-UI-Container --- uiContainer = new Container(); app.stage.addChild(uiContainer); lobbyPixiContainer = new Container(); lobbyPixiContainer.visible = false; app.stage.addChild(lobbyPixiContainer); sectorPixiContainer = buildLobbyBase(lobbyPixiContainer, sheet); const htmlSectorList = document.getElementById('sector-list-container'); if (htmlSectorList) { htmlSectorList.addEventListener('scroll', (e) => { sectorPixiContainer.y = -e.target.scrollTop; }); } // --- Footer Hintergund --- footerBackgroundContainer = new Container(); footerBackground = new TilingSprite({ texture: sheet.textures['SPR_SciFiMenus_Background_01'], height: 40, }); footerBackground.tileScale.set(1.0); footerBackground.tint = 0x000000; footerBackground.alpha = 1.0; footerBackgroundContainer.addChild(footerBackground); footerPattern = new TilingSprite({ texture: sheet.textures['SPR_SciFiMenus_Background_Hexagons_01'], height: 40, }); footerPattern.tileScale.set(0.3); footerPattern.tint = LOGIN_COLORS.PATTERN; footerPattern.alpha = 0.01; footerBackgroundContainer.addChild(footerPattern); app.stage.addChild(footerBackgroundContainer); onboardingPixiRefs = buildOnboardingModalPixi(app.stage, sheet); onboardingPixiContainer = onboardingPixiRefs.container; const loginRefs = buildLoginScene(uiContainer, sheet); initForms({ tabLogin: loginRefs.tabLogin, tabRegister: loginRefs.tabRegister, inputUser: loginRefs.inputUser, inputEmail: loginRefs.inputEmail, inputLock: loginRefs.inputLock, btnRegister: loginRefs.btnRegister, discordIcon: loginRefs.discordIcon, discordText: loginRefs.discordText, COLOR_TAB_ACTIVE: LOGIN_COLORS.TAB_ACTIVE, COLOR_TAB_INACTIVE: LOGIN_COLORS.TAB_INACTIVE, COLOR_TAB_HOVER: LOGIN_COLORS.TAB_HOVER, COLOR_BTN_HOVER: LOGIN_COLORS.BTN_HOVER, COLOR_BTN_DEFAULT: LOGIN_COLORS.BTN_DEFAULT }); setupResize({ background, discordContainer: loginRefs.discordContainer, logoContainer: loginRefs.logoContainer, uiContainer, panelFrame: loginRefs.panelFrame, lobbyPixiContainer, footerBackground, footerPattern, footerBackgroundContainer, onboardingPixiContainer }); formState.isLoginMode = true; setRegisterMode(); } const form = document.getElementById('register-form'); const msgBox = document.getElementById('msg-box'); form.addEventListener('submit', async (e) => { e.preventDefault(); const usernameVal = document.getElementById('username').value; const emailVal = document.getElementById('email').value; const passwordVal = document.getElementById('password').value; msgBox.textContent = '...'; msgBox.style.color = 'var(--color-text-main)'; if (formState.isForgotPasswordMode) { try { const result = await requestPasswordResetUser(emailVal); if (!result.ok) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t(result.data.error) || t('ERR_INTERNAL_SERVER'); return; } msgBox.style.color = 'var(--color-green-bright)'; msgBox.textContent = t(result.data.message); setTimeout(() => { setResetPasswordMode(emailVal); }, 1500); } catch (error) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t('ERR_INTERNAL_SERVER'); } return; } if (formState.isResetPasswordMode) { try { const result = await resetPasswordUser(formState.resetEmail, emailVal, passwordVal); if (!result.ok) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t(result.data.error) || t('ERR_INTERNAL_SERVER'); return; } msgBox.style.color = 'var(--color-green-bright)'; msgBox.textContent = t(result.data.message); setTimeout(() => { window.location.reload(); }, 1500); } catch (error) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t('ERR_INTERNAL_SERVER'); } return; } if (formState.isOtpMode) { try { const result = await verifyEmailUser(formState.pendingVerificationEmail, passwordVal); if (!result.ok) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t(result.data.error) || t('ERR_INTERNAL_SERVER'); return; } msgBox.style.color = 'var(--color-green-bright)'; msgBox.textContent = t('msg_verify_success'); setTimeout(() => { window.location.reload(); }, 1500); } catch (error) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t('ERR_INTERNAL_SERVER'); } return; } if (formState.isLoginMode) { try { const result = await loginUser(usernameVal, passwordVal); if (!result.ok) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t(result.data.error) || t('ERR_INTERNAL_SERVER'); if (result.data.error === 'ERR_EMAIL_NOT_VERIFIED') { setTimeout(() => { setOtpMode(result.data.email); }, 1500); } return; } msgBox.style.color = 'var(--color-green-bright)'; msgBox.textContent = t(result.data.message); const rememberMe = document.getElementById('remember').checked; sessionStorage.setItem('void_access_token', result.data.accessToken); sessionStorage.setItem('void_user', JSON.stringify(result.data.user)); if (rememberMe) { localStorage.setItem('void_refresh_token', result.data.refreshToken); sessionStorage.removeItem('void_refresh_token'); } else { sessionStorage.setItem('void_refresh_token', result.data.refreshToken); localStorage.removeItem('void_refresh_token'); } transitionToLobby(); } catch (error) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t('ERR_INTERNAL_SERVER'); } } else { // Register Mode try { const result = await registerUser(usernameVal, emailVal, passwordVal); if (!result.ok) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t(result.data.error)|| t('ERR_INTERNAL_SERVER'); return; } msgBox.style.color = 'var(--color-green-bright)'; msgBox.textContent = t(result.data.message); setTimeout(() => { setOtpMode(emailVal); }, 1500); } catch (error) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t('ERR_INTERNAL_SERVER'); } } }); const resendOtpLink = document.getElementById('resend-otp-link'); if (resendOtpLink) { resendOtpLink.addEventListener('click', async (e) => { e.preventDefault(); if (!pendingVerificationEmail) return; msgBox.textContent = '...'; msgBox.style.color = 'var(--color-text-main)'; try { const result = await resendOTPCode(pendingVerificationEmail); if (!result.ok) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t(result.data.error) || t('ERR_INTERNAL_SERVER'); return; } msgBox.style.color = 'var(--color-green-bright)'; msgBox.textContent = t(result.data.message); startVisualCountdown(resendOtpLink, 'link_resend_otp', 120); } catch (error) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t('ERR_INTERNAL_SERVER'); } }); } /** * Diese Funktion wird aufgerufenm wenn der Login erfolgreich war und die Tokens * sicher gespeichert sind, Sie baut das HTML-Formulat ab und bereitet PixiJS * auf die Lobby-Ansicht vor */ async function transitionToLobby() { const formElement = document.getElementById('register-form'); if (formElement) { formElement.style.display = 'none'; } uiContainer.visible = false; lobbyPixiContainer.visible = true; try { const lobbyBGPath = 'src/raw-assets/backgrounds/SPR_SciFiMenus_Example_Image_SpookyComputer_01.png'; const lobbyBGTexture = await Assets.load(lobbyBGPath); background.texture = lobbyBGTexture; triggerResize(); buildLobbyUI(); } catch (error) { console.error("Fehler beim Laden des Lobby-Hintergrunds:", error); } } /** * Blendet die Top-Bar ein, setzt den Spilernamen und aktiviert den Logout */ async function buildLobbyUI() { const userDropdown = document.getElementById('user-dropdown'); if (userDropdown) { userDropdown.style.display = 'block'; } const userDataStr = sessionStorage.getItem('void_user'); if (userDataStr) { try { const userData = JSON.parse(userDataStr); const usernameEl = document.getElementById('lobby-username'); if (usernameEl && userData.username) { usernameEl.textContent = userData.username; } const emailEl = document.getElementById('lobby-email'); if (emailEl && userData.email) { emailEl.textContent = userData.email; } const premiumEl = document.getElementById('lobby-premium'); if (premiumEl && userData.res_premium !== undefined) { premiumEl.textContent = userData.res_premium; } } catch (e) { console.error("Fehler beim Auslesen der User-Daten:", e); } } await loadAndRenderSectorBrowser(); } /** * Läd die Sektordaten von der API und steuert die Tab-Sichtbarkeiten */ async function loadAndRenderSectorBrowser() { const token = sessionStorage.getItem('void_access_token') || localStorage.getItem('void_access_token'); if (!token) return; try { const result = await fetchSectorsList(token); if (!result.ok || !result.data.success) { console.error("Fehler beim Laden der Sektoren:", result.data.error); return; } const data = result.data; const layer = document.getElementById('sector-browser-layer'); layer.style.display = 'block'; const tabLastSector = document.getElementById('tab-last-sector'); const tabMySectors = document.getElementById('tab-my-sectors'); const tabNewSectors = document.getElementById('tab-new-sectors'); if (sectorTabsPixiContainer) { lobbyPixiContainer.removeChild(sectorTabsPixiContainer); sectorTabsPixiContainer.destroy({ children: true }); } sectorTabsPixiContainer = new Container(); lobbyPixiContainer.addChild(sectorTabsPixiContainer); const isMobilePortrait = window.innerWidth <= 800 && window.innerHeight > window.innerWidth; const centerPos = isMobilePortrait ? 325 : 620; if (data.mySectors.length === 0) { // Szenario A: Keine eigenen Sektoren tabLastSector.style.display = 'none'; tabMySectors.style.display = 'none'; tabNewSectors.classList.add('active'); const singleTabX = centerPos - 90; const tabNewBg = createSectorTabPixi(globalSheet, singleTabX, 20, LOGIN_COLORS.TAB_ACTIVE, 0.6); // ACHTUNG: Hier jetzt .container verwenden! sectorTabsPixiContainer.addChild(tabNewBg.container); renderSectorList(data.newSectors, 'new'); } else { // Szenario B: Eigene Sektoren vorhanden tabLastSector.style.display = 'inline-block'; tabMySectors.style.display = 'inline-block'; tabNewSectors.style.display = 'inline-block'; // --- NEU: Daten für die Tabs filtern und aufteilen --- // 1. "Zuletzt gespielt" // Da das Backend bereits nach Datum absteigend sortiert, ist das Element // an Index 0 garantiert der Sektor, in dem der Spieler zuletzt aktiv war. // Wir packen ihn in ein neues Array, da unsere renderSectorList-Funktion ein Array erwartet. const lastPlayedSectorArray = [data.mySectors[0]]; // 2. "Meine Sektoren" (Der Rest) // Wir nutzen die JavaScript-Funktion 'slice(1)', um alle Sektoren ab dem zweiten Element (Index 1) // bis zum Ende des Arrays zu kopieren. // Hinweis: Wenn der Spieler insgesamt nur 1 Sektor besitzt, gibt slice(1) automatisch // ein leeres Array [] zurück, was perfekt ist! const otherMySectorsArray = data.mySectors.slice(1); // --- PixiJS-Hintergründe berechnen (unverändert) --- const leftTabX = centerPos - 290; const midTabX = centerPos - 90; const rightTabX = centerPos + 110; const tabLastBg = createSectorTabPixi(globalSheet, leftTabX, 20, LOGIN_COLORS.TAB_ACTIVE, 0.6); const tabMyBg = createSectorTabPixi(globalSheet, midTabX, 20, LOGIN_COLORS.TAB_INACTIVE, 0.4); const tabNewBg = createSectorTabPixi(globalSheet, rightTabX, 20, LOGIN_COLORS.TAB_INACTIVE, 0.4); sectorTabsPixiContainer.addChild(tabLastBg.container, tabMyBg.container, tabNewBg.container); const updateTabVisuals = (activeHtmlId) => { tabLastSector.classList.remove('active'); tabMySectors.classList.remove('active'); tabNewSectors.classList.remove('active'); document.getElementById(activeHtmlId).classList.add('active'); tabLastBg.fill.tint = LOGIN_COLORS.TAB_INACTIVE; tabLastBg.fill.alpha = 0.4; tabMyBg.fill.tint = LOGIN_COLORS.TAB_INACTIVE; tabMyBg.fill.alpha = 0.4; tabNewBg.fill.tint = LOGIN_COLORS.TAB_INACTIVE; tabNewBg.fill.alpha = 0.4; if (activeHtmlId === 'tab-last-sector') { tabLastBg.fill.tint = LOGIN_COLORS.TAB_ACTIVE; tabLastBg.fill.alpha = 0.6; } if (activeHtmlId === 'tab-my-sectors') { tabMyBg.fill.tint = LOGIN_COLORS.TAB_ACTIVE; tabMyBg.fill.alpha = 0.6; } if (activeHtmlId === 'tab-new-sectors') { tabNewBg.fill.tint = LOGIN_COLORS.TAB_ACTIVE; tabNewBg.fill.alpha = 0.6; } }; // --- ÄNDERUNG: Klick-Events mit den gefilterten Arrays versorgen --- tabLastSector.onclick = () => { updateTabVisuals('tab-last-sector'); // Wir übergeben hier ausschließlich das Array mit dem EINEN, letzten Sektor renderSectorList(lastPlayedSectorArray, 'my'); }; tabMySectors.onclick = () => { updateTabVisuals('tab-my-sectors'); // Wir übergeben hier alle Sektoren AUSSER dem letzten renderSectorList(otherMySectorsArray, 'my'); }; tabNewSectors.onclick = () => { updateTabVisuals('tab-new-sectors'); // Neue Sektoren bleiben natürlich unangetastet renderSectorList(data.newSectors, 'new'); }; const setupTabHover = (htmlEl, pixiRef) => { htmlEl.onmouseenter = () => { if (!htmlEl.classList.contains('active')) { pixiRef.fill.tint = LOGIN_COLORS.TAB_HOVER; pixiRef.fill.alpha = 0.8; } }; htmlEl.onmouseleave = () => { if (!htmlEl.classList.contains('active')) { pixiRef.fill.tint = LOGIN_COLORS.TAB_INACTIVE; pixiRef.fill.alpha = 0.4; } }; }; setupTabHover(tabLastSector, tabLastBg); setupTabHover(tabMySectors, tabMyBg); setupTabHover(tabNewSectors, tabNewBg); // --- ÄNDERUNG: Initialer Aufruf --- // Wenn die Lobby lädt, starten wir standardmäßig im "Zuletzt gespielt"-Tab, // also übergeben wir auch hier das gefilterte 1-Element-Array. renderSectorList(lastPlayedSectorArray, 'my'); } } catch (error) { console.error("Netzwerkfehler beim Sektor-Abruf:", error); } } /** * Rendert die HTML-Karte und die dazugehöhrigen PixiJS-Hintergrundboxen */ function renderSectorList(sectors, type) { const listContainer = document.getElementById('sector-list-container'); listContainer.innerHTML = ''; if (sectorPixiContainer) { sectorPixiContainer.removeChildren(); sectorPixiContainer.y = 0; } const htmlSectorList = document.getElementById('sector-list-container'); if (htmlSectorList) htmlSectorList.scrollTop = 0; if (sectors.length === 0) { listContainer.innerHTML = '

Keine Sektoren in dieser Kategorie verfügbar.

'; return; } sectors.forEach((sector, index) => { const cardLink = document.createElement('a'); cardLink.className = 'sector-card-link'; cardLink.href = `#`; // --- Temporäre Platzhalter für das neue UI (ersetzen wir später durch echte DB-Werte) --- const ageDays = sector.age_days || Math.floor(Math.random() * 30) + 1; const totalPlayers = sector.total_players || Math.floor(Math.random() * 500) + 150; let bottomRowHtml = ''; if (type === 'my' && sector.local_username) { bottomRowHtml = `
Spieler: ${sector.local_username}
`; } cardLink.innerHTML = `
${sector.name} ${ageDays} Tage ${sector.status === 'online' ? 'online' : 'wartung'} Online: ${sector.online_players}/${totalPlayers} Planeten: ${sector.planets_count} ${bottomRowHtml}
`; cardLink.onclick = (e) => { e.preventDefault(); console.log(`Starte Onboarding für Sektor: ${sector.name} (ID: ${sector.id})`); selectedSectorId = sector.id; const sectorBrowserLayer = document.getElementById('sector-browser-layer'); if (sectorBrowserLayer) { sectorBrowserLayer.style.opacity = 0.05; sectorBrowserLayer.style.pointerEvents = 'none'; } const onboardingHtmlLayer = document.getElementById('sector-onboarding-layer'); if (onboardingHtmlLayer) onboardingHtmlLayer.style.display = 'flex'; if (onboardingPixiContainer) onboardingPixiContainer.visible = true; const localUsernameInput = document.getElementById('local-username'); if (localUsernameInput) { // Den Nutzer-String aus dem SessionStorage abrufen, den wir beim Login gespeichert haben const userDataStr = sessionStorage.getItem('void_user') || localStorage.getItem('void_user'); if (userDataStr) { try { // Den JSON-String wieder in ein nutzbares JavaScript-Objekt umwandeln const userData = JSON.parse(userDataStr); if (userData.username) { // Wir tragen den Namen als echten Wert ein, damit das 'required' Attribut erfüllt ist localUsernameInput.value = userData.username; } } catch (err) { console.error("Fehler beim Auslesen der User-Daten für das Onboarding:", err); } } } }; listContainer.appendChild(cardLink); const isMobilePortrait = window.innerWidth <= 800 && window.innerHeight > window.innerWidth; // Im Hochformat haben wir 2 Spalten (durch unsere Media Query), sonst 4 const columns = isMobilePortrait ? 2 : 4; const cardWidth = 270; const cardHeight = 90; const gapX = 25; const gapY = 20; // Wir lesen die echte Breite des HTML-Containers ab (das zieht die Scrollbar automatisch ab!) const listContainerDOM = document.getElementById('sector-list-container'); const containerClientWidth = listContainerDOM ? listContainerDOM.clientWidth : (isMobilePortrait ? 650 : 1240); // Wir berechnen die Breite des GESAMTEN Grid-Blocks. // Bei 4 Spalten: (4 * 270) + (3 * 25) = 1155px Gesamtbreite. const gridBlockWidth = (columns * cardWidth) + ((columns - 1) * gapX); // Der Start-Punkt X ist exakt die verbleibende Restbreite geteilt durch 2. // Das entspricht mathematisch 1:1 dem 'justify-content: center' aus dem CSS. const startX = (containerClientWidth - gridBlockWidth) / 2; const startY = 100; // 80px Top-Bar-Offset + 20px Padding oben const col = index % columns; const row = Math.floor(index / columns); const posX = startX + col * (cardWidth + gapX); const posY = startY + row * (cardHeight + gapY); // PixiJS-Hintergründe & Icons generieren lassen const cardRefs = createSectorCardPixi(globalSheet, sectorPixiContainer, posX, posY); cardLink.addEventListener('mouseenter', () => { cardRefs.frameSprite.alpha = 1.0; cardRefs.bgSprite.alpha = 0.8; cardRefs.iconDetails.tint = 0x00f0ff; cardRefs.iconDetails.scale.set(0.09); cardRefs.iconDetails.rotation = 0.2; cardRefs.iconPlayers.tint = 0xffffff; cardRefs.iconPlanets.tint = 0xffffff; }); cardLink.addEventListener('mouseleave', () => { cardRefs.frameSprite.alpha = 0.8; cardRefs.bgSprite.alpha = 0.6; cardRefs.iconDetails.tint = 0xaaaaaa; cardRefs.iconDetails.scale.set(0.08); cardRefs.iconDetails.rotation = 0; cardRefs.iconPlayers.tint = 0xaaaaaa; cardRefs.iconPlanets.tint = 0xaaaaaa; }); }); } async function checkAuthOnStartup() { const refreshToken = localStorage.getItem('void_refresh_token') || sessionStorage.getItem('void_refresh_token'); if (!refreshToken) { return } try { const result = await refreshAccessTokenUser(refreshToken); if (result.ok && result.data.accessToken) { sessionStorage.setItem('void_access_token', result.data.accessToken); if (result.data.user) sessionStorage.setItem('void_user', JSON.stringify(result.data.user)); transitionToLobby(); } else { sessionStorage.removeItem('void_access_token'); sessionStorage.removeItem('void_refresh_token'); localStorage.removeItem('void_refresh_token'); sessionStorage.removeItem('void_user'); } } catch (error) { console.error("Netzwerkfehler beim Auto-Login:", error); } } initDropdowns(() => { const userField = document.getElementById('username'); if (userField) userField.placeholder = formState.isLoginMode ? t('ph_username_login') : t('ph_username_reg'); const emailField = document.getElementById('email'); if (emailField) emailField.placeholder = t('ph_email'); const passField = document.getElementById('password'); if (passField) passField.placeholder = formState.isOtpMode || formState.isResetPasswordMode ? t('ph_otp') : t('ph_password'); }); const btnGenderMale = document.getElementById('btn-gender-male'); const btnGenderFemale = document.getElementById('btn-gender-female'); const btnSubmitOnboarding = document.getElementById('btn-submit-onboarding'); const onboardingForm = document.getElementById('onboarding-form'); const btnCancelOnboarding = document.getElementById('btn-cancel-onboarding'); if (btnCancelOnboarding) { btnCancelOnboarding.addEventListener('click', (e) => { e.preventDefault(); // 1. Sektor-Browser HTML wieder voll sichtbar machen const sectorBrowserLayer = document.getElementById('sector-browser-layer'); if (sectorBrowserLayer) { sectorBrowserLayer.style.opacity = '1.0'; sectorBrowserLayer.style.pointerEvents = 'auto'; // Klicks wieder erlauben } // 2. HTML-Layer des Modals ausblenden const onboardingHtmlLayer = document.getElementById('sector-onboarding-layer'); if (onboardingHtmlLayer) onboardingHtmlLayer.style.display = 'none'; // 3. PixiJS-Layer ausblenden if (onboardingPixiContainer) onboardingPixiContainer.visible = false; // 4. Formular zurücksetzen (damit alte Eingaben verschwinden) const onboardingForm = document.getElementById('onboarding-form'); if (onboardingForm) onboardingForm.reset(); // Optional: Hier auch noch die visuelle 'active' Klasse von deinen // Geschlechter-Buttons entfernen, falls nötig. }); } // --- Hilfsfunktion: Hover-Effekte synchronisieren --- // Genau wie beim Login übertragen wir den Mauszeiger vom unsichtbaren HTML auf PixiJS function syncHover(htmlElement, pixiRef, defaultTint, hoverTint = LOGIN_COLORS.TAB_HOVER) { if (!htmlElement || !pixiRef) return; htmlElement.addEventListener('mouseenter', () => { // Wenn der Button gerade "aktiv" ist (z.B. gewähltes Geschlecht), ignorieren wir den Hover if (!htmlElement.classList.contains('active')) { pixiRef.fill.tint = hoverTint; pixiRef.fill.alpha = 0.8; } }); htmlElement.addEventListener('mouseleave', () => { if (!htmlElement.classList.contains('active')) { pixiRef.fill.tint = defaultTint; pixiRef.fill.alpha = 0.6; // Zurück zur Standard-Transparenz } }); } // Hover-Effekte auf die Buttons anwenden (falls onboardingPixiRefs schon existiert) // Wir prüfen hier sicherheitshalber ab, da die Refs asynchron generiert werden const applyHoverEffects = setInterval(() => { if (onboardingPixiRefs) { clearInterval(applyHoverEffects); // Sobald geladen, Interval stoppen // Geschlechter-Buttons (Standard-Farbe ist Inactive, Hover ist Weiß) syncHover(btnGenderMale, onboardingPixiRefs.btnMale, LOGIN_COLORS.TAB_INACTIVE); syncHover(btnGenderFemale, onboardingPixiRefs.btnFemale, LOGIN_COLORS.TAB_INACTIVE); // Aktions-Buttons (Standard-Farbe ist Default-Grün) syncHover(btnCancelOnboarding, onboardingPixiRefs.btnCancel, LOGIN_COLORS.BTN_DEFAULT, LOGIN_COLORS.BTN_HOVER); syncHover(btnSubmitOnboarding, onboardingPixiRefs.btnJoin, LOGIN_COLORS.BTN_DEFAULT, LOGIN_COLORS.BTN_HOVER); } }, 100); // --- Geschlecht Umschalten (Toggle-Logik) --- if (btnGenderMale && btnGenderFemale) { btnGenderMale.addEventListener('click', (e) => { e.preventDefault(); selectedOnboardingGender = 'male'; // HTML Klassen updaten (für Text-Farbe) btnGenderMale.classList.add('active'); btnGenderFemale.classList.remove('active'); // PixiJS Farben updaten if (onboardingPixiRefs) { onboardingPixiRefs.btnMale.fill.tint = LOGIN_COLORS.TAB_ACTIVE; onboardingPixiRefs.btnMale.fill.alpha = 0.6; onboardingPixiRefs.btnFemale.fill.tint = LOGIN_COLORS.TAB_INACTIVE; onboardingPixiRefs.btnFemale.fill.alpha = 0.4; } }); btnGenderFemale.addEventListener('click', (e) => { e.preventDefault(); selectedOnboardingGender = 'female'; // HTML Klassen updaten btnGenderFemale.classList.add('active'); btnGenderMale.classList.remove('active'); // PixiJS Farben updaten if (onboardingPixiRefs) { onboardingPixiRefs.btnFemale.fill.tint = LOGIN_COLORS.TAB_ACTIVE; onboardingPixiRefs.btnFemale.fill.alpha = 0.6; onboardingPixiRefs.btnMale.fill.tint = LOGIN_COLORS.TAB_INACTIVE; onboardingPixiRefs.btnMale.fill.alpha = 0.4; } }); } // --- Formular Absenden (Beitreten) --- if (onboardingForm) { onboardingForm.addEventListener('submit', async (e) => { e.preventDefault(); // Verhindert das Neuladen der Seite if (!selectedSectorId) return; const localUsername = document.getElementById('local-username').value; const msgBox = document.getElementById('onboarding-msg-box'); msgBox.textContent = '...'; msgBox.style.color = 'var(--color-text-main)'; const token = sessionStorage.getItem('void_access_token') || localStorage.getItem('void_access_token'); try { const result = await joinSectorUser(token, selectedSectorId, localUsername, selectedOnboardingGender); if (!result.ok) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t(result.data.error) || t('ERR_INTERNAL_SERVER'); return; } msgBox.style.color = 'var(--color-green-bright)'; msgBox.textContent = t(result.data.message); setTimeout(() => { if (btnCancelOnboarding) btnCancelOnboarding.click(); loadAndRenderSectorBrowser(); }, 1500); } catch (error) { msgBox.style.color = 'var(--color-error)'; msgBox.textContent = t('ERR_INTERNAL_SERVER'); } }); } initGame();