Entkopple Partnersuche vom Altersabstand und entferne garantierte Schwangerschaften
All checks were successful
Deploy to production / deploy (push) Successful in 2m41s
All checks were successful
Deploy to production / deploy (push) Successful in 2m41s
This commit is contained in:
@@ -5,7 +5,8 @@ import FalukantPredefineFirstname from '../models/falukant/predefine/firstname.j
|
||||
import FalukantPredefineLastname from '../models/falukant/predefine/lastname.js';
|
||||
import FalukantUser from '../models/falukant/data/user.js';
|
||||
import FalukantCharacter from '../models/falukant/data/character.js';
|
||||
import { getCharacterDevelopment, hasReachedFertility } from '../utils/falukant/characterDevelopment.js';
|
||||
import { getCharacterDevelopment } from '../utils/falukant/characterDevelopment.js';
|
||||
import { buildPartnerCandidateQuery } from '../utils/falukant/partnerCandidates.js';
|
||||
import RegionData from '../models/falukant/data/region.js';
|
||||
import RegionType from '../models/falukant/type/region.js';
|
||||
import FalukantStock from '../models/falukant/data/stock.js';
|
||||
@@ -3610,108 +3611,6 @@ class FalukantService extends BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nach der Trauung (relationship = married): geplante Geburt auf der Mutter-Charakterzeile setzen,
|
||||
* damit der Daemon den UserCharacterWorker-Pfad mit pregnancy_due_at nutzen kann.
|
||||
* Läuft idempotent pro Ehe über relationship_state.flags_json.honeymoonPregnancyScheduled.
|
||||
* @returns {{ scheduled: boolean, motherCharacterId?: number }}
|
||||
*/
|
||||
async _ensureMarriageHoneymoonPregnancyScheduled({
|
||||
playerCharacterId,
|
||||
playerGender,
|
||||
spouseCharacterId,
|
||||
spouseGender,
|
||||
relationshipId,
|
||||
}) {
|
||||
if (!relationshipId || !playerCharacterId || !spouseCharacterId) {
|
||||
return { scheduled: false };
|
||||
}
|
||||
const norm = (g) => String(g || '').trim().toLowerCase();
|
||||
const isFemale = (g) => {
|
||||
const s = norm(g);
|
||||
return s === 'female' || s === 'f';
|
||||
};
|
||||
const isMale = (g) => {
|
||||
const s = norm(g);
|
||||
return s === 'male' || s === 'm';
|
||||
};
|
||||
let motherId;
|
||||
let fatherId;
|
||||
if (isFemale(playerGender) && isMale(spouseGender)) {
|
||||
motherId = playerCharacterId;
|
||||
fatherId = spouseCharacterId;
|
||||
} else if (isFemale(spouseGender) && isMale(playerGender)) {
|
||||
motherId = spouseCharacterId;
|
||||
fatherId = playerCharacterId;
|
||||
} else {
|
||||
return { scheduled: false };
|
||||
}
|
||||
|
||||
const parents = await FalukantCharacter.unscoped().findAll({
|
||||
where: { id: [motherId, fatherId] },
|
||||
attributes: ['id', 'birthdate', 'fertileFromAge'],
|
||||
});
|
||||
if (
|
||||
parents.length !== 2
|
||||
|| parents.some((parent) => !hasReachedFertility(parent, calcAge(parent.birthdate)))
|
||||
) {
|
||||
return { scheduled: false };
|
||||
}
|
||||
|
||||
const stateRow = await RelationshipState.findOne({ where: { relationshipId } });
|
||||
const flags = stateRow?.flagsJson && typeof stateRow.flagsJson === 'object'
|
||||
? { ...stateRow.flagsJson }
|
||||
: {};
|
||||
if (flags.honeymoonPregnancyScheduled) {
|
||||
return { scheduled: false };
|
||||
}
|
||||
|
||||
const pregRows = await sequelize.query(
|
||||
`SELECT pregnancy_due_at FROM falukant_data."character" WHERE id = :id`,
|
||||
{ replacements: { id: motherId }, type: Sequelize.QueryTypes.SELECT }
|
||||
);
|
||||
if (pregRows[0]?.pregnancy_due_at) {
|
||||
return { scheduled: false };
|
||||
}
|
||||
|
||||
// Automatische Hochzeits-Schwangerschaften nutzen die kurze Spielzeit von 18 Stunden.
|
||||
const BIRTH_DUE_HOURS = 18;
|
||||
const due = new Date();
|
||||
due.setHours(due.getHours() + BIRTH_DUE_HOURS);
|
||||
|
||||
await FalukantCharacter.unscoped().update(
|
||||
{
|
||||
pregnancyDueAt: due,
|
||||
pregnancyFatherCharacterId: fatherId,
|
||||
},
|
||||
{ where: { id: motherId } }
|
||||
);
|
||||
|
||||
const mergedFlags = { ...flags, honeymoonPregnancyScheduled: true };
|
||||
if (stateRow) {
|
||||
await stateRow.update({ flagsJson: mergedFlags });
|
||||
} else {
|
||||
await RelationshipState.create({
|
||||
relationshipId,
|
||||
...this.buildDefaultRelationshipState('married'),
|
||||
flagsJson: mergedFlags,
|
||||
});
|
||||
}
|
||||
|
||||
const mother = await FalukantCharacter.unscoped().findByPk(motherId, { attributes: ['id', 'userId'] });
|
||||
if (mother?.userId) {
|
||||
const fu = await FalukantUser.findByPk(mother.userId);
|
||||
if (fu) {
|
||||
const u = await User.findByPk(fu.userId);
|
||||
if (u?.hashedId) {
|
||||
await notifyUser(u.hashedId, 'familychanged', {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { scheduled: true, motherCharacterId: motherId };
|
||||
}
|
||||
|
||||
async getFamily(hashedUserId) {
|
||||
const user = await this.getFalukantUserByHashedId(hashedUserId);
|
||||
if (!user) throw new Error('User not found');
|
||||
@@ -3926,7 +3825,7 @@ class FalukantService extends BaseService {
|
||||
if (!child.hasName || child.relationship || !kid || calcAge(kid.birthdate) < FAMILY_AGE.MIN_WOOING) continue;
|
||||
child.possiblePartners = await this.getPossiblePartners(kid.id);
|
||||
if (child.possiblePartners.length === 0) {
|
||||
await this.createPossiblePartners(kid.id, kid.gender, kid.regionId, kid.titleOfNobility, calcAge(kid.birthdate));
|
||||
await this.createPossiblePartners(kid.id, kid.gender, kid.regionId, kid.titleOfNobility);
|
||||
child.possiblePartners = await this.getPossiblePartners(kid.id);
|
||||
}
|
||||
}
|
||||
@@ -4039,25 +3938,11 @@ class FalukantService extends BaseService {
|
||||
character.id,
|
||||
character.gender,
|
||||
character.regionId,
|
||||
character.titleOfNobility,
|
||||
ownAge
|
||||
character.titleOfNobility
|
||||
);
|
||||
family.possiblePartners = await this.getPossiblePartners(character.id);
|
||||
}
|
||||
}
|
||||
const marriedRel = family.relationships.find((r) => r.relationshipType === 'married');
|
||||
if (marriedRel?.id && marriedRel.character2?.id != null) {
|
||||
const honeymoon = await this._ensureMarriageHoneymoonPregnancyScheduled({
|
||||
playerCharacterId: character.id,
|
||||
playerGender: character.gender,
|
||||
spouseCharacterId: marriedRel.character2.id,
|
||||
spouseGender: marriedRel.character2.gender,
|
||||
relationshipId: marriedRel.id,
|
||||
});
|
||||
if (honeymoon.scheduled && honeymoon.motherCharacterId === character.id) {
|
||||
family.pregnancy = await this._getCharacterPregnancyOptional(character.id);
|
||||
}
|
||||
}
|
||||
return family;
|
||||
}
|
||||
|
||||
@@ -4663,7 +4548,7 @@ class FalukantService extends BaseService {
|
||||
});
|
||||
}
|
||||
|
||||
async createPossiblePartners(requestingCharacterId, requestingCharacterGender, requestingRegionId, requestingCharacterTitleOfNobility, ownAge) {
|
||||
async createPossiblePartners(requestingCharacterId, requestingCharacterGender, requestingRegionId, requestingCharacterTitleOfNobility) {
|
||||
try {
|
||||
const minTitleResult = await TitleOfNobility.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
@@ -4674,20 +4559,13 @@ class FalukantService extends BaseService {
|
||||
}
|
||||
const minTitle = minTitleResult.id;
|
||||
|
||||
const potentialPartners = await FalukantCharacter.findAll({
|
||||
where: {
|
||||
id: { [Op.ne]: requestingCharacterId },
|
||||
gender: { [Op.ne]: requestingCharacterGender },
|
||||
regionId: requestingRegionId,
|
||||
birthdate: { [Op.lte]: new Date(Date.now() - FAMILY_AGE.MIN_WOOING * 24 * 60 * 60 * 1000) },
|
||||
createdAt: { [Op.lt]: new Date(Date.now() - FAMILY_AGE.MIN_WOOING * 24 * 60 * 60 * 1000) },
|
||||
titleOfNobility: { [Op.between]: [requestingCharacterTitleOfNobility - 1, requestingCharacterTitleOfNobility + 1] }
|
||||
},
|
||||
order: [
|
||||
[Sequelize.literal(`ABS((EXTRACT(EPOCH FROM (NOW() - "birthdate")) / 86400) - ${ownAge})`), 'ASC']
|
||||
],
|
||||
limit: 5,
|
||||
});
|
||||
const potentialPartners = await FalukantCharacter.findAll(buildPartnerCandidateQuery({
|
||||
characterId: requestingCharacterId,
|
||||
gender: requestingCharacterGender,
|
||||
regionId: requestingRegionId,
|
||||
titleId: requestingCharacterTitleOfNobility,
|
||||
minimumAge: FAMILY_AGE.MIN_WOOING,
|
||||
}));
|
||||
|
||||
const proposals = potentialPartners.map(partner => {
|
||||
const age = calcAge(partner.birthdate);
|
||||
|
||||
Reference in New Issue
Block a user