diff --git a/YpDaemon/src/worker/user_character.rs b/YpDaemon/src/worker/user_character.rs index 0838724..828bb86 100644 --- a/YpDaemon/src/worker/user_character.rs +++ b/YpDaemon/src/worker/user_character.rs @@ -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 { diff --git a/src/worker/sql.rs b/src/worker/sql.rs index 8040ef5..b3e2f76 100644 --- a/src/worker/sql.rs +++ b/src/worker/sql.rs @@ -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#" diff --git a/src/worker/user_character.rs b/src/worker/user_character.rs index 3b0b6ee..df9a752 100644 --- a/src/worker/user_character.rs +++ b/src/worker/user_character.rs @@ -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 {