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 @@
+