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.
This commit is contained in:
Torsten Schulz (local)
2026-01-09 14:37:55 +01:00
parent c80cc8ec86
commit d0a2b122b2

View File

@@ -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 } });