diff --git a/src/worker/events.rs b/src/worker/events.rs index b71679e..4339970 100644 --- a/src/worker/events.rs +++ b/src/worker/events.rs @@ -16,6 +16,7 @@ use crate::worker::sql::{ QUERY_INSERT_NOTIFICATION, QUERY_GET_MONEY, QUERY_UPDATE_MONEY, + QUERY_INSERT_MONEY_HISTORY, QUERY_GET_REGION_STOCKS, QUERY_GET_USER_STOCKS, QUERY_UPDATE_STOCK_CAPACITY, @@ -67,8 +68,14 @@ pub enum EventType { /// Mögliche Effekte, die ein Ereignis haben kann #[derive(Debug, Clone)] pub enum EventEffect { - /// Änderung des Geldes eines Spielers (in Prozent) - MoneyChange { probability: f64, min_percent: f64, max_percent: f64 }, + /// Änderung des Geldes eines Spielers (in Prozent). + /// Bei positiver Änderung kann min_absolute_positive einen Mindestbetrag erzwingen (z. B. damit ein „Fund“ nie 0 ist). + MoneyChange { + probability: f64, + min_percent: f64, + max_percent: f64, + min_absolute_positive: Option, + }, /// Änderung der Produktionsqualität in einer Region (in Prozentpunkten) ProductionQualityChange { probability: f64, min_change: i32, max_change: i32 }, /// Änderung der Verkaufspreise in einer Region (in Prozent) @@ -169,6 +176,7 @@ impl EventsWorker { probability: 1.0, min_percent: 5.0, max_percent: 15.0, + min_absolute_positive: Some(1.0), // Fund ist nie 0 }, ], }, @@ -183,6 +191,7 @@ impl EventsWorker { probability: 1.0, min_percent: -10.0, max_percent: -5.0, + min_absolute_positive: None, }, ], }, @@ -511,13 +520,23 @@ impl EventsWorker { probability, min_percent, max_percent, + min_absolute_positive, } => { if effect_roll < *probability { let percent_change = rng.gen_range(*min_percent..=*max_percent); let current_money = Self::get_current_money(&mut conn, user_id).unwrap_or(0.0); let computed_change = current_money * (percent_change / 100.0); - let absolute_change = Self::apply_money_change(&mut conn, user_id, percent_change) - .unwrap_or(computed_change); + let effective_change = match min_absolute_positive { + Some(min_abs) if percent_change > 0.0 && computed_change < *min_abs => *min_abs, + _ => computed_change, + }; + let absolute_change = Self::apply_money_change( + &mut conn, + user_id, + percent_change, + Some(effective_change), + ) + .unwrap_or(effective_change); effect_results.push(json!({ "type": "money_change", "percent": percent_change, @@ -1030,19 +1049,18 @@ impl EventsWorker { conn: &mut DbConnection, user_id: i32, percent_change: f64, + absolute_override: Option, ) -> Result { let current_money = Self::get_current_money(conn, user_id)?; - let change = current_money * (percent_change / 100.0); + let change = absolute_override + .unwrap_or_else(|| current_money * (percent_change / 100.0)); let action = format!("Zufallsereignis: Geldänderung {:.2}%", percent_change); // Verwende parametrisierte Queries für Sicherheit gegen SQL-Injection conn.prepare("update_money_event", QUERY_UPDATE_MONEY)?; let _ = conn.execute("update_money_event", &[&user_id, &change, &action])?; - // Best-effort money_history insert for UI/history visibility. - let money_str = format!("{:.2}", change); - fn escape_sql_literal(s: &str) -> String { s.replace('\'', "''") } - let escaped_action = escape_sql_literal(&action); + // money_history für UI/Verlauf: Betrag und Aktion zuverlässig speichern (parametrisiert). let create_sql = r#" CREATE TABLE IF NOT EXISTS falukant_log.money_history ( id BIGSERIAL PRIMARY KEY, @@ -1054,13 +1072,9 @@ impl EventsWorker { "#; let _ = conn.query(create_sql); - let history_sql = format!( - "INSERT INTO falukant_log.money_history (user_id, change, action, created_at) VALUES ({uid}, {money}::numeric, '{act}', NOW());", - uid = user_id, - money = money_str, - act = escaped_action - ); - if let Err(err) = conn.query(&history_sql) { + let money_str = format!("{:.2}", change); + let _ = conn.prepare("insert_money_history", QUERY_INSERT_MONEY_HISTORY); + if let Err(err) = conn.execute("insert_money_history", &[&user_id, &money_str, &action]) { eprintln!( "[EventsWorker] Warning: inserting money_history failed for user {}: {}", user_id, err diff --git a/src/worker/sql.rs b/src/worker/sql.rs index 30f8196..9a06469 100644 --- a/src/worker/sql.rs +++ b/src/worker/sql.rs @@ -4,6 +4,11 @@ pub const QUERY_UPDATE_MONEY: &str = r#" SELECT falukant_data.update_money($1, $2, $3); "#; +/// Insert in money_history für UI/Verlauf; Betrag als Parameter für zuverlässige Speicherung. +pub const QUERY_INSERT_MONEY_HISTORY: &str = r#" +INSERT INTO falukant_log.money_history (user_id, change, action, created_at) VALUES ($1, $2::numeric, $3, NOW()) +"#; + pub const QUERY_GET_MONEY: &str = r#" SELECT money FROM falukant_data.falukant_user WHERE id = $1; "#;