diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index 4043f99..7d6bb26 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -3886,17 +3886,64 @@ class FalukantService extends BaseService { }); } + const userHouse = await UserHouse.findOne({ + where: { userId: user.id }, + attributes: ['householdOrder'] + }); + const productionDelayMinutes = 15; + const runningProductions = await Production.findAll({ + where: { sleep: false }, + include: [{ + model: Branch, + as: 'branch', + required: true, + where: { falukantUserId: user.id }, + attributes: ['id'] + }], + attributes: ['id', 'startTimestamp'] + }); const nextSatisfaction = this.clampScore((state.marriageSatisfaction ?? 55) + 2); const nextPublicStability = this.clampScore((state.marriagePublicStability ?? 55) + 1); - await state.update({ - marriageSatisfaction: nextSatisfaction, - marriagePublicStability: nextPublicStability + const nextHouseholdOrder = userHouse + ? this.clampScore(Number(userHouse.householdOrder ?? 55) - 2) + : null; + const delayMs = productionDelayMinutes * 60 * 1000; + let delayedProductions = 0; + + await sequelize.transaction(async (t) => { + await state.update({ + marriageSatisfaction: nextSatisfaction, + marriagePublicStability: nextPublicStability + }); + if (userHouse && nextHouseholdOrder != null) { + await userHouse.update({ + householdOrder: nextHouseholdOrder + }); + } + for (const production of runningProductions) { + const startAt = new Date(production.startTimestamp); + if (Number.isNaN(startAt.getTime())) { + continue; + } + await production.update( + { startTimestamp: new Date(startAt.getTime() + delayMs) }, + { transaction: t } + ); + delayedProductions += 1; + } }); await this.refreshHouseholdTensionState(user, user.character); await notifyUser(hashedUserId, 'falukantUpdateFamily', { reason: 'daily' }); await notifyUser(hashedUserId, 'falukantUpdateStatus', {}); - return { success: true, marriageSatisfaction: nextSatisfaction }; + return { + success: true, + marriageSatisfaction: nextSatisfaction, + marriagePublicStability: nextPublicStability, + householdOrder: nextHouseholdOrder, + delayedProductions, + productionDelayMinutes + }; } async giftToSpouse(hashedUserId, giftLevel) { diff --git a/frontend/src/i18n/locales/ceb/falukant.json b/frontend/src/i18n/locales/ceb/falukant.json index 798d835..66b28ef 100644 --- a/frontend/src/i18n/locales/ceb/falukant.json +++ b/frontend/src/i18n/locales/ceb/falukant.json @@ -938,7 +938,14 @@ "giftDecent": "Decent regalo", "giftLavish": "Lavish regalo", "reconcile": "Reconcile dispute", + "costFree": "free", + "effectHintTitle": "Gasto ug epekto sa kini nga mga aksyon", + "effectSpendTime": "Conversation/time together: walay gasto sa kwarta, +2 marriage satisfaction, +1 public stability, -2 household order ug +{minutes} minutos sa running productions.", + "effectGifts": "Ang mga regalo naay gasto ug mas kusog nga epekto: small {small} (+2/+1), decent {decent} (+4/+2), lavish {lavish} (+7/+3).", + "effectReconcile": "Reconcile dispute: walay gasto sa kwarta, +1 marriage satisfaction, +1 public stability.", + "effectProduction": "Ang production effect daemon-based: ang running productions makadawat ug +{minutes} minutos pinaagi sa start timestamp ug mahuman nga mas ulahi.", "spendTimeSuccess": "Ang time together naay stabilized ang kasal.", + "spendTimeSuccessWithDelay": "Ang time together naay stabilized ang kasal. {count} ka running production na-delay ug {minutes} minutos.", "giftSuccess": "Ang regalo naay improved ang kasal.", "reconcileSuccess": "Ang dispute naay eased para sa now.", "actionError": "Ang action could dili be completed." diff --git a/frontend/src/i18n/locales/de/falukant.json b/frontend/src/i18n/locales/de/falukant.json index 2744e99..52de3dc 100644 --- a/frontend/src/i18n/locales/de/falukant.json +++ b/frontend/src/i18n/locales/de/falukant.json @@ -695,7 +695,14 @@ "giftDecent": "Gutes Geschenk", "giftLavish": "Großzügiges Geschenk", "reconcile": "Streit schlichten", + "costFree": "kostenlos", + "effectHintTitle": "Kosten und Wirkung dieser Aktionen", + "effectSpendTime": "Gespräch/Zeit miteinander: keine Geldkosten, +2 Ehezufriedenheit, +1 öffentliche Stabilität, -2 Haushaltsordnung und laufende Produktionen +{minutes} Minuten.", + "effectGifts": "Geschenke kosten Geld und wirken stärker: klein {small} (+2/+1), gut {decent} (+4/+2), großzügig {lavish} (+7/+3).", + "effectReconcile": "Streit schlichten: keine Geldkosten, +1 Ehezufriedenheit, +1 öffentliche Stabilität.", + "effectProduction": "Die Produktionswirkung ist daemonbasiert: Laufende Produktionen erhalten +{minutes} Minuten über den Startzeitpunkt und werden entsprechend später abgeschlossen.", "spendTimeSuccess": "Die gemeinsame Zeit hat die Ehe stabilisiert.", + "spendTimeSuccessWithDelay": "Die gemeinsame Zeit hat die Ehe stabilisiert. {count} laufende Produktion(en) wurden um {minutes} Minuten verzögert.", "giftSuccess": "Das Geschenk hat die Ehe verbessert.", "reconcileSuccess": "Der Streit wurde fürs Erste geschlichtet.", "actionError": "Die Aktion konnte nicht ausgeführt werden." diff --git a/frontend/src/i18n/locales/en/falukant.json b/frontend/src/i18n/locales/en/falukant.json index fc66909..11f9b78 100644 --- a/frontend/src/i18n/locales/en/falukant.json +++ b/frontend/src/i18n/locales/en/falukant.json @@ -882,7 +882,14 @@ "giftDecent": "Decent gift", "giftLavish": "Lavish gift", "reconcile": "Reconcile dispute", + "costFree": "free", + "effectHintTitle": "Costs and effects of these actions", + "effectSpendTime": "Conversation/time together: no money cost, +2 marriage satisfaction, +1 public stability, -2 household order, and +{minutes} minutes on running productions.", + "effectGifts": "Gifts cost money and have stronger effects: small {small} (+2/+1), decent {decent} (+4/+2), lavish {lavish} (+7/+3).", + "effectReconcile": "Reconcile dispute: no money cost, +1 marriage satisfaction, +1 public stability.", + "effectProduction": "Production impact is daemon-based: running productions get +{minutes} minutes via their start timestamp and therefore finish later.", "spendTimeSuccess": "The time together has stabilized the marriage.", + "spendTimeSuccessWithDelay": "The time together has stabilized the marriage. {count} running production(s) were delayed by {minutes} minutes.", "giftSuccess": "The gift has improved the marriage.", "reconcileSuccess": "The dispute has been eased for now.", "actionError": "The action could not be completed." diff --git a/frontend/src/i18n/locales/es/falukant.json b/frontend/src/i18n/locales/es/falukant.json index b6d9c9d..3bddbcd 100644 --- a/frontend/src/i18n/locales/es/falukant.json +++ b/frontend/src/i18n/locales/es/falukant.json @@ -695,7 +695,14 @@ "giftDecent": "Buen regalo", "giftLavish": "Regalo generoso", "reconcile": "Resolver disputa", + "costFree": "gratis", + "effectHintTitle": "Costes y efectos de estas acciones", + "effectSpendTime": "Conversación/tiempo juntos: sin coste de dinero, +2 satisfacción matrimonial, +1 estabilidad pública, -2 de orden del hogar y +{minutes} minutos en producciones en curso.", + "effectGifts": "Los regalos cuestan dinero y tienen efectos más fuertes: pequeño {small} (+2/+1), bueno {decent} (+4/+2), generoso {lavish} (+7/+3).", + "effectReconcile": "Resolver disputa: sin coste de dinero, +1 satisfacción matrimonial, +1 estabilidad pública.", + "effectProduction": "El efecto de producción es basado en daemon: las producciones en curso reciben +{minutes} minutos mediante su marca de inicio y por eso terminan más tarde.", "spendTimeSuccess": "El tiempo compartido ha estabilizado el matrimonio.", + "spendTimeSuccessWithDelay": "El tiempo compartido ha estabilizado el matrimonio. {count} producción(es) en curso se retrasaron {minutes} minutos.", "giftSuccess": "El regalo ha mejorado el matrimonio.", "reconcileSuccess": "La disputa se ha calmado por ahora.", "actionError": "No se pudo realizar la acción." diff --git a/frontend/src/i18n/locales/fr/falukant.json b/frontend/src/i18n/locales/fr/falukant.json index 5f230ec..800eeec 100644 --- a/frontend/src/i18n/locales/fr/falukant.json +++ b/frontend/src/i18n/locales/fr/falukant.json @@ -693,7 +693,14 @@ "giftDecent": "Bon cadeau", "giftLavish": "Cadeau généreux", "reconcile": "régler les différends", + "costFree": "gratuit", + "effectHintTitle": "Coûts et effets de ces actions", + "effectSpendTime": "Conversation/temps ensemble : pas de coût en argent, +2 satisfaction du mariage, +1 stabilité publique, -2 ordre du foyer et +{minutes} minutes sur les productions en cours.", + "effectGifts": "Les cadeaux coûtent de l'argent et ont des effets plus forts : petit {small} (+2/+1), bon {decent} (+4/+2), généreux {lavish} (+7/+3).", + "effectReconcile": "Régler les différends : pas de coût en argent, +1 satisfaction du mariage, +1 stabilité publique.", + "effectProduction": "L'effet de production est piloté par le daemon : les productions en cours reçoivent +{minutes} minutes via leur horodatage de départ et se terminent donc plus tard.", "spendTimeSuccess": "Le temps passé ensemble a stabilisé le mariage.", + "spendTimeSuccessWithDelay": "Le temps passé ensemble a stabilisé le mariage. {count} production(s) en cours ont été retardées de {minutes} minutes.", "giftSuccess": "Le cadeau a amélioré le mariage.", "reconcileSuccess": "Le différend était pour le moment réglé.", "actionError": "L'action n'a pas pu être réalisée." diff --git a/frontend/src/views/falukant/FamilyView.vue b/frontend/src/views/falukant/FamilyView.vue index 75be2d4..c77de96 100644 --- a/frontend/src/views/falukant/FamilyView.vue +++ b/frontend/src/views/falukant/FamilyView.vue @@ -238,21 +238,30 @@

{{ $t('falukant.family.marriageActions.title') }}

+
+ {{ $t('falukant.family.marriageActions.effectHintTitle') }} + +
{{ $t('falukant.family.householdTension.reasonsLabel') }}
@@ -486,6 +495,11 @@ import { confirmAction, showError, showInfo, showSuccess } from '@/utils/feedbac import { mapState } from 'vuex' const WOOING_PROGRESS_TARGET = 70 +const MARRIAGE_GIFT_COSTS = { + small: 25, + decent: 80, + lavish: 180 +} export default { name: 'FamilyView', @@ -527,6 +541,9 @@ export default { }, computed: { ...mapState(['socket', 'daemonSocket', 'user']), + marriageGiftCosts() { + return MARRIAGE_GIFT_COSTS; + }, partnerSummaryLine() { if (this.relationships?.length > 0) { const r = this.relationships[0]; @@ -713,8 +730,20 @@ export default { async spendTimeWithSpouse() { try { - await apiClient.post('/api/falukant/family/marriage/spend-time'); + const { data } = await apiClient.post('/api/falukant/family/marriage/spend-time'); await this.loadFamilyData(); + const delayed = Number(data?.delayedProductions || 0); + const delayMinutes = Number(data?.productionDelayMinutes || 15); + if (delayed > 0) { + showInfo( + this, + this.$t('falukant.family.marriageActions.spendTimeSuccessWithDelay', { + count: delayed, + minutes: delayMinutes + }) + ); + return; + } showSuccess(this, this.$t('falukant.family.marriageActions.spendTimeSuccess')); } catch (error) { console.error('Error spending time with spouse:', error); @@ -1217,6 +1246,21 @@ export default { gap: 10px; } +.marriage-actions__help { + margin: -2px 0 0; + color: var(--color-text-secondary); +} + +.marriage-actions__help summary { + cursor: pointer; + font-weight: 600; +} + +.marriage-actions__help ul { + margin: 8px 0 0; + padding-left: 18px; +} + .marriage-actions__reasons { display: grid; gap: 8px;