diff --git a/src/worker/events.rs b/src/worker/events.rs index 19afb6d..c0bddc9 100644 --- a/src/worker/events.rs +++ b/src/worker/events.rs @@ -45,6 +45,7 @@ use crate::worker::sql::{ QUERY_DELETE_CHILD_RELATION, QUERY_DELETE_CHARACTER, QUERY_GET_HEIR, + QUERY_GET_RANDOM_HEIR_FROM_REGION, QUERY_SET_CHARACTER_USER, QUERY_CLEAR_CHARACTER_USER, QUERY_GET_CURRENT_MONEY, @@ -1589,18 +1590,28 @@ impl EventsWorker { .and_then(|r| r.get("child_character_id")) .and_then(|v| v.parse::().ok()); + // Kein Kind als Erbe vorhanden? Dann fallback: zufälliger NPC-Character aus der Region, + // Alter 10–14 Tage. let heir_id = match heir_id { Some(id) if id > 0 => id, _ => { - // Kein Erbe gefunden - Vermögen geht verloren - eprintln!( - "[EventsWorker] Kein Erbe für Charakter {} gefunden, Vermögen geht verloren", - deceased_character_id - ); - return Ok(()); + conn.prepare("random_heir_region", QUERY_GET_RANDOM_HEIR_FROM_REGION)?; + let rows = conn.execute("random_heir_region", &[&deceased_character_id])?; + rows.first() + .and_then(|r| r.get("child_character_id")) + .and_then(|v| v.parse::().ok()) + .unwrap_or(0) } }; + if heir_id <= 0 { + eprintln!( + "[EventsWorker] Kein Erbe für Charakter {} gefunden (weder Kind noch Fallback in Region). User {} hat danach keinen Character.", + deceased_character_id, falukant_user_id + ); + return Ok(()); + } + // 2) Wichtig: erst die alte User-Zuordnung am verstorbenen Charakter lösen. // Falls es einen Unique-Constraint auf `character.user_id` gibt, würde das // direkte Setzen am Erben sonst fehlschlagen. diff --git a/src/worker/sql.rs b/src/worker/sql.rs index d2f1aab..8f6b2ba 100644 --- a/src/worker/sql.rs +++ b/src/worker/sql.rs @@ -1351,6 +1351,31 @@ pub const QUERY_RANDOM_HEIR: &str = r#" chosen.child_character_id; "#; +// Fallback-Erbe: Wenn ein Spieler-Character ohne Kinder stirbt, suchen wir einen zufälligen +// NPC-Character in derselben Region (Alter 10–14 Tage) und übergeben ihm die user_id. +pub const QUERY_GET_RANDOM_HEIR_FROM_REGION: &str = r#" + SELECT ch.id AS child_character_id + FROM falukant_data.character ch + WHERE ch.user_id IS NULL + AND ch.health > 0 + AND ch.id <> $1 + AND ch.region_id = ( + SELECT region_id + FROM falukant_data.character + WHERE id = $1 + ) + -- Alter zwischen 10 und 14 Tagen: birthdate in [now-14d, now-10d] + AND ch.birthdate <= NOW() - INTERVAL '10 days' + AND ch.birthdate >= NOW() - INTERVAL '14 days' + AND ch.title_of_nobility = ( + SELECT id + FROM falukant_type.title + WHERE label_tr = 'noncivil' + ) + ORDER BY RANDOM() + LIMIT 1; +"#; + pub const QUERY_UPDATE_USER_MONEY: &str = r#" UPDATE falukant_data.falukant_user SET money = $1, @@ -1600,8 +1625,16 @@ pub const QUERY_GET_FINISHED_PRODUCTIONS: &str = r#" ON p.product_id = pr.id JOIN falukant_data.branch br ON p.branch_id = br.id - JOIN falukant_data.character c - ON c.user_id = br.falukant_user_id + -- Es kann vorkommen, dass ein User temporär keinen zugeordneten Character hat + -- (z.B. nach Tod/Erbe). Produktionen sollen trotzdem abschließen. + -- LATERAL verhindert Duplikate, falls ein User mehrere Characters hat. + LEFT JOIN LATERAL ( + SELECT c.id, c.user_id + FROM falukant_data.character c + WHERE c.user_id = br.falukant_user_id + ORDER BY c.updated_at DESC NULLS LAST, c.id DESC + LIMIT 1 + ) c ON TRUE LEFT JOIN falukant_data.knowledge k ON p.product_id = k.product_id AND k.character_id = c.id diff --git a/src/worker/user_character.rs b/src/worker/user_character.rs index 201bf05..3d8026c 100644 --- a/src/worker/user_character.rs +++ b/src/worker/user_character.rs @@ -28,6 +28,7 @@ use crate::worker::sql::{ QUERY_COUNT_CHILDREN, QUERY_GET_HEIR, QUERY_RANDOM_HEIR, + QUERY_GET_RANDOM_HEIR_FROM_REGION, QUERY_SET_CHARACTER_USER, QUERY_CLEAR_CHARACTER_USER, QUERY_UPDATE_USER_MONEY, @@ -608,6 +609,12 @@ impl UserCharacterWorker { new_money = self.calculate_new_money(falukant_user_id, heir_id > 0)?; } + // Wenn es gar keine Kinder gibt, nimm einen zufälligen NPC in der Region (Alter 10–14 Tage). + if heir_id < 1 { + heir_id = self.get_random_heir_from_region(character_id)?; + new_money = self.calculate_new_money(falukant_user_id, heir_id > 0)?; + } + if heir_id > 0 { // Erst die alte Zuordnung lösen (Unique-Constraint safety), dann den Erben zuweisen. self.clear_character_user(character_id)?; @@ -669,6 +676,23 @@ impl UserCharacterWorker { .unwrap_or(-1)) } + fn get_random_heir_from_region(&mut self, deceased_character_id: i32) -> Result { + let mut conn = self + .base + .pool + .get() + .map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?; + + conn.prepare("random_heir_region", QUERY_GET_RANDOM_HEIR_FROM_REGION)?; + let rows = conn.execute("random_heir_region", &[&deceased_character_id])?; + + Ok(rows + .first() + .and_then(|r| r.get("child_character_id")) + .and_then(|v| v.parse::().ok()) + .unwrap_or(-1)) + } + fn set_new_character( &mut self, falukant_user_id: i32,