Änderungen: - Integration des Taxi-Minispiels mit neuen Routen und Komponenten im Backend und Frontend. - Erstellung von Modellen und Datenbank-Schemas für das Taxi-Spiel, einschließlich TaxiGameState, TaxiLevelStats und TaxiMap. - Erweiterung der Navigationsstruktur und der Benutzeroberfläche, um das Taxi-Spiel und die zugehörigen Tools zu unterstützen. - Aktualisierung der Übersetzungen für das Taxi-Minispiel in Deutsch und Englisch. Diese Anpassungen erweitern die Funktionalität der Anwendung um ein neues Minispiel und verbessern die Benutzererfahrung durch neue Features und Inhalte.
408 lines
11 KiB
JavaScript
408 lines
11 KiB
JavaScript
import BaseService from './BaseService.js';
|
|
import TaxiGameState from '../models/taxi/taxiGameState.js';
|
|
import TaxiLevelStats from '../models/taxi/taxiLevelStats.js';
|
|
import User from '../models/community/user.js';
|
|
|
|
class TaxiService extends BaseService {
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
// Hilfsmethode: Konvertiere hashedId zu userId
|
|
async getUserIdFromHashedId(hashedUserId) {
|
|
const user = await User.findOne({ where: { hashedId: hashedUserId } });
|
|
if (!user) {
|
|
throw new Error('User not found');
|
|
}
|
|
return user.id;
|
|
}
|
|
|
|
// Spielstand abrufen
|
|
async getGameState(hashedUserId) {
|
|
try {
|
|
const userId = await this.getUserIdFromHashedId(hashedUserId);
|
|
|
|
let gameState = await TaxiGameState.findOne({
|
|
where: { userId }
|
|
});
|
|
|
|
if (!gameState) {
|
|
// Erstelle neuen Spielstand
|
|
gameState = await TaxiGameState.create({
|
|
userId,
|
|
currentLevel: 1,
|
|
totalScore: 0,
|
|
totalMoney: 0,
|
|
totalPassengersDelivered: 0,
|
|
unlockedLevels: [1],
|
|
achievements: []
|
|
});
|
|
}
|
|
|
|
return {
|
|
currentLevel: gameState.currentLevel,
|
|
totalScore: gameState.totalScore,
|
|
totalMoney: gameState.totalMoney,
|
|
totalPassengersDelivered: gameState.totalPassengersDelivered,
|
|
unlockedLevels: gameState.unlockedLevels,
|
|
achievements: gameState.achievements
|
|
};
|
|
} catch (error) {
|
|
console.error('Error getting taxi game state:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Spielstand speichern
|
|
async saveGameState(hashedUserId, gameData) {
|
|
try {
|
|
const userId = await this.getUserIdFromHashedId(hashedUserId);
|
|
const { level, score, money, passengersDelivered, fuel } = gameData;
|
|
|
|
const [gameState, created] = await TaxiGameState.findOrCreate({
|
|
where: { userId },
|
|
defaults: {
|
|
userId,
|
|
currentLevel: level || 1,
|
|
totalScore: score || 0,
|
|
totalMoney: money || 0,
|
|
totalPassengersDelivered: passengersDelivered || 0,
|
|
unlockedLevels: [1],
|
|
achievements: []
|
|
}
|
|
});
|
|
|
|
if (!created) {
|
|
// Aktualisiere bestehenden Spielstand
|
|
await gameState.update({
|
|
currentLevel: Math.max(gameState.currentLevel, level || 1),
|
|
totalScore: Math.max(gameState.totalScore, score || 0),
|
|
totalMoney: Math.max(gameState.totalMoney, money || 0),
|
|
totalPassengersDelivered: Math.max(gameState.totalPassengersDelivered, passengersDelivered || 0)
|
|
});
|
|
}
|
|
|
|
return {
|
|
currentLevel: gameState.currentLevel,
|
|
totalScore: gameState.totalScore,
|
|
totalMoney: gameState.totalMoney,
|
|
totalPassengersDelivered: gameState.totalPassengersDelivered,
|
|
unlockedLevels: gameState.unlockedLevels,
|
|
achievements: gameState.achievements
|
|
};
|
|
} catch (error) {
|
|
console.error('Error saving taxi game state:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Level-Statistiken abrufen
|
|
async getLevelStats(hashedUserId, level) {
|
|
try {
|
|
const userId = await this.getUserIdFromHashedId(hashedUserId);
|
|
const stats = await TaxiLevelStats.findOne({
|
|
where: { userId, level }
|
|
});
|
|
|
|
if (!stats) {
|
|
return {
|
|
level,
|
|
bestScore: 0,
|
|
bestMoney: 0,
|
|
bestPassengersDelivered: 0,
|
|
timesPlayed: 0,
|
|
completed: false
|
|
};
|
|
}
|
|
|
|
return {
|
|
level: stats.level,
|
|
bestScore: stats.bestScore,
|
|
bestMoney: stats.bestMoney,
|
|
bestPassengersDelivered: stats.bestPassengersDelivered,
|
|
timesPlayed: stats.timesPlayed,
|
|
completed: stats.completed
|
|
};
|
|
} catch (error) {
|
|
console.error('Error getting level stats:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Bestenliste abrufen
|
|
async getLeaderboard(type = 'score', limit = 10) {
|
|
try {
|
|
let orderBy;
|
|
switch (type) {
|
|
case 'money':
|
|
orderBy = [['totalMoney', 'DESC']];
|
|
break;
|
|
case 'passengers':
|
|
orderBy = [['totalPassengersDelivered', 'DESC']];
|
|
break;
|
|
case 'level':
|
|
orderBy = [['currentLevel', 'DESC']];
|
|
break;
|
|
default:
|
|
orderBy = [['totalScore', 'DESC']];
|
|
}
|
|
|
|
const leaderboard = await TaxiGameState.findAll({
|
|
order: orderBy,
|
|
limit: parseInt(limit),
|
|
include: [{
|
|
model: User,
|
|
attributes: ['username', 'id']
|
|
}]
|
|
});
|
|
|
|
return leaderboard.map((entry, index) => ({
|
|
rank: index + 1,
|
|
username: entry.User.username,
|
|
userId: entry.User.id,
|
|
score: entry.totalScore,
|
|
money: entry.totalMoney,
|
|
passengers: entry.totalPassengersDelivered,
|
|
level: entry.currentLevel
|
|
}));
|
|
} catch (error) {
|
|
console.error('Error getting leaderboard:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Spiel beenden und Punkte verarbeiten
|
|
async finishGame(hashedUserId, gameData) {
|
|
try {
|
|
const userId = await this.getUserIdFromHashedId(hashedUserId);
|
|
const { finalScore, finalMoney, passengersDelivered, level } = gameData;
|
|
|
|
// Aktualisiere Spielstand
|
|
const gameState = await this.saveGameState(userId, {
|
|
level,
|
|
score: finalScore,
|
|
money: finalMoney,
|
|
passengersDelivered
|
|
});
|
|
|
|
// Aktualisiere Level-Statistiken
|
|
await this.updateLevelStats(hashedUserId, level, {
|
|
score: finalScore,
|
|
money: finalMoney,
|
|
passengersDelivered
|
|
});
|
|
|
|
// Prüfe auf neue freigeschaltete Level
|
|
const newUnlockedLevels = await this.checkUnlockedLevels(hashedUserId, level);
|
|
|
|
// Prüfe auf neue Erfolge
|
|
const newAchievements = await this.checkAchievements(hashedUserId, gameState);
|
|
|
|
return {
|
|
gameState,
|
|
newUnlockedLevels,
|
|
newAchievements
|
|
};
|
|
} catch (error) {
|
|
console.error('Error finishing game:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Level freischalten
|
|
async unlockLevel(hashedUserId, level) {
|
|
try {
|
|
const userId = await this.getUserIdFromHashedId(hashedUserId);
|
|
const gameState = await TaxiGameState.findOne({
|
|
where: { userId }
|
|
});
|
|
|
|
if (!gameState) {
|
|
throw new Error('Spielstand nicht gefunden');
|
|
}
|
|
|
|
const unlockedLevels = [...gameState.unlockedLevels];
|
|
if (!unlockedLevels.includes(level)) {
|
|
unlockedLevels.push(level);
|
|
unlockedLevels.sort((a, b) => a - b);
|
|
|
|
await gameState.update({
|
|
unlockedLevels
|
|
});
|
|
}
|
|
|
|
return { unlockedLevels };
|
|
} catch (error) {
|
|
console.error('Error unlocking level:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Spieler-Statistiken abrufen
|
|
async getPlayerStats(hashedUserId) {
|
|
try {
|
|
const userId = await this.getUserIdFromHashedId(hashedUserId);
|
|
const gameState = await this.getGameState(hashedUserId);
|
|
const levelStats = await TaxiLevelStats.findAll({
|
|
where: { userId },
|
|
order: [['level', 'ASC']]
|
|
});
|
|
|
|
const totalLevelsPlayed = levelStats.length;
|
|
const completedLevels = levelStats.filter(stat => stat.completed).length;
|
|
const totalPlayTime = levelStats.reduce((sum, stat) => sum + (stat.playTime || 0), 0);
|
|
|
|
return {
|
|
...gameState,
|
|
totalLevelsPlayed,
|
|
completedLevels,
|
|
totalPlayTime,
|
|
levelStats: levelStats.map(stat => ({
|
|
level: stat.level,
|
|
bestScore: stat.bestScore,
|
|
bestMoney: stat.bestMoney,
|
|
bestPassengersDelivered: stat.bestPassengersDelivered,
|
|
timesPlayed: stat.timesPlayed,
|
|
completed: stat.completed
|
|
}))
|
|
};
|
|
} catch (error) {
|
|
console.error('Error getting player stats:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Level zurücksetzen
|
|
async resetLevel(hashedUserId, level) {
|
|
try {
|
|
const userId = await this.getUserIdFromHashedId(hashedUserId);
|
|
await TaxiLevelStats.destroy({
|
|
where: { userId, level }
|
|
});
|
|
|
|
return { success: true };
|
|
} catch (error) {
|
|
console.error('Error resetting level:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Alle Spielstände zurücksetzen
|
|
async resetAllProgress(hashedUserId) {
|
|
try {
|
|
const userId = await this.getUserIdFromHashedId(hashedUserId);
|
|
await TaxiGameState.destroy({
|
|
where: { userId }
|
|
});
|
|
|
|
await TaxiLevelStats.destroy({
|
|
where: { userId }
|
|
});
|
|
|
|
return { success: true };
|
|
} catch (error) {
|
|
console.error('Error resetting all progress:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Hilfsmethoden
|
|
async updateLevelStats(hashedUserId, level, stats) {
|
|
try {
|
|
const userId = await this.getUserIdFromHashedId(hashedUserId);
|
|
const { score, money, passengersDelivered } = stats;
|
|
|
|
const [levelStat, created] = await TaxiLevelStats.findOrCreate({
|
|
where: { userId, level },
|
|
defaults: {
|
|
userId,
|
|
level,
|
|
bestScore: score,
|
|
bestMoney: money,
|
|
bestPassengersDelivered: passengersDelivered,
|
|
timesPlayed: 1,
|
|
completed: true
|
|
}
|
|
});
|
|
|
|
if (!created) {
|
|
const updates = {
|
|
timesPlayed: levelStat.timesPlayed + 1,
|
|
completed: true
|
|
};
|
|
|
|
if (score > levelStat.bestScore) updates.bestScore = score;
|
|
if (money > levelStat.bestMoney) updates.bestMoney = money;
|
|
if (passengersDelivered > levelStat.bestPassengersDelivered) {
|
|
updates.bestPassengersDelivered = passengersDelivered;
|
|
}
|
|
|
|
await levelStat.update(updates);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error updating level stats:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async checkUnlockedLevels(hashedUserId, currentLevel) {
|
|
try {
|
|
const userId = await this.getUserIdFromHashedId(hashedUserId);
|
|
const gameState = await TaxiGameState.findOne({
|
|
where: { userId }
|
|
});
|
|
|
|
if (!gameState) return [];
|
|
|
|
const newUnlockedLevels = [];
|
|
const nextLevel = currentLevel + 1;
|
|
|
|
if (!gameState.unlockedLevels.includes(nextLevel)) {
|
|
newUnlockedLevels.push(nextLevel);
|
|
await this.unlockLevel(hashedUserId, nextLevel);
|
|
}
|
|
|
|
return newUnlockedLevels;
|
|
} catch (error) {
|
|
console.error('Error checking unlocked levels:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
async checkAchievements(hashedUserId, gameState) {
|
|
try {
|
|
const userId = await this.getUserIdFromHashedId(hashedUserId);
|
|
const achievements = [];
|
|
const currentAchievements = gameState.achievements || [];
|
|
|
|
// Beispiel-Erfolge
|
|
if (gameState.totalScore >= 1000 && !currentAchievements.includes('score_1000')) {
|
|
achievements.push('score_1000');
|
|
}
|
|
|
|
if (gameState.totalPassengersDelivered >= 50 && !currentAchievements.includes('passengers_50')) {
|
|
achievements.push('passengers_50');
|
|
}
|
|
|
|
if (gameState.currentLevel >= 10 && !currentAchievements.includes('level_10')) {
|
|
achievements.push('level_10');
|
|
}
|
|
|
|
if (achievements.length > 0) {
|
|
const newAchievements = [...currentAchievements, ...achievements];
|
|
await TaxiGameState.update(
|
|
{ achievements: newAchievements },
|
|
{ where: { userId } }
|
|
);
|
|
}
|
|
|
|
return achievements;
|
|
} catch (error) {
|
|
console.error('Error checking achievements:', error);
|
|
return [];
|
|
}
|
|
}
|
|
}
|
|
|
|
export default TaxiService;
|