Änderung: Hinzufügung des Taxi-Minispiels und zugehöriger Funktionen

Ä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.
This commit is contained in:
Torsten Schulz (local)
2025-09-15 17:59:42 +02:00
parent 4699488ce1
commit f230849a5c
72 changed files with 7698 additions and 133 deletions

View File

@@ -102,6 +102,10 @@ import Match3Level from './match3/level.js';
import Objective from './match3/objective.js';
import UserProgress from './match3/userProgress.js';
import UserLevelProgress from './match3/userLevelProgress.js';
import TaxiGameState from './taxi/taxiGameState.js';
import TaxiLevelStats from './taxi/taxiLevelStats.js';
import TaxiMapType from './taxi/taxiMapType.js';
import TaxiMap from './taxi/taxiMap.js';
export default function setupAssociations() {
// RoomType 1:n Room
@@ -786,4 +790,15 @@ export default function setupAssociations() {
UserLevelProgress.belongsTo(UserProgress, { foreignKey: 'userProgressId', as: 'userProgress' });
Match3Level.hasMany(UserLevelProgress, { foreignKey: 'levelId', as: 'userLevelProgress' });
UserLevelProgress.belongsTo(Match3Level, { foreignKey: 'levelId', as: 'level' });
// Taxi Game associations
TaxiGameState.belongsTo(User, { foreignKey: 'userId', as: 'user' });
User.hasOne(TaxiGameState, { foreignKey: 'userId', as: 'taxiGameState' });
TaxiLevelStats.belongsTo(User, { foreignKey: 'userId', as: 'user' });
User.hasMany(TaxiLevelStats, { foreignKey: 'userId', as: 'taxiLevelStats' });
// Taxi Map associations
TaxiMap.belongsTo(TaxiMapType, { foreignKey: 'mapTypeId', as: 'mapType' });
TaxiMapType.hasMany(TaxiMap, { foreignKey: 'mapTypeId', as: 'maps' });
}

View File

@@ -95,6 +95,9 @@ import Match3Objective from './match3/objective.js';
import Match3UserProgress from './match3/userProgress.js';
import Match3UserLevelProgress from './match3/userLevelProgress.js';
// — Taxi Minigame —
import { TaxiGameState, TaxiLevelStats } from './taxi/index.js';
// — Politische Ämter (Politics) —
import PoliticalOfficeType from './falukant/type/political_office_type.js';
import PoliticalOfficeRequirement from './falukant/predefine/political_office_prerequisite.js';
@@ -230,6 +233,10 @@ const models = {
Match3Objective,
Match3UserProgress,
Match3UserLevelProgress,
// Taxi Minigame
TaxiGameState,
TaxiLevelStats,
};
export default models;

View File

@@ -0,0 +1,6 @@
import TaxiGameState from './taxiGameState.js';
import TaxiLevelStats from './taxiLevelStats.js';
import TaxiMapType from './taxiMapType.js';
import TaxiMap from './taxiMap.js';
export { TaxiGameState, TaxiLevelStats, TaxiMapType, TaxiMap };

View File

@@ -0,0 +1,75 @@
import { DataTypes } from 'sequelize';
import { sequelize } from '../../utils/sequelize.js';
const TaxiGameState = sequelize.define('TaxiGameState', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
userId: {
type: DataTypes.INTEGER,
allowNull: false
},
currentLevel: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 1
},
totalScore: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
},
totalMoney: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
},
totalPassengersDelivered: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
},
unlockedLevels: {
type: DataTypes.JSON,
allowNull: false,
defaultValue: [1]
},
achievements: {
type: DataTypes.JSON,
allowNull: false,
defaultValue: []
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
}
}, {
tableName: 'taxi_game_states',
schema: 'taxi',
timestamps: true,
indexes: [
{
unique: true,
fields: ['user_id']
},
{
fields: ['total_score']
},
{
fields: ['total_money']
},
{
fields: ['total_passengers_delivered']
}
]
});
export default TaxiGameState;

View File

@@ -0,0 +1,79 @@
import { DataTypes } from 'sequelize';
import { sequelize } from '../../utils/sequelize.js';
const TaxiLevelStats = sequelize.define('TaxiLevelStats', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
userId: {
type: DataTypes.INTEGER,
allowNull: false
},
level: {
type: DataTypes.INTEGER,
allowNull: false
},
bestScore: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
},
bestMoney: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
},
bestPassengersDelivered: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
},
timesPlayed: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
},
completed: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
playTime: {
type: DataTypes.INTEGER,
allowNull: true,
comment: 'Play time in seconds'
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
}
}, {
tableName: 'taxi_level_stats',
schema: 'taxi',
timestamps: true,
indexes: [
{
unique: true,
fields: ['user_id', 'level']
},
{
fields: ['level']
},
{
fields: ['best_score']
},
{
fields: ['completed']
}
]
});
export default TaxiLevelStats;

View File

@@ -0,0 +1,101 @@
import { DataTypes } from 'sequelize';
import { sequelize } from '../../utils/sequelize.js';
const TaxiMap = sequelize.define('TaxiMap', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING(100),
allowNull: false
},
description: {
type: DataTypes.TEXT,
allowNull: true
},
width: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 8,
comment: 'Map width in tiles'
},
height: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 8,
comment: 'Map height in tiles'
},
tileSize: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 50,
comment: 'Size of each tile in pixels'
},
mapTypeId: {
type: DataTypes.INTEGER,
allowNull: false,
comment: 'Reference to TaxiMapType'
},
mapData: {
type: DataTypes.JSON,
allowNull: false,
comment: '2D array of map type IDs for each tile position'
},
positionX: {
type: DataTypes.INTEGER,
allowNull: false,
comment: 'X position as continuous integer (1, 2, 3, ...)'
},
positionY: {
type: DataTypes.INTEGER,
allowNull: false,
comment: 'Y position as continuous integer (1, 2, 3, ...)'
},
isActive: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
},
isDefault: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
comment: 'Whether this is the default map for new games'
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
}
}, {
tableName: 'taxi_maps',
schema: 'taxi',
timestamps: true,
indexes: [
{
fields: ['name']
},
{
fields: ['is_active']
},
{
fields: ['is_default']
},
{
fields: ['position_x', 'position_y']
},
{
unique: true,
fields: ['position_x', 'position_y']
}
]
});
export default TaxiMap;

View File

@@ -0,0 +1,57 @@
import { DataTypes } from 'sequelize';
import { sequelize } from '../../utils/sequelize.js';
const TaxiMapType = sequelize.define('TaxiMapType', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true
},
description: {
type: DataTypes.TEXT,
allowNull: true
},
tileType: {
type: DataTypes.STRING(50),
allowNull: false,
comment: 'Type of tile: cornerBottomLeft, cornerBottomRight, cornerTopLeft, cornerTopRight, horizontal, vertical, cross, fuelHorizontal, fuelVertical, tLeft, tRight, tUp, tDown'
},
isActive: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
}
}, {
tableName: 'taxi_map_types',
schema: 'taxi',
timestamps: true,
indexes: [
{
unique: true,
fields: ['name']
},
{
fields: ['tile_type']
},
{
fields: ['is_active']
}
]
});
export default TaxiMapType;