Wetier am Cahstity game gebasterln
This commit is contained in:
70
xxxthegame/src/main/resources/static/js/card-defs.js
Normal file
70
xxxthegame/src/main/resources/static/js/card-defs.js
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Zentrale Kartendefinitionen für das Chastity Game.
|
||||
*
|
||||
* Exportiert (global):
|
||||
* CARD_DEFS – Array mit { id, img, name, desc, defMin, defMax }
|
||||
* CARD_LABELS – Object { ID: { name, img, desc } } (Lookup für card-display.js u.a.)
|
||||
*/
|
||||
const CARD_DEFS = [
|
||||
{
|
||||
id: 'RED',
|
||||
img: '/img/card_red.png',
|
||||
name: 'Rote Karte',
|
||||
desc: 'Niete - Viel Erfolg beim nächsten Zug',
|
||||
defMin: 5,
|
||||
defMax: 10,
|
||||
},
|
||||
{
|
||||
id: 'GREEN',
|
||||
img: '/img/card_green.png',
|
||||
name: 'Grüne Karte',
|
||||
desc: 'Öffnet das Lock. Kann wieder ins Deck zurück gelegt werden',
|
||||
defMin: 1,
|
||||
defMax: 2,
|
||||
},
|
||||
{
|
||||
id: 'YELLOW',
|
||||
img: '/img/card_yellow.png',
|
||||
name: 'Gelbe Karte',
|
||||
desc: 'Per Zufall werden rote Karten entfernt oder hinzugefügt',
|
||||
defMin: 1,
|
||||
defMax: 2,
|
||||
},
|
||||
{
|
||||
id: 'TASK',
|
||||
img: '/img/card_task.png',
|
||||
name: 'Aufgabe',
|
||||
desc: 'Keyholder*In, Community oder der Zufall teilt eine Aufgabe zu.',
|
||||
defMin: 0,
|
||||
defMax: 0,
|
||||
},
|
||||
{
|
||||
id: 'FREEZE',
|
||||
img: '/img/card_freeze.png',
|
||||
name: 'Freeze',
|
||||
desc: 'Friert das Lock für eine festgelegte Zeit ein – in diesem Zeitraum können keine Karten gezogen werden.',
|
||||
defMin: 0,
|
||||
defMax: 0,
|
||||
},
|
||||
{
|
||||
id: 'RESET',
|
||||
img: '/img/card_reset.png',
|
||||
name: 'Reset',
|
||||
desc: 'Setzt das Kartendeck auf den Ausgangszustand zurück. Alle bisher gezogenen Karten kommen wieder rein.',
|
||||
defMin: 0,
|
||||
defMax: 0,
|
||||
},
|
||||
{
|
||||
id: 'DOUBLE_UP',
|
||||
img: '/img/card_doubleup.png',
|
||||
name: 'Double Up',
|
||||
desc: 'Verdoppelt alle noch im Deck vorhandenen Karten.',
|
||||
defMin: 0,
|
||||
defMax: 0,
|
||||
},
|
||||
];
|
||||
|
||||
/** Lookup-Objekt für Konsumenten, die nach ID auf Name/Bild/Beschreibung zugreifen. */
|
||||
const CARD_LABELS = Object.fromEntries(
|
||||
CARD_DEFS.map(c => [c.id, { name: c.name, img: c.img, desc: c.desc }])
|
||||
);
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Gemeinsame Kartenanzeige für Chastity Game.
|
||||
* Exportiert: CARD_LABELS, cardTypeGridHtml(cardCounts)
|
||||
* Benötigt: /js/card-defs.js (CARD_LABELS muss bereits global verfügbar sein)
|
||||
* Exportiert: cardTypeGridHtml(cardCounts)
|
||||
*/
|
||||
(function () {
|
||||
const style = document.createElement('style');
|
||||
@@ -35,16 +36,6 @@
|
||||
document.head.appendChild(style);
|
||||
})();
|
||||
|
||||
const CARD_LABELS = {
|
||||
RED: { name: 'Rote Karte', img: '/img/card_red.png', desc: 'Verlängert die Sperrzeit. Je nach Konfiguration werden Minuten oder Stunden auf den Timer addiert.' },
|
||||
GREEN: { name: 'Grüne Karte', img: '/img/card_green.png', desc: 'Verkürzt die Sperrzeit. Eine grüne Karte bringt dich dem Öffnen näher.' },
|
||||
YELLOW: { name: 'Gelbe Karte', img: '/img/card_yellow.png', desc: 'Neutrales Ereignis – keine Zeitveränderung, aber es passiert trotzdem etwas.' },
|
||||
TASK: { name: 'Aufgabe', img: '/img/card_task.png', desc: 'Teilt dir eine zufällige Aufgabe aus der Aufgabenliste zu. Die Aufgabe muss erfüllt werden.' },
|
||||
FREEZE: { name: 'Freeze', img: '/img/card_freeze.png', desc: 'Friert das Lock für eine festgelegte Zeit ein – in diesem Zeitraum können keine Karten gezogen werden.' },
|
||||
RESET: { name: 'Reset', img: '/img/card_reset.png', desc: 'Setzt das Kartendeck auf den Ausgangszustand zurück. Alle bisher gezogenen Karten kommen wieder rein.' },
|
||||
DOUBLE_UP: { name: 'Double Up', img: '/img/card_doubleup.png', desc: 'Verdoppelt alle Karten im aktuellen Deck.' },
|
||||
};
|
||||
|
||||
/**
|
||||
* Gibt HTML für ein Karten-Typ-Raster zurück (ein Bild pro Typ, Anzahl-Badge).
|
||||
* @param {Object} cardCounts – { RED: 3, GREEN: 1, … }
|
||||
|
||||
@@ -27,11 +27,12 @@
|
||||
icon: '⊗',
|
||||
items: [
|
||||
{ href: '/infochastity.html', icon: 'ℹ', label: 'Info' },
|
||||
{ href: '/sessionchastity.html', icon: '▷', label: 'Neues Lock', id: 'navChastityNeu' },
|
||||
{ href: '/neulock.html', icon: '▷', label: 'Neues Lock', id: 'navChastityNeu' },
|
||||
{ href: '#', icon: '▶', label: 'Aktives Lock', id: 'navChastityAktiv' },
|
||||
{ href: '/communityvotes.html', icon: '🗳️', label: 'Community Votes' },
|
||||
{ href: '/meine-locks.html', icon: '🔒', label: 'Meine Locks' },
|
||||
{ href: '/keyholder.html', icon: '🔑', label: 'Keyholder' },
|
||||
{ href: '/unlock-history.html', icon: '🗝️', label: 'Code-Historie' },
|
||||
]
|
||||
},
|
||||
];
|
||||
@@ -125,7 +126,7 @@
|
||||
const lockId = lockData.lockId;
|
||||
if (navCAktiv) {
|
||||
navCAktiv.style.display = '';
|
||||
navCAktiv.querySelector('a').href = '/sessionchastityingame.html?lockId=' + lockId;
|
||||
navCAktiv.querySelector('a').href = '/activelock.html?lockId=' + lockId;
|
||||
}
|
||||
}
|
||||
} catch (_) { /* Menü bleibt im Standardzustand */ }
|
||||
|
||||
@@ -5,12 +5,13 @@
|
||||
const path = window.location.pathname;
|
||||
|
||||
const links = [
|
||||
{ href: '/feed.html', icon: '📰', label: 'Feed', badgeId: null, mobileBadgeId: null },
|
||||
{ href: '/personen-suchen.html', icon: '⊕', label: 'Personen suchen', badgeId: null, mobileBadgeId: null },
|
||||
{ href: '/freunde.html', icon: '♡', label: 'Freunde', badgeId: 'socialFriendsBadge', mobileBadgeId: 'socialMobileFriendsBadge' },
|
||||
{ href: '/nachrichten.html', icon: '✉', label: 'Nachrichten', badgeId: 'socialMsgBadge', mobileBadgeId: 'socialMobileMsgBadge' },
|
||||
{ href: '/gruppen.html', icon: '👥', label: 'Gruppen', badgeId: 'socialGruppenBadge', mobileBadgeId: 'socialMobileGruppenBadge' },
|
||||
{ href: '/einladungen.html', icon: '✉', label: 'Einladungen', badgeId: 'socialInvBadge', mobileBadgeId: 'socialMobileInvBadge' },
|
||||
{ href: '/feed.html', icon: '📰', label: 'Feed', badgeId: null, mobileBadgeId: null },
|
||||
{ href: '/personen-suchen.html', icon: '⊕', label: 'Personen suchen', badgeId: null, mobileBadgeId: null },
|
||||
{ href: '/freunde.html', icon: '♡', label: 'Freunde', badgeId: 'socialFriendsBadge', mobileBadgeId: 'socialMobileFriendsBadge' },
|
||||
{ href: '/nachrichten.html', icon: '✉', label: 'Nachrichten', badgeId: 'socialMsgBadge', mobileBadgeId: 'socialMobileMsgBadge' },
|
||||
{ href: '/benachrichtigungen.html', icon: '🔔', label: 'Benachrichtigungen', badgeId: 'socialNotifBadge', mobileBadgeId: 'socialMobileNotifBadge' },
|
||||
{ href: '/gruppen.html', icon: '👥', label: 'Gruppen', badgeId: 'socialGruppenBadge', mobileBadgeId: 'socialMobileGruppenBadge' },
|
||||
{ href: '/einladungen.html', icon: '✉', label: 'Einladungen', badgeId: 'socialInvBadge', mobileBadgeId: 'socialMobileInvBadge' },
|
||||
];
|
||||
|
||||
const profileActive = (path === '/benutzer.html' || path === '/profile.html') ? ' class="active"' : '';
|
||||
@@ -102,6 +103,23 @@
|
||||
});
|
||||
}
|
||||
|
||||
// ── Ton abspielen ──
|
||||
// Browser erlauben audio.play() sobald der Nutzer mindestens einmal interagiert hat.
|
||||
let userHasInteracted = false;
|
||||
document.addEventListener('click', () => { userHasInteracted = true; }, { passive: true });
|
||||
document.addEventListener('keydown', () => { userHasInteracted = true; }, { passive: true });
|
||||
document.addEventListener('touchstart', () => { userHasInteracted = true; }, { passive: true });
|
||||
|
||||
function playSound(src) {
|
||||
if (!userHasInteracted) return;
|
||||
try {
|
||||
const audio = new Audio(src);
|
||||
audio.volume = 0.6;
|
||||
audio.play().catch(() => {});
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// ── Initiale Badge-Counts laden ──
|
||||
fetch('/social/friends/pending/count')
|
||||
.then(r => r.ok ? r.json() : 0)
|
||||
.then(n => setBadge(['socialFriendsBadge', 'socialMobileFriendsBadge'], n))
|
||||
@@ -112,6 +130,11 @@
|
||||
.then(n => setBadge(['socialMsgBadge', 'socialMobileMsgBadge'], n))
|
||||
.catch(() => {});
|
||||
|
||||
fetch('/notifications/unread/count')
|
||||
.then(r => r.ok ? r.json() : 0)
|
||||
.then(n => setBadge(['socialNotifBadge', 'socialMobileNotifBadge'], n))
|
||||
.catch(() => {});
|
||||
|
||||
Promise.all([
|
||||
fetch('/gruppen/requests/pending/count').then(r => r.ok ? r.json() : 0).catch(() => 0),
|
||||
fetch('/gruppen/reports/pending/count').then(r => r.ok ? r.json() : 0).catch(() => 0)
|
||||
@@ -124,4 +147,41 @@
|
||||
]).then(([khInvs, lockeeInvs]) =>
|
||||
setBadge(['socialInvBadge', 'socialMobileInvBadge'], khInvs.length + lockeeInvs.length)
|
||||
).catch(() => {});
|
||||
|
||||
// ── SSE: Echtzeit-Push vom Server ──
|
||||
function connectSse() {
|
||||
const es = new EventSource('/events/stream');
|
||||
|
||||
es.addEventListener('DM', e => {
|
||||
try {
|
||||
const data = JSON.parse(e.data);
|
||||
setBadge(['socialMsgBadge', 'socialMobileMsgBadge'], data.unreadCount || 0);
|
||||
// Nur Ton abspielen wenn nicht gerade auf der Nachrichten-Seite
|
||||
if (window.location.pathname !== '/nachrichten.html') {
|
||||
playSound('/audio/message.mp3');
|
||||
}
|
||||
// Nachrichten-Seite: sofortiges Laden neuer Nachrichten auslösen
|
||||
if (typeof window.__sseOnDm === 'function') window.__sseOnDm(data);
|
||||
} catch(ex) {}
|
||||
});
|
||||
|
||||
es.addEventListener('NOTIFICATION', e => {
|
||||
try {
|
||||
const data = JSON.parse(e.data);
|
||||
setBadge(['socialNotifBadge', 'socialMobileNotifBadge'], data.unreadCount || 0);
|
||||
if (window.location.pathname !== '/benachrichtigungen.html') {
|
||||
playSound('/audio/notification.mp3');
|
||||
}
|
||||
if (typeof window.__sseOnNotification === 'function') window.__sseOnNotification(data);
|
||||
} catch(ex) {}
|
||||
});
|
||||
|
||||
es.onerror = () => {
|
||||
es.close();
|
||||
// Nach 5 Sekunden neu verbinden
|
||||
setTimeout(connectSse, 5000);
|
||||
};
|
||||
}
|
||||
|
||||
connectSse();
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user