Refactor pregnancy handling in UserCharacterWorker: Changed the pregnancy check from a daily to an hourly basis, updating the associated method and SQL query to reflect this new frequency. This adjustment improves the accuracy of pregnancy probability calculations and aligns with the updated family dynamics logic.

This commit is contained in:
Torsten Schulz (local)
2026-03-22 09:43:36 +01:00
parent ac5ec3a245
commit 4086e9a207
3 changed files with 76 additions and 53 deletions

View File

@@ -85,7 +85,7 @@ impl UserCharacterWorker {
self.maybe_run_hourly_tasks();
self.maybe_run_mood_updates();
self.maybe_run_daily_pregnancies();
self.maybe_run_hourly_pregnancies();
// Entspricht in etwa der 1-Sekunden-Schleife im C++-Code
std::thread::sleep(Duration::from_secs(1));
@@ -123,11 +123,13 @@ impl UserCharacterWorker {
Ok(())
}
fn maybe_run_daily_pregnancies(&mut self) {
/// Ehe-Schwangerschaft: höchstens einmal pro Stunde (Daemon-Schleife ~1 s).
/// SQL nutzt stündliche Zerlegung der Jahres-Wahrscheinlichkeit (`1/8760`), siehe `QUERY_GET_PREGNANCY_CANDIDATES`.
fn maybe_run_hourly_pregnancies(&mut self) {
let now = Instant::now();
let should_run = match self.last_pregnancy_run {
None => true,
Some(last) => now.saturating_duration_since(last) >= Duration::from_secs(24 * 3600),
Some(last) => now.saturating_duration_since(last) >= Duration::from_secs(3600),
};
if !should_run {

View File

@@ -1218,73 +1218,92 @@ pub const QUERY_AUTOBATISM: &str = r#"
"#;
// Biologische Fruchtbarkeit nach Alter der Frau (Jahres-Wahrscheinlichkeit).
// Umrechnung auf Tages-Wahrscheinlichkeit: P_tag = 1 - (1 - P_jahr)^(1/365)
// Grenzen in Tagen: 1 Jahr ≈ 365 Tage
// Worker würfelt stündlich: P_stunde = 1 - (1 - P_jahr)^(1/8760), damit 24×/Tag zusammen
// dieselbe kumulative Jahresaufteilung wie früher 1×/Tag mit P_tag = 1 - (1 - P_jahr)^(1/365).
// Grenzen in Tagen: 1 Jahr ≈ 365 Tage (mother_age_days).
// WICHTIG: Vater/Mutter und Alter immer über gender ableiten — nicht character1/2 fest als Mutter!
pub const QUERY_GET_PREGNANCY_CANDIDATES: &str = r#"
WITH mother_age AS (
WITH paired AS (
SELECT
r.character1_id,
r.character2_id,
c1.title_of_nobility,
c1.last_name,
c1.region_id,
fu1.id AS father_uid,
fu2.id AS mother_uid,
(CURRENT_DATE - c2.birthdate::date)::int AS mother_age_days,
CASE
WHEN (CURRENT_DATE - c2.birthdate::date) < 4380 THEN 0.005
WHEN (CURRENT_DATE - c2.birthdate::date) < 4745 THEN 0.30
WHEN (CURRENT_DATE - c2.birthdate::date) < 5110 THEN 0.45
WHEN (CURRENT_DATE - c2.birthdate::date) < 5475 THEN 0.55
WHEN (CURRENT_DATE - c2.birthdate::date) < 5840 THEN 0.60
WHEN (CURRENT_DATE - c2.birthdate::date) < 6205 THEN 0.725
WHEN (CURRENT_DATE - c2.birthdate::date) < 6570 THEN 0.80
WHEN (CURRENT_DATE - c2.birthdate::date) < 7305 THEN 0.855
WHEN (CURRENT_DATE - c2.birthdate::date) < 9125 THEN 0.875
WHEN (CURRENT_DATE - c2.birthdate::date) < 10950 THEN 0.84
WHEN (CURRENT_DATE - c2.birthdate::date) < 11315 THEN 0.785
WHEN (CURRENT_DATE - c2.birthdate::date) < 11680 THEN 0.765
WHEN (CURRENT_DATE - c2.birthdate::date) < 12045 THEN 0.74
WHEN (CURRENT_DATE - c2.birthdate::date) < 12410 THEN 0.72
WHEN (CURRENT_DATE - c2.birthdate::date) < 12775 THEN 0.695
WHEN (CURRENT_DATE - c2.birthdate::date) < 13140 THEN 0.65
WHEN (CURRENT_DATE - c2.birthdate::date) < 13505 THEN 0.63
WHEN (CURRENT_DATE - c2.birthdate::date) < 13870 THEN 0.60
WHEN (CURRENT_DATE - c2.birthdate::date) < 14235 THEN 0.55
WHEN (CURRENT_DATE - c2.birthdate::date) < 14600 THEN 0.50
WHEN (CURRENT_DATE - c2.birthdate::date) < 14965 THEN 0.45
WHEN (CURRENT_DATE - c2.birthdate::date) < 15330 THEN 0.35
WHEN (CURRENT_DATE - c2.birthdate::date) < 15695 THEN 0.25
WHEN (CURRENT_DATE - c2.birthdate::date) < 16060 THEN 0.15
WHEN (CURRENT_DATE - c2.birthdate::date) < 16425 THEN 0.075
WHEN (CURRENT_DATE - c2.birthdate::date) < 16790 THEN 0.03
WHEN (CURRENT_DATE - c2.birthdate::date) < 17155 THEN 0.02
WHEN (CURRENT_DATE - c2.birthdate::date) < 17520 THEN 0.015
WHEN (CURRENT_DATE - c2.birthdate::date) < 18250 THEN 0.005
ELSE 0.001
END AS prob_year
CASE WHEN c1.gender = 'male' THEN c1.id ELSE c2.id END AS father_cid,
CASE WHEN c1.gender = 'female' THEN c1.id ELSE c2.id END AS mother_cid,
CASE WHEN c1.gender = 'male' THEN c1.title_of_nobility ELSE c2.title_of_nobility END AS title_of_nobility,
CASE WHEN c1.gender = 'male' THEN c1.last_name ELSE c2.last_name END AS last_name,
CASE WHEN c1.gender = 'male' THEN c1.region_id ELSE c2.region_id END AS region_id,
CASE WHEN c1.gender = 'male' THEN fu1.id ELSE fu2.id END AS father_uid,
CASE WHEN c1.gender = 'female' THEN fu1.id ELSE fu2.id END AS mother_uid,
(CURRENT_DATE - c_female.birthdate::date)::int AS mother_age_days
FROM falukant_data.relationship r
JOIN falukant_type.relationship r2
ON r2.id = r.relationship_type_id AND r2.tr = 'married'
JOIN falukant_data.character c1 ON c1.id = r.character1_id
JOIN falukant_data.character c2 ON c2.id = r.character2_id
JOIN falukant_data.character c_female ON c_female.id = (
CASE WHEN c1.gender = 'female' THEN c1.id ELSE c2.id END
)
LEFT JOIN falukant_data.falukant_user fu1 ON fu1.id = c1.user_id
LEFT JOIN falukant_data.falukant_user fu2 ON fu2.id = c2.user_id
WHERE (c1.gender = 'male' AND c2.gender = 'female')
OR (c1.gender = 'female' AND c2.gender = 'male')
),
mother_age AS (
SELECT
p.father_cid,
p.mother_cid,
p.title_of_nobility,
p.last_name,
p.region_id,
p.father_uid,
p.mother_uid,
p.mother_age_days,
CASE
WHEN p.mother_age_days < 4380 THEN 0.005
WHEN p.mother_age_days < 4745 THEN 0.30
WHEN p.mother_age_days < 5110 THEN 0.45
WHEN p.mother_age_days < 5475 THEN 0.55
WHEN p.mother_age_days < 5840 THEN 0.60
WHEN p.mother_age_days < 6205 THEN 0.725
WHEN p.mother_age_days < 6570 THEN 0.80
WHEN p.mother_age_days < 7305 THEN 0.855
WHEN p.mother_age_days < 9125 THEN 0.875
WHEN p.mother_age_days < 10950 THEN 0.84
WHEN p.mother_age_days < 11315 THEN 0.785
WHEN p.mother_age_days < 11680 THEN 0.765
WHEN p.mother_age_days < 12045 THEN 0.74
WHEN p.mother_age_days < 12410 THEN 0.72
WHEN p.mother_age_days < 12775 THEN 0.695
WHEN p.mother_age_days < 13140 THEN 0.65
WHEN p.mother_age_days < 13505 THEN 0.63
WHEN p.mother_age_days < 13870 THEN 0.60
WHEN p.mother_age_days < 14235 THEN 0.55
WHEN p.mother_age_days < 14600 THEN 0.50
WHEN p.mother_age_days < 14965 THEN 0.45
WHEN p.mother_age_days < 15330 THEN 0.35
WHEN p.mother_age_days < 15695 THEN 0.25
WHEN p.mother_age_days < 16060 THEN 0.15
WHEN p.mother_age_days < 16425 THEN 0.075
WHEN p.mother_age_days < 16790 THEN 0.03
WHEN p.mother_age_days < 17155 THEN 0.02
WHEN p.mother_age_days < 17520 THEN 0.015
WHEN p.mother_age_days < 18250 THEN 0.005
ELSE 0.001
END AS prob_year
FROM paired p
)
SELECT
character1_id AS father_cid,
character2_id AS mother_cid,
father_cid,
mother_cid,
title_of_nobility,
last_name,
region_id,
father_uid,
mother_uid,
mother_age_days,
(1 - POWER(1 - prob_year, 1.0/365.0)) * 100 AS prob_pct
(1 - POWER(1 - prob_year, 1.0/8760.0)) * 100 AS prob_pct
FROM mother_age
WHERE mother_age_days >= 4380
AND mother_age_days < 18993
AND random() < (1 - POWER(1 - prob_year, 1.0/365.0));
AND random() < (1 - POWER(1 - prob_year, 1.0/8760.0));
"#;
pub const QUERY_INSERT_CHILD: &str = r#"

View File

@@ -89,7 +89,7 @@ impl UserCharacterWorker {
self.maybe_run_hourly_tasks();
self.maybe_run_death_check();
self.maybe_run_mood_updates();
self.maybe_run_daily_pregnancies();
self.maybe_run_hourly_pregnancies();
// Entspricht in etwa der 1-Sekunden-Schleife im C++-Code
std::thread::sleep(Duration::from_secs(1));
@@ -172,11 +172,13 @@ impl UserCharacterWorker {
Ok(())
}
fn maybe_run_daily_pregnancies(&mut self) {
/// Ehe-Schwangerschaft: höchstens einmal pro Stunde (Daemon-Schleife ~1 s).
/// SQL nutzt stündliche Zerlegung der Jahres-Wahrscheinlichkeit (`1/8760`), siehe `QUERY_GET_PREGNANCY_CANDIDATES`.
fn maybe_run_hourly_pregnancies(&mut self) {
let now = Instant::now();
let should_run = match self.last_pregnancy_run {
None => true,
Some(last) => now.saturating_duration_since(last) >= Duration::from_secs(24 * 3600),
Some(last) => now.saturating_duration_since(last) >= Duration::from_secs(3600),
};
if !should_run {