From deb6f5f36ce6aa8cd343e425c6d427b10685e992 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Tue, 14 Apr 2026 11:39:42 +0200 Subject: [PATCH] feat(falukant): add improve lover affection feature and localization updates - Introduced the `improveLoverAffection` method in FalukantService to enhance relationship dynamics by allowing users to boost affection at a cost. - Updated FalukantController and FalukantRouter to include the new endpoint for improving lover affection. - Enhanced FamilyView component to provide a button for users to trigger the affection improvement action. - Added localization entries for the new feature in multiple languages, ensuring clarity in user interactions regarding affection improvements. --- backend/controllers/falukantController.js | 2 + backend/routers/falukantRouter.js | 1 + backend/services/falukantService.js | 85 +++++++++++++++++++++ frontend/src/i18n/locales/ceb/falukant.json | 4 + frontend/src/i18n/locales/de/falukant.json | 4 + frontend/src/i18n/locales/en/falukant.json | 4 + frontend/src/i18n/locales/es/falukant.json | 4 + frontend/src/i18n/locales/fr/falukant.json | 4 + frontend/src/views/falukant/FamilyView.vue | 30 ++++++++ 9 files changed, 138 insertions(+) diff --git a/backend/controllers/falukantController.js b/backend/controllers/falukantController.js index 3c77829..bc6ebdc 100644 --- a/backend/controllers/falukantController.js +++ b/backend/controllers/falukantController.js @@ -119,6 +119,8 @@ class FalukantController { }); this.setLoverMaintenance = this._wrapWithUser((userId, req) => this.service.setLoverMaintenance(userId, req.params.relationshipId, req.body?.maintenanceLevel), { blockInDebtorsPrison: true }); + this.improveLoverAffection = this._wrapWithUser((userId, req) => + this.service.improveLoverAffection(userId, req.params.relationshipId), { blockInDebtorsPrison: true }); this.createLoverRelationship = this._wrapWithUser((userId, req) => this.service.createLoverRelationship(userId, req.body?.targetCharacterId, req.body?.loverRole), { successStatus: 201, blockInDebtorsPrison: true }); this.spendTimeWithSpouse = this._wrapWithUser((userId) => diff --git a/backend/routers/falukantRouter.js b/backend/routers/falukantRouter.js index 73336f4..aa42a67 100644 --- a/backend/routers/falukantRouter.js +++ b/backend/routers/falukantRouter.js @@ -54,6 +54,7 @@ router.post('/family/marriage/spend-time', falukantController.spendTimeWithSpous router.post('/family/marriage/gift', falukantController.giftToSpouse); router.post('/family/marriage/reconcile', falukantController.reconcileMarriage); router.post('/family/lover/:relationshipId/maintenance', falukantController.setLoverMaintenance); +router.post('/family/lover/:relationshipId/improve-affection', falukantController.improveLoverAffection); router.post('/family/lover/:relationshipId/acknowledge', falukantController.acknowledgeLover); router.post('/family/lover/:relationshipId/end', falukantController.endLoverRelationship); router.get('/heirs/potential', falukantController.getPotentialHeirs); diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index 38ae6a5..fd8037f 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -3880,6 +3880,91 @@ class FalukantService extends BaseService { }; } + async improveLoverAffection(hashedUserId, relationshipId) { + const parsedRelationshipId = Number.parseInt(relationshipId, 10); + if (Number.isNaN(parsedRelationshipId)) { + throw { status: 400, message: 'relationshipId is required' }; + } + + const action = { + cost: 60, + affectionDelta: 6, + visibilityDelta: 3, + discretionDelta: -2, + householdOrderDelta: -3, + marriageSatisfactionDelta: -1 + }; + + const { user, state } = await this.getOwnedLoverRelationState(hashedUserId, parsedRelationshipId); + if (Number(user.money || 0) < action.cost) { + throw new Error('notenoughmoney.'); + } + + const userHouse = await UserHouse.findOne({ + where: { userId: user.id }, + attributes: ['householdOrder'] + }); + + const marriage = await Relationship.findOne({ + where: { character1Id: user.character.id }, + include: [ + { model: RelationshipType, as: 'relationshipType', where: { tr: 'married' } }, + { model: RelationshipState, as: 'state', required: false } + ] + }); + + let marriageState = marriage?.state || null; + if (marriage && !marriageState) { + marriageState = await RelationshipState.create({ + relationshipId: marriage.id, + ...this.buildDefaultRelationshipState('married') + }); + } + + const nextAffection = this.clampScore((state.affection ?? 50) + action.affectionDelta); + const nextVisibility = this.clampScore((state.visibility ?? 15) + action.visibilityDelta); + const nextDiscretion = this.clampScore((state.discretion ?? 50) + action.discretionDelta); + const nextHouseholdOrder = userHouse + ? this.clampScore((userHouse.householdOrder ?? 55) + action.householdOrderDelta) + : null; + const nextMarriageSatisfaction = marriageState + ? this.clampScore((marriageState.marriageSatisfaction ?? 55) + action.marriageSatisfactionDelta) + : null; + + await sequelize.transaction(async (t) => { + await state.update( + { + affection: nextAffection, + visibility: nextVisibility, + discretion: nextDiscretion, + }, + { transaction: t } + ); + if (userHouse && nextHouseholdOrder != null) { + await userHouse.update({ householdOrder: nextHouseholdOrder }, { transaction: t }); + } + if (marriageState && nextMarriageSatisfaction != null) { + await marriageState.update({ marriageSatisfaction: nextMarriageSatisfaction }, { transaction: t }); + } + await updateFalukantUserMoney(user.id, -action.cost, 'lover_affection_boost', user.id); + }); + + await this.refreshHouseholdTensionState(user, user.character); + await notifyUser(hashedUserId, 'falukantUpdateFamily', { reason: 'daily' }); + await notifyUser(hashedUserId, 'falukantUpdateStatus', {}); + + return { + success: true, + relationshipId: parsedRelationshipId, + cost: action.cost, + affection: nextAffection, + visibility: nextVisibility, + discretion: nextDiscretion, + householdOrder: nextHouseholdOrder, + marriageSatisfaction: nextMarriageSatisfaction, + }; + } + async spendTimeWithSpouse(hashedUserId) { const user = await this.getFalukantUserByHashedId(hashedUserId); if (!user?.character?.id) throw new Error('User or character not found'); diff --git a/frontend/src/i18n/locales/ceb/falukant.json b/frontend/src/i18n/locales/ceb/falukant.json index 658e9a4..7b85418 100644 --- a/frontend/src/i18n/locales/ceb/falukant.json +++ b/frontend/src/i18n/locales/ceb/falukant.json @@ -831,6 +831,10 @@ "maintenanceHigh": "Suporta 75", "maintenanceSuccess": "Na-update ang suporta.", "maintenanceError": "Dili ma-update ang suporta.", + "improveAffection": "Pauswaga ang pagmahal ({cost})", + "improveAffectionHint": "Mopataas sa pagmahal, mogasto og kwarta, ug mopataas usab sa visibility.", + "improveAffectionSuccess": "Napalig-on ang pagmahal ({cost}). Bag-ong bili: pagmahal {affection}, visibility {visibility}, discretion {discretion}.", + "improveAffectionError": "Dili mapaayo ang pagmahal.", "acknowledge": "Iila", "acknowledgeSuccess": "Giila na ang relasyon.", "acknowledgeError": "Dili ma-ila ang relasyon.", diff --git a/frontend/src/i18n/locales/de/falukant.json b/frontend/src/i18n/locales/de/falukant.json index dea70ce..fe9accf 100644 --- a/frontend/src/i18n/locales/de/falukant.json +++ b/frontend/src/i18n/locales/de/falukant.json @@ -805,6 +805,10 @@ "maintenanceHigh": "Unterhalt 75", "maintenanceSuccess": "Der Unterhalt wurde angepasst.", "maintenanceError": "Der Unterhalt konnte nicht angepasst werden.", + "improveAffection": "Zuneigung steigern ({cost})", + "improveAffectionHint": "Erhöht Zuneigung, kostet Geld und erhöht zugleich Sichtbarkeit.", + "improveAffectionSuccess": "Die Zuneigung wurde gestärkt ({cost}). Neuer Stand: Zuneigung {affection}, Sichtbarkeit {visibility}, Diskretion {discretion}.", + "improveAffectionError": "Die Zuneigung konnte nicht gesteigert werden.", "acknowledge": "Anerkennen", "acknowledgeSuccess": "Die Beziehung wurde offiziell anerkannt.", "acknowledgeError": "Die Beziehung konnte nicht anerkannt werden.", diff --git a/frontend/src/i18n/locales/en/falukant.json b/frontend/src/i18n/locales/en/falukant.json index 72851e8..cb89b2a 100644 --- a/frontend/src/i18n/locales/en/falukant.json +++ b/frontend/src/i18n/locales/en/falukant.json @@ -942,6 +942,10 @@ "maintenanceHigh": "Maintenance 75", "maintenanceSuccess": "Maintenance has been updated.", "maintenanceError": "Maintenance could not be updated.", + "improveAffection": "Boost affection ({cost})", + "improveAffectionHint": "Raises affection, costs money, and also increases visibility.", + "improveAffectionSuccess": "Affection has been strengthened ({cost}). New values: affection {affection}, visibility {visibility}, discretion {discretion}.", + "improveAffectionError": "Affection could not be improved.", "acknowledge": "Acknowledge", "acknowledgeSuccess": "The relationship has been officially acknowledged.", "acknowledgeError": "The relationship could not be acknowledged.", diff --git a/frontend/src/i18n/locales/es/falukant.json b/frontend/src/i18n/locales/es/falukant.json index ee8d25a..44b3618 100644 --- a/frontend/src/i18n/locales/es/falukant.json +++ b/frontend/src/i18n/locales/es/falukant.json @@ -796,6 +796,10 @@ "maintenanceHigh": "Mantenimiento 75", "maintenanceSuccess": "Se ha ajustado el mantenimiento.", "maintenanceError": "No se pudo ajustar el mantenimiento.", + "improveAffection": "Mejorar afecto ({cost})", + "improveAffectionHint": "Aumenta el afecto, cuesta dinero y también sube la visibilidad.", + "improveAffectionSuccess": "El afecto ha mejorado ({cost}). Nuevos valores: afecto {affection}, visibilidad {visibility}, discreción {discretion}.", + "improveAffectionError": "No se pudo mejorar el afecto.", "acknowledge": "Reconocer", "acknowledgeSuccess": "La relación ha sido reconocida oficialmente.", "acknowledgeError": "No se pudo reconocer la relación.", diff --git a/frontend/src/i18n/locales/fr/falukant.json b/frontend/src/i18n/locales/fr/falukant.json index d6c1cc5..e945999 100644 --- a/frontend/src/i18n/locales/fr/falukant.json +++ b/frontend/src/i18n/locales/fr/falukant.json @@ -794,6 +794,10 @@ "maintenanceHigh": "Entretien 75", "maintenanceSuccess": "L'entretien a été ajusté.", "maintenanceError": "La maintenance n'a pas pu être ajustée.", + "improveAffection": "Renforcer l’affection ({cost})", + "improveAffectionHint": "Augmente l’affection, coûte de l’argent et augmente aussi la visibilité.", + "improveAffectionSuccess": "L’affection a été renforcée ({cost}). Nouvelles valeurs : affection {affection}, visibilité {visibility}, discrétion {discretion}.", + "improveAffectionError": "L’affection n’a pas pu être améliorée.", "acknowledge": "Reconnaître", "acknowledgeSuccess": "La relation a été officiellement reconnue.", "acknowledgeError": "La relation n'a pas pu être reconnue.", diff --git a/frontend/src/views/falukant/FamilyView.vue b/frontend/src/views/falukant/FamilyView.vue index 2c68a98..28bb889 100644 --- a/frontend/src/views/falukant/FamilyView.vue +++ b/frontend/src/views/falukant/FamilyView.vue @@ -437,6 +437,13 @@ +