From d0a2b122b29e0009aa7abd6a1c8d11f46e3b6902 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Fri, 9 Jan 2026 14:37:55 +0100 Subject: [PATCH] Implement enhanced partner search and NPC creation logic in FalukantService - Added detailed logging for partner search criteria and results, improving traceability. - Refactored partner search logic to include a fallback mechanism for searching across all regions if no partners are found in the specified region. - Introduced a new method for creating NPCs when no suitable partners are available, ensuring a continuous flow in the partner matching process. - Improved the handling of character attributes such as age and title of nobility during partner searches and NPC creation. --- backend/services/falukantService.js | 142 +++++++++++++++++++++++++--- 1 file changed, 131 insertions(+), 11 deletions(-) diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index 5ee319b..9b05e8f 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -3190,20 +3190,29 @@ class FalukantService extends BaseService { ownAge }); + const minAgeDate = new Date(new Date() - 12 * 24 * 60 * 60 * 1000); + const titleMin = Math.max(1, requestingCharacterTitleOfNobility - 1); + const titleMax = requestingCharacterTitleOfNobility + 1; + + console.log(`[createPossiblePartners] Search criteria:`, { + excludeId: requestingCharacterId, + gender: `not ${requestingCharacterGender}`, + regionId: requestingRegionId, + minAge: '12 days old', + titleRange: `${titleMin}-${titleMax}`, + userId: 'null (NPCs only)' + }); + const whereClause = { id: { [Op.ne]: requestingCharacterId }, gender: { [Op.ne]: requestingCharacterGender }, regionId: requestingRegionId, - createdAt: { [Op.lt]: new Date(new Date() - 12 * 24 * 60 * 60 * 1000) }, - titleOfNobility: { [Op.between]: [Math.max(1, requestingCharacterTitleOfNobility - 1), requestingCharacterTitleOfNobility + 1] } + createdAt: { [Op.lt]: minAgeDate }, + titleOfNobility: { [Op.between]: [titleMin, titleMax] }, + userId: null // Nur NPCs suchen }; - // Nur NPCs suchen (userId ist null) - whereClause.userId = null; - - console.log(`[createPossiblePartners] Where clause:`, JSON.stringify(whereClause, null, 2)); - - const potentialPartners = await FalukantCharacter.findAll({ + let potentialPartners = await FalukantCharacter.findAll({ where: whereClause, order: [ [Sequelize.literal(`ABS((EXTRACT(EPOCH FROM (NOW() - "birthdate")) / 86400) - ${ownAge})`), 'ASC'] @@ -3211,11 +3220,54 @@ class FalukantService extends BaseService { limit: 5, }); - console.log(`[createPossiblePartners] Found ${potentialPartners.length} potential partners`); + console.log(`[createPossiblePartners] Found ${potentialPartners.length} potential partners in region ${requestingRegionId}`); + + // Fallback: Wenn keine Partner in der gleichen Region gefunden werden, suche in allen Regionen + if (potentialPartners.length === 0) { + console.log(`[createPossiblePartners] No partners in region ${requestingRegionId}, trying all regions...`); + const fallbackWhereClause = { + id: { [Op.ne]: requestingCharacterId }, + gender: { [Op.ne]: requestingCharacterGender }, + createdAt: { [Op.lt]: minAgeDate }, + titleOfNobility: { [Op.between]: [titleMin, titleMax] }, + userId: null + }; + + potentialPartners = await FalukantCharacter.findAll({ + where: fallbackWhereClause, + order: [ + [Sequelize.literal(`ABS((EXTRACT(EPOCH FROM (NOW() - "birthdate")) / 86400) - ${ownAge})`), 'ASC'] + ], + limit: 5, + }); + + console.log(`[createPossiblePartners] Found ${potentialPartners.length} potential partners in all regions`); + } if (potentialPartners.length === 0) { - console.warn(`[createPossiblePartners] No partners found with criteria. Consider creating NPCs.`); - return; // Keine Partner gefunden, aber kein Fehler + console.log(`[createPossiblePartners] No partners found, creating new NPCs...`); + // Erstelle automatisch 5 neue NPCs, die den Kriterien entsprechen + const targetGender = requestingCharacterGender === 'male' ? 'female' : 'male'; + const createdNPCs = await this._createNPCsForMarriage( + requestingRegionId, + targetGender, + titleMin, + titleMax, + ownAge, + 5 + ); + + if (createdNPCs.length > 0) { + console.log(`[createPossiblePartners] Created ${createdNPCs.length} new NPCs, using them as partners`); + potentialPartners = createdNPCs; + } else { + console.warn(`[createPossiblePartners] Failed to create NPCs. Consider creating NPCs manually with:`); + console.warn(` - gender: ${targetGender}`); + console.warn(` - regionId: ${requestingRegionId}`); + console.warn(` - titleOfNobility: ${titleMin}-${titleMax}`); + console.warn(` - age: ~${ownAge} years`); + return; // Keine Partner gefunden, aber kein Fehler + } } const proposals = potentialPartners.map(partner => { @@ -3235,6 +3287,74 @@ class FalukantService extends BaseService { } } + async _createNPCsForMarriage(regionId, gender, minTitle, maxTitle, targetAge, count = 5) { + try { + const sequelize = FalukantCharacter.sequelize; + const createdNPCs = []; + + await sequelize.transaction(async (t) => { + for (let i = 0; i < count; i++) { + // Zufälliger Titel im Bereich + const randomTitle = Math.floor(Math.random() * (maxTitle - minTitle + 1)) + minTitle; + + // Alter: ±2 Jahre um targetAge + const ageVariation = Math.floor(Math.random() * 5) - 2; // -2 bis +2 + const randomAge = Math.max(12, targetAge + ageVariation); // Mindestens 12 Jahre + + // Zufälliger Vorname für das Geschlecht + const firstName = await FalukantPredefineFirstname.findAll({ + where: { gender }, + order: sequelize.fn('RANDOM'), + limit: 1, + transaction: t + }); + + if (!firstName || firstName.length === 0) { + console.warn(`[_createNPCsForMarriage] No first names found for gender ${gender}`); + continue; + } + + // Zufälliger Nachname + const lastName = await FalukantPredefineLastname.findAll({ + order: sequelize.fn('RANDOM'), + limit: 1, + transaction: t + }); + + if (!lastName || lastName.length === 0) { + console.warn(`[_createNPCsForMarriage] No last names found`); + continue; + } + + // Geburtsdatum berechnen (Alter in Tagen) + const birthdate = new Date(); + birthdate.setDate(birthdate.getDate() - randomAge); + + // Erstelle den NPC-Charakter + const npc = await FalukantCharacter.create({ + userId: null, // Wichtig: null = NPC + regionId: regionId, + firstName: firstName[0].id, + lastName: lastName[0].id, + gender: gender, + birthdate: birthdate, + titleOfNobility: randomTitle, + health: 100, + moodId: 1 + }, { transaction: t }); + + createdNPCs.push(npc); + } + }); + + console.log(`[_createNPCsForMarriage] Created ${createdNPCs.length} NPCs`); + return createdNPCs; + } catch (error) { + console.error('[_createNPCsForMarriage] Error creating NPCs:', error); + return []; // Bei Fehler leeres Array zurückgeben + } + } + async acceptMarriageProposal(hashedUserId, proposedCharacterId) { const user = await this.getFalukantUserByHashedId(hashedUserId); const character = await FalukantCharacter.findOne({ where: { userId: user.id } });