204 lines
5.9 KiB
JavaScript
204 lines
5.9 KiB
JavaScript
const mongoose = require('mongoose');
|
||
|
||
const playerDataSchema = new mongoose.Schema({
|
||
userId: {
|
||
type: String,
|
||
required: true,
|
||
unique: true
|
||
},
|
||
username: {
|
||
type: String,
|
||
required: true
|
||
},
|
||
// Player stats
|
||
stats: {
|
||
level: { type: Number, default: 1 },
|
||
experience: { type: Number, default: 0 },
|
||
totalExperience: { type: Number, default: 0 },
|
||
credits: { type: Number, default: 1000 },
|
||
gems: { type: Number, default: 0 },
|
||
skillPoints: { type: Number, default: 0 },
|
||
totalKills: { type: Number, default: 0 },
|
||
dungeonsCleared: { type: Number, default: 0 },
|
||
questsCompleted: { type: Number, default: 0 },
|
||
playTime: { type: Number, default: 0 },
|
||
lastLogin: { type: Date, default: Date.now }
|
||
},
|
||
// Game systems data
|
||
inventory: {
|
||
items: [{ type: mongoose.Schema.Types.Mixed }],
|
||
maxSize: { type: Number, default: 50 }
|
||
},
|
||
ship: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: null
|
||
},
|
||
base: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: null
|
||
},
|
||
quests: {
|
||
active: [{ type: mongoose.Schema.Types.Mixed }],
|
||
completed: [{ type: String }]
|
||
},
|
||
skills: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: {}
|
||
},
|
||
idleSystem: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: {}
|
||
},
|
||
dungeonSystem: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: {}
|
||
},
|
||
crafting: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: {}
|
||
},
|
||
// Starbase customisation — wallpapers and room unlocks
|
||
starbase: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: {
|
||
wallpaper: null,
|
||
ownedWallpapers: [],
|
||
unlockedRooms: [],
|
||
}
|
||
},
|
||
// NPC Faction Reputation (GDD §15.3) — scale -2000 to +2000
|
||
reputation: { type: mongoose.Schema.Types.Mixed, default: null },
|
||
|
||
// Fleet missions (GDD §8.3)
|
||
fleetMissions: { type: mongoose.Schema.Types.Mixed, default: [] },
|
||
|
||
// Ship construction queue (GDD §7.4)
|
||
shipQueue: { type: mongoose.Schema.Types.Mixed, default: [] },
|
||
|
||
// Alliance membership (GDD §12)
|
||
allianceId: { type: String, default: null },
|
||
allianceTag: { type: String, default: null },
|
||
allianceName: { type: String, default: null },
|
||
allianceRank: { type: String, default: null },
|
||
|
||
// Core resources — Metal, Gas, Crystal, Energy Cells, Dark Matter (GDD §5)
|
||
resources: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: { metal: 500, gas: 200, crystal: 100, energyCells: 300, darkMatter: 0, lastTick: null }
|
||
},
|
||
// Building slots — { buildingId: { level, buildQueue: { startedAt, completesAt } | null } }
|
||
buildings: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: { command_center: { level: 1, buildQueue: null } }
|
||
},
|
||
// Galaxy map — explored sectors and home sector
|
||
exploredSectors: { type: [String], default: ['15_10'] },
|
||
homeSector: { type: String, default: '15_10' },
|
||
// Research progress
|
||
research: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: { completed: [], inProgress: null, effects: {} }
|
||
},
|
||
// Server-specific data
|
||
currentServerId: {
|
||
type: String,
|
||
default: null
|
||
},
|
||
lastServerJoin: {
|
||
type: Date,
|
||
default: null
|
||
},
|
||
totalPlayTime: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
|
||
// PvP Ranked (GDD Phase 3)
|
||
pvp: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: {
|
||
rating: 1000, // ELO-style starting rating
|
||
wins: 0,
|
||
losses: 0,
|
||
winStreak: 0,
|
||
bestStreak: 0,
|
||
seasonRating: 1000,
|
||
lastRankedAt: null,
|
||
tier: 'bronze', // bronze / silver / gold / platinum / diamond
|
||
history: [] // last 50 match records
|
||
}
|
||
},
|
||
|
||
// Raid participation (GDD Phase 3)
|
||
raids: {
|
||
type: mongoose.Schema.Types.Mixed,
|
||
default: { completed: [], weeklyDone: false, monthlyBossDone: false, totalRaids: 0 }
|
||
}
|
||
}, {
|
||
timestamps: true
|
||
});
|
||
|
||
// Indexes for performance
|
||
playerDataSchema.index({ username: 1 });
|
||
playerDataSchema.index({ 'stats.level': 1 });
|
||
|
||
// Note: userId field already has unique: true which creates an index automatically
|
||
|
||
// Methods
|
||
// GDD §3.2: XP_required(L) = 500 × L^1.65
|
||
function xpForLevel(level) { return Math.floor(500 * Math.pow(level, 1.65)); }
|
||
|
||
playerDataSchema.methods.addExperience = function(amount) {
|
||
this.stats.experience = (this.stats.experience || 0) + amount;
|
||
this.stats.totalExperience = (this.stats.totalExperience || 0) + amount;
|
||
// Level-up loop
|
||
let leveled = false;
|
||
while (this.stats.experience >= xpForLevel(this.stats.level + 1)) {
|
||
this.stats.experience -= xpForLevel(this.stats.level + 1);
|
||
this.stats.level += 1;
|
||
this.stats.skillPoints = (this.stats.skillPoints || 0) + 1; // +1 skill point per level
|
||
leveled = true;
|
||
}
|
||
this.stats.experienceToNextLevel = xpForLevel(this.stats.level + 1);
|
||
return { newXP: this.stats.experience, level: this.stats.level, leveled };
|
||
};
|
||
|
||
playerDataSchema.methods.addCredits = function(amount) {
|
||
this.stats.credits += amount;
|
||
return this.stats.credits;
|
||
};
|
||
|
||
playerDataSchema.methods.updatePlayTime = function() {
|
||
const sessionTime = Date.now() - (this.lastLogin || Date.now());
|
||
this.stats.playTime += sessionTime;
|
||
this.totalPlayTime += sessionTime;
|
||
this.lastLogin = new Date();
|
||
return sessionTime;
|
||
};
|
||
|
||
playerDataSchema.methods.joinServer = function(serverId) {
|
||
this.currentServerId = serverId;
|
||
this.lastServerJoin = new Date();
|
||
this.lastLogin = new Date();
|
||
};
|
||
|
||
playerDataSchema.methods.leaveServer = function() {
|
||
console.log('[PLAYER DATA] leaveServer called for:', this.username);
|
||
|
||
// Update play time before leaving
|
||
const sessionTime = Date.now() - (this.lastLogin || Date.now());
|
||
this.stats.playTime += sessionTime;
|
||
this.totalPlayTime += sessionTime;
|
||
this.lastLogin = new Date();
|
||
|
||
// Clear server association
|
||
this.currentServerId = null;
|
||
this.lastServerJoin = null;
|
||
|
||
console.log('[PLAYER DATA] Updated play time:', sessionTime, 'Total play time:', this.totalPlayTime);
|
||
|
||
return sessionTime;
|
||
};
|
||
|
||
module.exports = mongoose.model('PlayerData', playerDataSchema);
|