Improve Challenge-Logik... aber noch nicht fertig
This commit is contained in:
parent
c060590a4a
commit
be451f36ce
@ -135,9 +135,9 @@
|
||||
<script src="assets/src/service/challenge-service.js"></script>
|
||||
<script src="js/login.js"></script>
|
||||
<script src="js/leaderboard.js"></script>
|
||||
<script src="js/messages.js"></script>
|
||||
<script src="js/messages.js?v=challenge-flow-20260525"></script>
|
||||
<!--Navigation Script -->
|
||||
<script src="js/play.js"></script>
|
||||
<script src="js/navigation.js"></script>
|
||||
<script src="js/play.js?v=challenge-flow-20260525"></script>
|
||||
<script src="js/navigation.js?v=challenge-flow-20260525"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
189
js/messages.js
189
js/messages.js
@ -3,6 +3,7 @@
|
||||
const MESSAGE_TYPE_CHALLENGE_RESULT = "challenge-result";
|
||||
const MESSAGE_POLL_INTERVAL_MS = 30000;
|
||||
const ACTIVE_CHALLENGE_STORAGE_KEY = "loremIpsumActiveChallenge";
|
||||
const CHALLENGE_DATA_PREFIX = "[[loremIpsumChallenge:";
|
||||
|
||||
let currentMessages = [];
|
||||
let currentUsers = [];
|
||||
@ -50,18 +51,159 @@
|
||||
}
|
||||
|
||||
function normalizeMessage(message) {
|
||||
const embeddedChallenge = extractEmbeddedChallenge(message.text ?? "");
|
||||
const type = message.type ?? MESSAGE_TYPE_CHALLENGE;
|
||||
const challenge = message.challenge
|
||||
?? message.result
|
||||
?? embeddedChallenge.challenge
|
||||
?? (type === MESSAGE_TYPE_CHALLENGE || type === MESSAGE_TYPE_CHALLENGE_RESULT ? message : null);
|
||||
|
||||
return {
|
||||
id: message.id,
|
||||
sender: message.sender ?? message.from ?? "",
|
||||
recipient: message.recipient ?? message.to ?? "",
|
||||
type: message.type ?? MESSAGE_TYPE_CHALLENGE,
|
||||
text: message.text ?? "",
|
||||
type: type,
|
||||
text: embeddedChallenge.text,
|
||||
read: Boolean(message.read),
|
||||
createdAt: message.createdAt ?? message.time ?? message.date ?? "",
|
||||
challenge: message.challenge ?? message.result ?? null,
|
||||
challenge: challenge,
|
||||
};
|
||||
}
|
||||
|
||||
function extractEmbeddedChallenge(text) {
|
||||
const rawText = String(text ?? "");
|
||||
if (!rawText.startsWith(CHALLENGE_DATA_PREFIX)) {
|
||||
return {
|
||||
text: rawText,
|
||||
challenge: null,
|
||||
};
|
||||
}
|
||||
|
||||
const endIndex = rawText.indexOf("]]");
|
||||
if (endIndex === -1) {
|
||||
return {
|
||||
text: rawText,
|
||||
challenge: null,
|
||||
};
|
||||
}
|
||||
|
||||
const json = rawText.slice(CHALLENGE_DATA_PREFIX.length, endIndex);
|
||||
const displayText = rawText.slice(endIndex + 2).trim();
|
||||
|
||||
try {
|
||||
return {
|
||||
text: displayText,
|
||||
challenge: JSON.parse(json),
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
text: rawText,
|
||||
challenge: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function getChallengeId(challenge) {
|
||||
return challenge?.challengeId ?? challenge?.challenge_id ?? challenge?.id ?? null;
|
||||
}
|
||||
|
||||
function getChallengeChallenger(challenge, fallbackName) {
|
||||
return challenge?.challenger
|
||||
?? challenge?.challengerName
|
||||
?? challenge?.sender
|
||||
?? challenge?.from
|
||||
?? fallbackName
|
||||
?? "";
|
||||
}
|
||||
|
||||
function getChallengeOpponent(challenge, fallbackName) {
|
||||
return challenge?.opponent
|
||||
?? challenge?.opponentName
|
||||
?? challenge?.challengedUser
|
||||
?? challenge?.recipient
|
||||
?? challenge?.to
|
||||
?? fallbackName
|
||||
?? "";
|
||||
}
|
||||
|
||||
function getOpponentScore(challenge) {
|
||||
return challenge?.opponentScore
|
||||
?? challenge?.challengedScore
|
||||
?? challenge?.challengedUserScore
|
||||
?? null;
|
||||
}
|
||||
|
||||
function hasScore(value) {
|
||||
return value !== null && value !== undefined && value !== "";
|
||||
}
|
||||
|
||||
function getChallengeRole(message) {
|
||||
const auth = getAuth();
|
||||
const challenge = message.challenge;
|
||||
if (!auth || !challenge || getChallengeId(challenge) === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const ownName = normalizeUsername(auth.username);
|
||||
const challenger = normalizeUsername(getChallengeChallenger(challenge, message.sender));
|
||||
const opponent = normalizeUsername(getChallengeOpponent(challenge, message.recipient));
|
||||
|
||||
if (ownName === opponent) {
|
||||
return "opponent";
|
||||
}
|
||||
|
||||
if (ownName === challenger) {
|
||||
return "challenger";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function canOpponentAcceptChallenge(message) {
|
||||
if (message.type !== MESSAGE_TYPE_CHALLENGE || !message.challenge) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const role = getChallengeRole(message);
|
||||
const challenge = message.challenge;
|
||||
const opponentScore = getOpponentScore(challenge);
|
||||
|
||||
return role === "opponent" && !hasScore(opponentScore) && !hasScore(challenge.challengerScore);
|
||||
}
|
||||
|
||||
function canChallengerPlayChallenge(message) {
|
||||
const role = getChallengeRole(message);
|
||||
const challenge = message.challenge;
|
||||
|
||||
return role === "challenger"
|
||||
&& hasScore(getOpponentScore(challenge))
|
||||
&& !hasScore(challenge.challengerScore);
|
||||
}
|
||||
|
||||
function startChallenge(message, role) {
|
||||
const challenge = message.challenge;
|
||||
const challenger = getChallengeChallenger(challenge, message.sender);
|
||||
const opponent = getChallengeOpponent(challenge, message.recipient);
|
||||
const auth = getAuth();
|
||||
const otherUser = role === "opponent" ? challenger : opponent;
|
||||
|
||||
sessionStorage.setItem(
|
||||
ACTIVE_CHALLENGE_STORAGE_KEY,
|
||||
JSON.stringify({
|
||||
id: getChallengeId(challenge),
|
||||
role: role,
|
||||
challenger: challenger,
|
||||
opponent: otherUser,
|
||||
opponentScore: role === "challenger" ? getOpponentScore(challenge) : null,
|
||||
ownUsername: auth?.username ?? "",
|
||||
}),
|
||||
);
|
||||
|
||||
if (typeof window.loadPage === "function") {
|
||||
window.loadPage("play", "nav-play");
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeUser(user) {
|
||||
if (typeof user === "string") {
|
||||
return user;
|
||||
@ -218,6 +360,24 @@
|
||||
item.appendChild(createChallengeResultGraphic(message.challenge));
|
||||
}
|
||||
|
||||
if (canOpponentAcceptChallenge(message)) {
|
||||
const acceptButton = document.createElement("button");
|
||||
acceptButton.type = "button";
|
||||
acceptButton.className = "btn btn-sm mt-3";
|
||||
acceptButton.textContent = "Challenge annehmen";
|
||||
acceptButton.addEventListener("click", () => startChallenge(message, "opponent"));
|
||||
item.appendChild(acceptButton);
|
||||
}
|
||||
|
||||
if (canChallengerPlayChallenge(message)) {
|
||||
const playButton = document.createElement("button");
|
||||
playButton.type = "button";
|
||||
playButton.className = "btn btn-sm mt-3";
|
||||
playButton.textContent = "Challenge spielen";
|
||||
playButton.addEventListener("click", () => startChallenge(message, "challenger"));
|
||||
item.appendChild(playButton);
|
||||
}
|
||||
|
||||
messageList.appendChild(item);
|
||||
});
|
||||
}
|
||||
@ -343,26 +503,11 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const challenge = result.body || {};
|
||||
sessionStorage.setItem(
|
||||
ACTIVE_CHALLENGE_STORAGE_KEY,
|
||||
JSON.stringify({
|
||||
id: challenge.id,
|
||||
challenger: challenge.challenger || auth.username,
|
||||
opponent: challenge.opponent || recipient,
|
||||
opponentScore: challenge.opponentScore ?? null,
|
||||
}),
|
||||
sessionStorage.removeItem(ACTIVE_CHALLENGE_STORAGE_KEY);
|
||||
setFeedback(
|
||||
"Challenge an " + recipient + " wurde gesendet. Der Gegner spielt zuerst; danach bekommst du sein Resultat.",
|
||||
"success",
|
||||
);
|
||||
|
||||
const scoreText = challenge.opponentScore !== undefined && challenge.opponentScore !== null
|
||||
? " Gegner-Score: " + challenge.opponentScore + "."
|
||||
: "";
|
||||
setFeedback("Challenge an " + recipient + " wurde erstellt." + scoreText + " Du wirst zum Spiel weitergeleitet.", "success");
|
||||
window.setTimeout(() => {
|
||||
if (typeof window.loadPage === "function") {
|
||||
window.loadPage("play", "nav-play");
|
||||
}
|
||||
}, 900);
|
||||
await loadMessages({ showFeedback: false });
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
if (activeLink) activeLink.classList.add("active");
|
||||
}
|
||||
window.loadPage = function loadPage(page, menuId) {
|
||||
fetch("pages/" + page + ".html")
|
||||
fetch("pages/" + page + ".html", { cache: "no-store" })
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP " + response.status);
|
||||
|
||||
109
js/play.js
109
js/play.js
@ -2,6 +2,7 @@
|
||||
// --- Konfiguration ---
|
||||
const MEMORIZE_TIME_SECONDS = 15;
|
||||
const ACTIVE_CHALLENGE_STORAGE_KEY = "loremIpsumActiveChallenge";
|
||||
const CHALLENGE_DATA_PREFIX = "[[loremIpsumChallenge:";
|
||||
|
||||
// Bausteine fuer den zufaelligen Rundentext. Alles bleibt lokal, damit das Spiel ohne Backend starten kann.
|
||||
const TEXT_PARTS = {
|
||||
@ -261,6 +262,14 @@
|
||||
return new window.ChallengeService(window.config);
|
||||
}
|
||||
|
||||
function getMessageService() {
|
||||
if (!window.config || !window.MessageService) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new window.MessageService(window.config);
|
||||
}
|
||||
|
||||
function readActiveChallenge() {
|
||||
const raw = sessionStorage.getItem(ACTIVE_CHALLENGE_STORAGE_KEY);
|
||||
if (!raw) {
|
||||
@ -269,7 +278,7 @@
|
||||
|
||||
try {
|
||||
const challenge = JSON.parse(raw);
|
||||
if (!challenge || !challenge.id || !challenge.opponent) {
|
||||
if (!challenge || challenge.id === undefined || challenge.id === null || !challenge.opponent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -279,6 +288,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
function hasActiveChallenge() {
|
||||
return Boolean(activeChallenge && activeChallenge.id !== undefined && activeChallenge.id !== null);
|
||||
}
|
||||
|
||||
function isChallengeSecondRound() {
|
||||
return hasActiveChallenge()
|
||||
&& activeChallenge.role === "challenger"
|
||||
&& activeChallenge.opponentScore !== null
|
||||
&& activeChallenge.opponentScore !== undefined;
|
||||
}
|
||||
|
||||
function isChallengeFirstRound() {
|
||||
return hasActiveChallenge() && activeChallenge.role === "opponent";
|
||||
}
|
||||
|
||||
function showScoreSaveFeedback(message, type) {
|
||||
if (!scoreSaveFeedback) return;
|
||||
|
||||
@ -345,7 +369,7 @@
|
||||
}
|
||||
|
||||
function renderChallengeResult(score) {
|
||||
if (!scoreSaveFeedback || !activeChallenge) {
|
||||
if (!scoreSaveFeedback || !isChallengeSecondRound()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -398,7 +422,7 @@
|
||||
|
||||
async function completeChallenge(scoreData) {
|
||||
const auth = getAuth();
|
||||
if (!auth || !activeChallenge) {
|
||||
if (!auth || !hasActiveChallenge()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -423,18 +447,77 @@
|
||||
|
||||
if (!result.ok) {
|
||||
showScoreSaveFeedback(
|
||||
"Score gespeichert, aber die Challenge konnte nicht abgeschlossen werden (Status " + result.status + ").",
|
||||
"warning",
|
||||
"Challenge konnte nicht abgeschlossen werden (Status " + result.status + ").",
|
||||
"danger",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStorage.removeItem(ACTIVE_CHALLENGE_STORAGE_KEY);
|
||||
activeChallenge = null;
|
||||
showScoreSaveFeedback(
|
||||
"Challenge abgeschlossen. Beide User erhalten eine Ergebnisnachricht.",
|
||||
"success",
|
||||
);
|
||||
|
||||
if (typeof window.updateMessagesNavState === "function") {
|
||||
window.updateMessagesNavState();
|
||||
}
|
||||
}
|
||||
|
||||
async function finishFirstChallengeRound(scoreData) {
|
||||
await saveScore(scoreData);
|
||||
await notifyChallenger(scoreData);
|
||||
|
||||
sessionStorage.removeItem(ACTIVE_CHALLENGE_STORAGE_KEY);
|
||||
activeChallenge = null;
|
||||
showScoreSaveFeedback("Resultat wurde an den Herausforderer gesendet.", "success");
|
||||
|
||||
if (typeof window.updateMessagesNavState === "function") {
|
||||
window.updateMessagesNavState();
|
||||
}
|
||||
}
|
||||
|
||||
async function notifyChallenger(scoreData) {
|
||||
const auth = getAuth();
|
||||
const messageService = getMessageService();
|
||||
if (!auth || !messageService || !activeChallenge.challenger) {
|
||||
return;
|
||||
}
|
||||
|
||||
const challengeData = {
|
||||
id: activeChallenge.id,
|
||||
challenger: activeChallenge.challenger,
|
||||
opponent: auth.username,
|
||||
opponentScore: scoreData.score,
|
||||
};
|
||||
|
||||
const messageText =
|
||||
CHALLENGE_DATA_PREFIX +
|
||||
JSON.stringify(challengeData) +
|
||||
"]]" +
|
||||
"\n" +
|
||||
auth.username +
|
||||
" hat gespielt und " +
|
||||
scoreData.score +
|
||||
" Punkte erreicht. Jetzt bist du dran.";
|
||||
|
||||
const result = await messageService.postMessage(
|
||||
auth.username,
|
||||
auth.password,
|
||||
activeChallenge.challenger,
|
||||
"challenge",
|
||||
messageText,
|
||||
);
|
||||
|
||||
if (!result.ok) {
|
||||
showScoreSaveFeedback(
|
||||
"Challenge wurde gespeichert, aber die Nachricht an den Herausforderer konnte nicht gesendet werden.",
|
||||
"warning",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function submitScore() {
|
||||
if (!userTextInput) return;
|
||||
|
||||
@ -477,8 +560,15 @@
|
||||
console.log("Score bereit zum Senden:", scoreData);
|
||||
|
||||
try {
|
||||
await saveScore(scoreData);
|
||||
await completeChallenge(scoreData);
|
||||
if (isChallengeFirstRound()) {
|
||||
showScoreSaveFeedback("Resultat wird an den Herausforderer gesendet...", "info");
|
||||
await finishFirstChallengeRound(scoreData);
|
||||
} else if (hasActiveChallenge()) {
|
||||
showScoreSaveFeedback("Challenge-Resultat wird gesendet...", "info");
|
||||
await completeChallenge(scoreData);
|
||||
} else {
|
||||
await saveScore(scoreData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Speichern des Scores:", error);
|
||||
showScoreSaveFeedback(
|
||||
@ -522,7 +612,10 @@
|
||||
const opponentScore = activeChallenge.opponentScore !== null && activeChallenge.opponentScore !== undefined
|
||||
? " Score: " + activeChallenge.opponentScore + "."
|
||||
: "";
|
||||
challengeHint.textContent = "Challenge gegen " + activeChallenge.opponent + "." + opponentScore;
|
||||
const hintPrefix = activeChallenge.role === "opponent"
|
||||
? "Du spielst zuerst gegen "
|
||||
: "Finale Runde gegen ";
|
||||
challengeHint.textContent = hintPrefix + activeChallenge.opponent + "." + opponentScore;
|
||||
challengeHint.classList.remove("d-none");
|
||||
}
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
<select id="challenge-recipient" class="form-select mb-3"></select>
|
||||
|
||||
<label for="challenge-text" class="form-label">Nachricht</label>
|
||||
<textarea id="challenge-text" class="form-control mb-3" rows="3">Ich fordere dich zu einer Lorem-Ipsum-Challenge heraus!</textarea>
|
||||
<textarea id="challenge-text" class="form-control mb-3" rows="3">Kannst du mich schlagen? Spiel eine Runde, dann bin ich dran.</textarea>
|
||||
|
||||
<button class="btn" type="submit">Challenge senden</button>
|
||||
</form>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user