diff --git a/src/worker/events.rs b/src/worker/events.rs index b27d665..ffdfd10 100644 --- a/src/worker/events.rs +++ b/src/worker/events.rs @@ -49,6 +49,8 @@ pub enum EventEffect { storage_destruction_min_percent: f64, storage_destruction_max_percent: f64, }, + /// Änderung der Hausqualität (in Punkten, kann negativ sein) + HouseQualityChange { probability: f64, min_change: i32, max_change: i32 }, } /// Definition eines zufälligen Ereignisses @@ -154,6 +156,12 @@ impl EventsWorker { storage_destruction_min_percent: 0.0, storage_destruction_max_percent: 10.0, }, + // Verbleibende Lager können durch den Sturm beschädigt werden und Kapazität verlieren + EventEffect::StorageCapacityChange { + probability: 0.7, // 70% Chance, dass verbleibende Lager beschädigt werden + min_percent: -10.0, + max_percent: -3.0, + }, ], }, RandomEvent { @@ -200,9 +208,12 @@ impl EventsWorker { storage_destruction_min_percent: 0.0, storage_destruction_max_percent: 50.0, }, - // Für alle anderen Lagerarten: nur Lagerbestand kann zerstört werden - // (storage_destruction_max_percent = 0.0 bedeutet keine Lager-Zerstörung) - // Hinweis: Weitere Stock-Typen können hier hinzugefügt werden + // Verbleibende Lager können durch das Feuer beschädigt werden und Kapazität verlieren + EventEffect::StorageCapacityChange { + probability: 0.8, // 80% Chance, dass verbleibende Lager beschädigt werden + min_percent: -15.0, + max_percent: -5.0, + }, ], }, RandomEvent { @@ -283,6 +294,33 @@ impl EventsWorker { }, ], }, + RandomEvent { + id: "earthquake".to_string(), + probability_per_minute: 0.001, // 0.1% pro Minute (sehr selten) + event_type: EventType::Regional, + title: "Erdbeben".to_string(), + description: "Ein Erdbeben hat die Region erschüttert.".to_string(), + effects: vec![ + EventEffect::CharacterHealthChange { + probability: 0.3, // 30% Chance auf Gesundheitsschäden (geringe Wahrscheinlichkeit) + min_change: -20, + max_change: -5, + }, + EventEffect::CharacterDeath { + probability: 0.05, // 5% Chance auf Tod (sehr geringe Wahrscheinlichkeit) + }, + EventEffect::StorageCapacityChange { + probability: 1.0, // Alle Lager werden beschädigt + min_percent: -20.0, + max_percent: -5.0, + }, + EventEffect::HouseQualityChange { + probability: 1.0, // Alle Häuser werden beschädigt + min_change: -15, + max_change: -5, + }, + ], + }, ] } @@ -782,6 +820,46 @@ impl EventsWorker { } } } + EventEffect::StorageCapacityChange { + probability, + min_percent, + max_percent, + } => { + if effect_roll < *probability { + if let Ok(affected_stocks) = Self::apply_regional_storage_capacity_change( + &mut conn, + region_id, + *min_percent, + *max_percent, + rng, + ) { + effect_results.push(json!({ + "type": "storage_capacity_change", + "affected_stocks": affected_stocks, + })); + } + } + } + EventEffect::HouseQualityChange { + probability, + min_change, + max_change, + } => { + if effect_roll < *probability { + if let Ok(affected_houses) = Self::apply_regional_house_quality_change( + &mut conn, + region_id, + *min_change, + *max_change, + rng, + ) { + effect_results.push(json!({ + "type": "house_quality_change", + "affected_houses": affected_houses, + })); + } + } + } _ => { eprintln!( "[EventsWorker] Effekt {:?} wird für regionale Ereignisse noch nicht unterstützt", @@ -856,19 +934,209 @@ impl EventsWorker { } fn apply_storage_capacity_change( - _conn: &mut DbConnection, + conn: &mut DbConnection, user_id: i32, percent_change: f64, ) -> Result<(), DbError> { - // TODO: Implementierung für Lagerkapazitätsänderung - // Dies könnte eine temporäre Modifikation sein oder eine permanente Änderung + // Hole alle Stocks des Spielers + const QUERY_GET_USER_STOCKS: &str = r#" + SELECT s.id AS stock_id, s.quantity AS current_capacity + FROM falukant_data.stock s + JOIN falukant_data.branch b ON s.branch_id = b.id + WHERE b.falukant_user_id = $1; + "#; + + conn.prepare("get_user_stocks_capacity", QUERY_GET_USER_STOCKS)?; + let stock_rows = conn.execute("get_user_stocks_capacity", &[&user_id])?; + + if stock_rows.is_empty() { + eprintln!( + "[EventsWorker] Keine Stocks für Spieler {} gefunden", + user_id + ); + return Ok(()); + } + + // Reduziere die Kapazität aller Stocks + const QUERY_UPDATE_STOCK_CAPACITY: &str = r#" + UPDATE falukant_data.stock + SET quantity = GREATEST(1, ROUND(quantity * (1 + $1 / 100.0))) + WHERE id = $2; + "#; + + conn.prepare("update_stock_capacity", QUERY_UPDATE_STOCK_CAPACITY)?; + + let mut affected_stocks = 0; + for row in stock_rows { + let stock_id: Option = row + .get("stock_id") + .and_then(|v| v.parse::().ok()); + + let stock_id = match stock_id { + Some(id) => id, + None => continue, + }; + + let current_capacity: i32 = row + .get("current_capacity") + .and_then(|v| v.parse::().ok()) + .unwrap_or(0); + + if current_capacity > 0 { + conn.execute("update_stock_capacity", &[&percent_change, &stock_id])?; + affected_stocks += 1; + } + } + eprintln!( - "[EventsWorker] Lagerkapazitätsänderung für Spieler {}: {:.2}% (noch nicht implementiert)", - user_id, percent_change + "[EventsWorker] Lagerkapazitätsänderung für Spieler {}: {:.2}% bei {} Stocks", + user_id, percent_change, affected_stocks ); + Ok(()) } + fn apply_regional_storage_capacity_change( + conn: &mut DbConnection, + region_id: i32, + min_percent: f64, + max_percent: f64, + rng: &mut impl Rng, + ) -> Result { + // Hole alle Stocks in der Region + const QUERY_GET_REGION_STOCKS: &str = r#" + SELECT s.id AS stock_id, s.quantity AS current_capacity + FROM falukant_data.stock s + JOIN falukant_data.branch b ON s.branch_id = b.id + WHERE b.region_id = $1; + "#; + + conn.prepare("get_region_stocks_capacity", QUERY_GET_REGION_STOCKS)?; + let stock_rows = conn.execute("get_region_stocks_capacity", &[®ion_id])?; + + if stock_rows.is_empty() { + eprintln!( + "[EventsWorker] Keine Stocks in Region {} gefunden", + region_id + ); + return Ok(0); + } + + // Berechne die prozentuale Änderung + let percent_change = rng.gen_range(min_percent..=max_percent); + + // Reduziere die Kapazität aller Stocks + const QUERY_UPDATE_STOCK_CAPACITY_REGIONAL: &str = r#" + UPDATE falukant_data.stock + SET quantity = GREATEST(1, ROUND(quantity * (1 + $1 / 100.0))) + WHERE id = $2; + "#; + + conn.prepare("update_stock_capacity_regional", QUERY_UPDATE_STOCK_CAPACITY_REGIONAL)?; + + let mut affected_stocks = 0; + for row in stock_rows { + let stock_id: Option = row + .get("stock_id") + .and_then(|v| v.parse::().ok()); + + let stock_id = match stock_id { + Some(id) => id, + None => continue, + }; + + let current_capacity: i32 = row + .get("current_capacity") + .and_then(|v| v.parse::().ok()) + .unwrap_or(0); + + if current_capacity > 0 { + conn.execute("update_stock_capacity_regional", &[&percent_change, &stock_id])?; + affected_stocks += 1; + } + } + + eprintln!( + "[EventsWorker] Regionale Lagerkapazitätsänderung für Region {}: {:.2}% bei {} Stocks", + region_id, percent_change, affected_stocks + ); + + Ok(affected_stocks) + } + + fn apply_regional_house_quality_change( + conn: &mut DbConnection, + region_id: i32, + min_change: i32, + max_change: i32, + rng: &mut impl Rng, + ) -> Result { + // Hole alle Häuser in der Region + const QUERY_GET_REGION_HOUSES: &str = r#" + SELECT uh.id AS house_id, + uh.roof_condition, + uh.floor_condition, + uh.wall_condition, + uh.window_condition + FROM falukant_data.user_house uh + JOIN falukant_data.character c ON c.user_id = uh.user_id + WHERE c.region_id = $1 + AND uh.house_type_id NOT IN ( + SELECT id + FROM falukant_type.house h + WHERE h.label_tr = 'under_bridge' + ); + "#; + + conn.prepare("get_region_houses", QUERY_GET_REGION_HOUSES)?; + let house_rows = conn.execute("get_region_houses", &[®ion_id])?; + + if house_rows.is_empty() { + eprintln!( + "[EventsWorker] Keine Häuser in Region {} gefunden", + region_id + ); + return Ok(0); + } + + // Berechne die Änderung + let quality_change = rng.gen_range(min_change..=max_change); + + // Reduziere die Qualität aller Häuser + const QUERY_UPDATE_HOUSE_QUALITY: &str = r#" + UPDATE falukant_data.user_house + SET roof_condition = GREATEST(0, LEAST(100, roof_condition + $1)), + floor_condition = GREATEST(0, LEAST(100, floor_condition + $1)), + wall_condition = GREATEST(0, LEAST(100, wall_condition + $1)), + window_condition = GREATEST(0, LEAST(100, window_condition + $1)) + WHERE id = $2; + "#; + + conn.prepare("update_house_quality", QUERY_UPDATE_HOUSE_QUALITY)?; + + let mut affected_houses = 0; + for row in house_rows { + let house_id: Option = row + .get("house_id") + .and_then(|v| v.parse::().ok()); + + let house_id = match house_id { + Some(id) => id, + None => continue, + }; + + conn.execute("update_house_quality", &[&quality_change, &house_id])?; + affected_houses += 1; + } + + eprintln!( + "[EventsWorker] Regionale Hausqualitätsänderung für Region {}: {} Punkte bei {} Häusern", + region_id, quality_change, affected_houses + ); + + Ok(affected_houses) + } + fn apply_weather_change( conn: &mut DbConnection, region_id: i32,