diff --git a/src/worker/events.rs b/src/worker/events.rs index efe994c..c022f78 100644 --- a/src/worker/events.rs +++ b/src/worker/events.rs @@ -522,91 +522,18 @@ impl EventsWorker { max_percent, min_absolute_positive, } => { - if effect_roll < *probability { - let current_money = - Self::get_current_money(&mut conn, user_id).unwrap_or(0.0); - - // Spezialfall: Unerwarteter Geldsegen -> absoluter Zufallsbetrag 1..500 - if event.id == "windfall" { - let absolute_change: f64 = rng.gen_range(1.0..=500.0); - let percent_change = if current_money > 0.0 { - (absolute_change / current_money) * 100.0 - } else { - 0.0 - }; - - let applied_change = Self::apply_money_change( - &mut conn, - user_id, - percent_change, - Some(absolute_change), - ) - .unwrap_or(absolute_change); - - effect_results.push(json!({ - "type": "money_change", - "percent": percent_change, - "absolute": applied_change - })); - continue; - } - - // Spezialfall: Diebstahl -> Verlust > 0, max. 90% und mind. 20 Geld übrig - if event.id == "theft" { - // Wenn kaum Geld vorhanden ist, passiert nichts - if current_money <= 20.0 { - continue; - } - - let max_by_percent = current_money * 0.9; - let max_by_min_left = current_money - 20.0; - let max_loss = max_by_percent.min(max_by_min_left); - - if max_loss < 1.0 { - continue; - } - - let loss: f64 = rng.gen_range(1.0..=max_loss); - let percent_change = -(loss / current_money) * 100.0; - let absolute_change = -loss; - - let applied_change = Self::apply_money_change( - &mut conn, - user_id, - percent_change, - Some(absolute_change), - ) - .unwrap_or(absolute_change); - - effect_results.push(json!({ - "type": "money_change", - "percent": percent_change, - "absolute": applied_change - })); - continue; - } - - // Standardfall: prozentuale Änderung, optional mit Mindestbetrag für positive Änderungen - let percent_change = rng.gen_range(*min_percent..=*max_percent); - let computed_change = current_money * (percent_change / 100.0); - 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, - "absolute": absolute_change - })); + if let Some(effect_json) = Self::handle_money_change_effect( + &mut conn, + event, + user_id, + effect_roll, + *probability, + *min_percent, + *max_percent, + min_absolute_positive, + rng, + )? { + effect_results.push(effect_json); } } EventEffect::StorageCapacityChange { @@ -614,13 +541,16 @@ impl EventsWorker { min_percent, max_percent, } => { - if effect_roll < *probability { - let percent_change = rng.gen_range(*min_percent..=*max_percent); - Self::apply_storage_capacity_change(&mut conn, user_id, percent_change)?; - effect_results.push(json!({ - "type": "storage_capacity_change", - "percent": percent_change - })); + if let Some(effect_json) = Self::handle_personal_storage_capacity_effect( + &mut conn, + user_id, + effect_roll, + *probability, + *min_percent, + *max_percent, + rng, + )? { + effect_results.push(effect_json); } } EventEffect::CharacterHealthChange { @@ -628,32 +558,30 @@ impl EventsWorker { min_change, max_change, } => { - if effect_roll < *probability - && let Ok((character_id, health_change)) = Self::apply_character_health_change( - &mut conn, - user_id, - *min_change, - *max_change, - rng, - pool, - broker, - ) - { - effect_results.push(json!({ - "type": "character_health_change", - "character_id": character_id, - "change": health_change - })); + if let Some(effect_json) = Self::handle_personal_character_health_effect( + &mut conn, + user_id, + effect_roll, + *probability, + *min_change, + *max_change, + rng, + pool, + broker, + )? { + effect_results.push(effect_json); } } EventEffect::CharacterDeath { probability } => { - if effect_roll < *probability - && let Ok(character_id) = Self::apply_character_death(&mut conn, user_id, pool, broker) - { - effect_results.push(json!({ - "type": "character_death", - "character_id": character_id - })); + if let Some(effect_json) = Self::handle_personal_character_death_effect( + &mut conn, + user_id, + effect_roll, + *probability, + pool, + broker, + )? { + effect_results.push(effect_json); } } EventEffect::StorageDamage { @@ -664,28 +592,19 @@ impl EventsWorker { storage_destruction_min_percent, storage_destruction_max_percent, } => { - if effect_roll < *probability - && let Ok(damage_info) = Self::apply_personal_storage_damage( - &mut conn, - PersonalStorageDamageParams { - user_id, - stock_type_label, - inventory_damage_min_percent: *inventory_damage_min_percent, - inventory_damage_max_percent: *inventory_damage_max_percent, - storage_destruction_min_percent: *storage_destruction_min_percent, - storage_destruction_max_percent: *storage_destruction_max_percent, - }, - rng, - ) - { - effect_results.push(json!({ - "type": "storage_damage", - "stock_type": stock_type_label, - "inventory_damage_percent": damage_info.inventory_damage_percent, - "storage_destruction_percent": damage_info.storage_destruction_percent, - "affected_stocks": damage_info.affected_stocks, - "destroyed_stocks": damage_info.destroyed_stocks, - })); + if let Some(effect_json) = Self::handle_personal_storage_damage_effect( + &mut conn, + user_id, + stock_type_label, + *probability, + *inventory_damage_min_percent, + *inventory_damage_max_percent, + *storage_destruction_min_percent, + *storage_destruction_max_percent, + effect_roll, + rng, + )? { + effect_results.push(effect_json); } } _ => { @@ -960,28 +879,19 @@ impl EventsWorker { storage_destruction_min_percent, storage_destruction_max_percent, } => { - if effect_roll < *probability - && let Ok(damage_info) = Self::apply_storage_damage( - &mut conn, - StorageDamageParams { - region_id, - stock_type_label, - inventory_damage_min_percent: *inventory_damage_min_percent, - inventory_damage_max_percent: *inventory_damage_max_percent, - storage_destruction_min_percent: *storage_destruction_min_percent, - storage_destruction_max_percent: *storage_destruction_max_percent, - }, - rng, - ) - { - effect_results.push(json!({ - "type": "storage_damage", - "stock_type": stock_type_label, - "inventory_damage_percent": damage_info.inventory_damage_percent, - "storage_destruction_percent": damage_info.storage_destruction_percent, - "affected_stocks": damage_info.affected_stocks, - "destroyed_stocks": damage_info.destroyed_stocks, - })); + if let Some(effect_json) = Self::handle_regional_storage_damage_effect( + &mut conn, + region_id, + stock_type_label, + *probability, + *inventory_damage_min_percent, + *inventory_damage_max_percent, + *storage_destruction_min_percent, + *storage_destruction_max_percent, + effect_roll, + rng, + )? { + effect_results.push(effect_json); } } EventEffect::StorageCapacityChange { @@ -989,20 +899,16 @@ impl EventsWorker { min_percent, max_percent, } => { - if effect_roll < *probability - && let Ok((affected_stocks, percent_change)) = Self::apply_regional_storage_capacity_change( - &mut conn, - region_id, - *min_percent, - *max_percent, - rng, - ) - { - effect_results.push(json!({ - "type": "storage_capacity_change", - "percent": percent_change, - "affected_stocks": affected_stocks, - })); + if let Some(effect_json) = Self::handle_regional_storage_capacity_effect( + &mut conn, + region_id, + effect_roll, + *probability, + *min_percent, + *max_percent, + rng, + )? { + effect_results.push(effect_json); } } EventEffect::HouseQualityChange { @@ -1010,20 +916,16 @@ impl EventsWorker { min_change, max_change, } => { - if effect_roll < *probability - && let Ok((affected_houses, quality_change)) = Self::apply_regional_house_quality_change( - &mut conn, - region_id, - *min_change, - *max_change, - rng, - ) - { - effect_results.push(json!({ - "type": "house_quality_change", - "change": quality_change, - "affected_houses": affected_houses, - })); + if let Some(effect_json) = Self::handle_regional_house_quality_effect( + &mut conn, + region_id, + effect_roll, + *probability, + *min_change, + *max_change, + rng, + )? { + effect_results.push(effect_json); } } _ => { @@ -1347,6 +1249,323 @@ impl EventsWorker { Ok(()) } + /// Behandelt Geldänderungen für persönliche Events (inkl. Spezialfälle „windfall“ und „theft“). + fn handle_money_change_effect( + conn: &mut DbConnection, + event: &RandomEvent, + user_id: i32, + effect_roll: f64, + probability: f64, + min_percent: f64, + max_percent: f64, + min_absolute_positive: &Option, + rng: &mut impl Rng, + ) -> Result, DbError> { + if effect_roll >= probability { + return Ok(None); + } + + let current_money = Self::get_current_money(conn, user_id).unwrap_or(0.0); + + // Spezialfall: Unerwarteter Geldsegen -> absoluter Zufallsbetrag 1..500 + if event.id == "windfall" { + let absolute_change: f64 = rng.gen_range(1.0..=500.0); + let percent_change = if current_money > 0.0 { + (absolute_change / current_money) * 100.0 + } else { + 0.0 + }; + + let applied_change = Self::apply_money_change( + conn, + user_id, + percent_change, + Some(absolute_change), + ) + .unwrap_or(absolute_change); + + return Ok(Some(json!({ + "type": "money_change", + "percent": percent_change, + "absolute": applied_change + }))); + } + + // Spezialfall: Diebstahl -> Verlust > 0, max. 90% und mind. 20 Geld übrig + if event.id == "theft" { + // Wenn kaum Geld vorhanden ist, passiert nichts + if current_money <= 20.0 { + return Ok(None); + } + + let max_by_percent = current_money * 0.9; + let max_by_min_left = current_money - 20.0; + let max_loss = max_by_percent.min(max_by_min_left); + + if max_loss < 1.0 { + return Ok(None); + } + + let loss: f64 = rng.gen_range(1.0..=max_loss); + let percent_change = -(loss / current_money) * 100.0; + let absolute_change = -loss; + + let applied_change = Self::apply_money_change( + conn, + user_id, + percent_change, + Some(absolute_change), + ) + .unwrap_or(absolute_change); + + return Ok(Some(json!({ + "type": "money_change", + "percent": percent_change, + "absolute": applied_change + }))); + } + + // Standardfall: prozentuale Änderung, optional mit Mindestbetrag für positive Änderungen + let percent_change = rng.gen_range(min_percent..=max_percent); + let computed_change = current_money * (percent_change / 100.0); + 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( + conn, + user_id, + percent_change, + Some(effective_change), + ) + .unwrap_or(effective_change); + + Ok(Some(json!({ + "type": "money_change", + "percent": percent_change, + "absolute": absolute_change + }))) + } + + /// Behandelt Lagerkapazitätsänderungen für persönliche Events. + fn handle_personal_storage_capacity_effect( + conn: &mut DbConnection, + user_id: i32, + effect_roll: f64, + probability: f64, + min_percent: f64, + max_percent: f64, + rng: &mut impl Rng, + ) -> Result, DbError> { + if effect_roll >= probability { + return Ok(None); + } + + let percent_change = rng.gen_range(min_percent..=max_percent); + Self::apply_storage_capacity_change(conn, user_id, percent_change)?; + + Ok(Some(json!({ + "type": "storage_capacity_change", + "percent": percent_change + }))) + } + + /// Behandelt Gesundheitsänderungen bei persönlichen Events. + fn handle_personal_character_health_effect( + conn: &mut DbConnection, + user_id: i32, + effect_roll: f64, + probability: f64, + min_change: i32, + max_change: i32, + rng: &mut impl Rng, + pool: &ConnectionPool, + broker: &MessageBroker, + ) -> Result, DbError> { + if effect_roll >= probability { + return Ok(None); + } + + if let Ok((character_id, health_change)) = Self::apply_character_health_change( + conn, + user_id, + min_change, + max_change, + rng, + pool, + broker, + ) { + return Ok(Some(json!({ + "type": "character_health_change", + "character_id": character_id, + "change": health_change + }))); + } + + Ok(None) + } + + /// Behandelt Charakter-Tod bei persönlichen Events. + fn handle_personal_character_death_effect( + conn: &mut DbConnection, + user_id: i32, + effect_roll: f64, + probability: f64, + pool: &ConnectionPool, + broker: &MessageBroker, + ) -> Result, DbError> { + if effect_roll >= probability { + return Ok(None); + } + + if let Ok(character_id) = Self::apply_character_death(conn, user_id, pool, broker) { + return Ok(Some(json!({ + "type": "character_death", + "character_id": character_id + }))); + } + + Ok(None) + } + + /// Behandelt persönliche Lager-Schäden. + fn handle_personal_storage_damage_effect( + conn: &mut DbConnection, + user_id: i32, + stock_type_label: &str, + probability: f64, + inventory_damage_min_percent: f64, + inventory_damage_max_percent: f64, + storage_destruction_min_percent: f64, + storage_destruction_max_percent: f64, + effect_roll: f64, + rng: &mut impl Rng, + ) -> Result, DbError> { + if effect_roll >= probability { + return Ok(None); + } + + if let Ok(damage_info) = Self::apply_personal_storage_damage( + conn, + PersonalStorageDamageParams { + user_id, + stock_type_label, + inventory_damage_min_percent, + inventory_damage_max_percent, + storage_destruction_min_percent, + storage_destruction_max_percent, + }, + rng, + ) { + return Ok(Some(json!({ + "type": "storage_damage", + "stock_type": stock_type_label, + "inventory_damage_percent": damage_info.inventory_damage_percent, + "storage_destruction_percent": damage_info.storage_destruction_percent, + "affected_stocks": damage_info.affected_stocks, + "destroyed_stocks": damage_info.destroyed_stocks, + }))); + } + + Ok(None) + } + + /// Behandelt regionale Lager-Schäden. + fn handle_regional_storage_damage_effect( + conn: &mut DbConnection, + region_id: i32, + stock_type_label: &str, + probability: f64, + inventory_damage_min_percent: f64, + inventory_damage_max_percent: f64, + storage_destruction_min_percent: f64, + storage_destruction_max_percent: f64, + effect_roll: f64, + rng: &mut impl Rng, + ) -> Result, DbError> { + if effect_roll >= probability { + return Ok(None); + } + + if let Ok(damage_info) = Self::apply_storage_damage( + conn, + StorageDamageParams { + region_id, + stock_type_label, + inventory_damage_min_percent, + inventory_damage_max_percent, + storage_destruction_min_percent, + storage_destruction_max_percent, + }, + rng, + ) { + return Ok(Some(json!({ + "type": "storage_damage", + "stock_type": stock_type_label, + "inventory_damage_percent": damage_info.inventory_damage_percent, + "storage_destruction_percent": damage_info.storage_destruction_percent, + "affected_stocks": damage_info.affected_stocks, + "destroyed_stocks": damage_info.destroyed_stocks, + }))); + } + + Ok(None) + } + + /// Behandelt regionale Lagerkapazitätsänderungen. + fn handle_regional_storage_capacity_effect( + conn: &mut DbConnection, + region_id: i32, + effect_roll: f64, + probability: f64, + min_percent: f64, + max_percent: f64, + rng: &mut impl Rng, + ) -> Result, DbError> { + if effect_roll >= probability { + return Ok(None); + } + + if let Ok((affected_stocks, percent_change)) = + Self::apply_regional_storage_capacity_change(conn, region_id, min_percent, max_percent, rng) + { + return Ok(Some(json!({ + "type": "storage_capacity_change", + "percent": percent_change, + "affected_stocks": affected_stocks, + }))); + } + + Ok(None) + } + + /// Behandelt regionale Hausqualitätsänderungen. + fn handle_regional_house_quality_effect( + conn: &mut DbConnection, + region_id: i32, + effect_roll: f64, + probability: f64, + min_change: i32, + max_change: i32, + rng: &mut impl Rng, + ) -> Result, DbError> { + if effect_roll >= probability { + return Ok(None); + } + + if let Ok((affected_houses, quality_change)) = + Self::apply_regional_house_quality_change(conn, region_id, min_change, max_change, rng) + { + return Ok(Some(json!({ + "type": "house_quality_change", + "change": quality_change, + "affected_houses": affected_houses, + }))); + } + + Ok(None) + } + fn apply_character_health_change( conn: &mut DbConnection, user_id: i32,