From e553275b2e98ebdea557e57d08b69bf6d9acdf2a Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Fri, 17 Apr 2026 23:55:14 -0700 Subject: [PATCH] Rehost company management-attitude issue reader --- crates/rrt-runtime/src/lib.rs | 2 +- crates/rrt-runtime/src/runtime.rs | 110 ++++++++++++++++++++++++++++++ crates/rrt-runtime/src/step.rs | 94 ++++++++++++++++++++++++- 3 files changed, 203 insertions(+), 3 deletions(-) diff --git a/crates/rrt-runtime/src/lib.rs b/crates/rrt-runtime/src/lib.rs index 51454d4..571d77f 100644 --- a/crates/rrt-runtime/src/lib.rs +++ b/crates/rrt-runtime/src/lib.rs @@ -68,7 +68,7 @@ pub use runtime::{ runtime_company_annual_finance_state, runtime_company_assigned_share_pool, runtime_company_average_live_bond_coupon, runtime_company_book_value_per_share, runtime_company_credit_rating, runtime_company_investor_confidence, - runtime_company_market_value, runtime_company_prime_rate, + runtime_company_management_attitude, runtime_company_market_value, runtime_company_prime_rate, runtime_company_recent_per_share_subscore, runtime_company_stat_value, runtime_company_stat_value_f64, runtime_company_unassigned_share_pool, runtime_world_issue_opinion_multiplier, runtime_world_issue_opinion_term_sum_raw, diff --git a/crates/rrt-runtime/src/runtime.rs b/crates/rrt-runtime/src/runtime.rs index 64b93c5..ab21b3b 100644 --- a/crates/rrt-runtime/src/runtime.rs +++ b/crates/rrt-runtime/src/runtime.rs @@ -2145,6 +2145,23 @@ pub fn runtime_company_investor_confidence(state: &RuntimeState, company_id: u32 .and_then(runtime_round_f64_to_i64) } +pub fn runtime_company_management_attitude(state: &RuntimeState, company_id: u32) -> Option { + let company = state + .companies + .iter() + .find(|company| company.company_id == company_id)?; + if company.management_attitude != 0 { + return Some(company.management_attitude); + } + runtime_world_issue_opinion_term_sum_raw( + state, + RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE, + company.linked_chairman_profile_id, + Some(company_id), + None, + ) +} + fn runtime_company_control_transfer_stat_value_f64( state: &RuntimeState, company_id: u32, @@ -5157,6 +5174,99 @@ mod tests { ); } + #[test] + fn derives_company_management_attitude_from_issue3a_owner_state() { + let mut company_terms = vec![0; 0x3b]; + company_terms[RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE as usize] = 12; + let mut chairman_terms = vec![0; 0x3b]; + chairman_terms[RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE as usize] = 6; + let mut world_terms = vec![0; 0x3b]; + world_terms[RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE as usize] = 40; + + let state = RuntimeState { + calendar: CalendarPoint { + year: 1830, + month_slot: 0, + phase_slot: 0, + tick_slot: 0, + }, + world_flags: BTreeMap::new(), + save_profile: RuntimeSaveProfileState::default(), + world_restore: RuntimeWorldRestoreState::default(), + metadata: BTreeMap::new(), + companies: vec![RuntimeCompany { + company_id: 7, + current_cash: 0, + debt: 0, + credit_rating_score: None, + prime_rate: None, + active: true, + available_track_laying_capacity: None, + controller_kind: RuntimeCompanyControllerKind::Unknown, + linked_chairman_profile_id: Some(3), + book_value_per_share: 0, + investor_confidence: 0, + management_attitude: 0, + takeover_cooldown_year: None, + merger_cooldown_year: None, + track_piece_counts: RuntimeTrackPieceCounts::default(), + }], + selected_company_id: None, + players: Vec::new(), + selected_player_id: None, + chairman_profiles: vec![RuntimeChairmanProfile { + profile_id: 3, + name: "Chairman".to_string(), + active: true, + current_cash: 0, + linked_company_id: Some(7), + company_holdings: BTreeMap::new(), + holdings_value_total: 0, + net_worth_total: 0, + purchasing_power_total: 0, + }], + selected_chairman_profile_id: None, + trains: Vec::new(), + locomotive_catalog: Vec::new(), + cargo_catalog: Vec::new(), + territories: Vec::new(), + company_territory_track_piece_counts: Vec::new(), + company_territory_access: Vec::new(), + packed_event_collection: None, + event_runtime_records: Vec::new(), + candidate_availability: BTreeMap::new(), + named_locomotive_availability: BTreeMap::new(), + named_locomotive_cost: BTreeMap::new(), + all_cargo_price_override: None, + named_cargo_price_overrides: BTreeMap::new(), + all_cargo_production_override: None, + factory_cargo_production_override: None, + farm_mine_cargo_production_override: None, + named_cargo_production_overrides: BTreeMap::new(), + cargo_production_overrides: BTreeMap::new(), + world_runtime_variables: BTreeMap::new(), + company_runtime_variables: BTreeMap::new(), + player_runtime_variables: BTreeMap::new(), + territory_runtime_variables: BTreeMap::new(), + world_scalar_overrides: BTreeMap::new(), + special_conditions: BTreeMap::new(), + service_state: RuntimeServiceState { + world_issue_opinion_base_terms_raw_i32: world_terms, + company_market_state: BTreeMap::from([( + 7, + RuntimeCompanyMarketState { + issue_opinion_terms_raw_i32: company_terms, + ..RuntimeCompanyMarketState::default() + }, + )]), + chairman_issue_opinion_terms_raw_i32: BTreeMap::from([(3, chairman_terms)]), + ..RuntimeServiceState::default() + }, + }; + + assert_eq!(runtime_company_management_attitude(&state, 7), Some(58)); + } + #[test] fn reads_year_relative_company_stat_family_from_saved_market_matrix() { let mut year_stat_family_qword_bits = vec![ diff --git a/crates/rrt-runtime/src/step.rs b/crates/rrt-runtime/src/step.rs index aac487b..825a609 100644 --- a/crates/rrt-runtime/src/step.rs +++ b/crates/rrt-runtime/src/step.rs @@ -9,7 +9,8 @@ use crate::{ RuntimeEffect, RuntimeEventRecordTemplate, RuntimePlayerTarget, RuntimeState, RuntimeSummary, RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts, calendar::BoundaryEventKind, runtime_company_book_value_per_share, - runtime_company_credit_rating, runtime_company_investor_confidence, runtime_company_prime_rate, + runtime_company_credit_rating, runtime_company_investor_confidence, + runtime_company_management_attitude, runtime_company_prime_rate, }; const PERIODIC_TRIGGER_KIND_ORDER: [u8; 6] = [1, 0, 3, 2, 5, 4]; @@ -1529,7 +1530,9 @@ fn company_metric_value( RuntimeCompanyMetric::InvestorConfidence => { runtime_company_investor_confidence(state, company.company_id).unwrap_or(0) } - RuntimeCompanyMetric::ManagementAttitude => company.management_attitude, + RuntimeCompanyMetric::ManagementAttitude => { + runtime_company_management_attitude(state, company.company_id).unwrap_or(0) + } RuntimeCompanyMetric::TrackPiecesTotal => i64::from(company.track_piece_counts.total), RuntimeCompanyMetric::TrackPiecesSingle => i64::from(company.track_piece_counts.single), RuntimeCompanyMetric::TrackPiecesDouble => i64::from(company.track_piece_counts.double), @@ -4217,6 +4220,93 @@ mod tests { ); } + #[test] + fn derived_management_attitude_condition_reads_issue3a_owner_state() { + let mut issue_terms = vec![0; 0x3b]; + issue_terms[crate::RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE as usize] = 40; + let mut company_terms = vec![0; 0x3b]; + company_terms[crate::RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE as usize] = 12; + let mut chairman_terms = vec![0; 0x3b]; + chairman_terms[crate::RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE as usize] = 6; + + let mut state = RuntimeState { + companies: vec![RuntimeCompany { + company_id: 1, + controller_kind: RuntimeCompanyControllerKind::Human, + current_cash: 100, + debt: 0, + credit_rating_score: None, + prime_rate: None, + track_piece_counts: RuntimeTrackPieceCounts::default(), + active: true, + available_track_laying_capacity: None, + linked_chairman_profile_id: Some(3), + book_value_per_share: 2620, + investor_confidence: 0, + management_attitude: 0, + takeover_cooldown_year: Some(1844), + merger_cooldown_year: Some(1845), + }], + selected_company_id: Some(1), + chairman_profiles: vec![crate::RuntimeChairmanProfile { + profile_id: 3, + name: "Chairman".to_string(), + active: true, + current_cash: 0, + linked_company_id: Some(1), + company_holdings: BTreeMap::new(), + holdings_value_total: 0, + net_worth_total: 0, + purchasing_power_total: 0, + }], + service_state: RuntimeServiceState { + world_issue_opinion_base_terms_raw_i32: issue_terms, + company_market_state: BTreeMap::from([( + 1, + crate::RuntimeCompanyMarketState { + issue_opinion_terms_raw_i32: company_terms, + ..crate::RuntimeCompanyMarketState::default() + }, + )]), + chairman_issue_opinion_terms_raw_i32: BTreeMap::from([(3, chairman_terms)]), + ..RuntimeServiceState::default() + }, + event_runtime_records: vec![RuntimeEventRecord { + record_id: 196, + trigger_kind: 6, + active: true, + service_count: 0, + marks_collection_dirty: false, + one_shot: false, + has_fired: false, + conditions: vec![RuntimeCondition::CompanyNumericThreshold { + target: RuntimeCompanyTarget::SelectedCompany, + metric: crate::RuntimeCompanyMetric::ManagementAttitude, + comparator: RuntimeConditionComparator::Eq, + value: 58, + }], + effects: vec![RuntimeEffect::SetWorldFlag { + key: "world.derived_management_attitude_gate_passed".to_string(), + value: true, + }], + }], + ..state() + }; + + execute_step_command( + &mut state, + &StepCommand::ServiceTriggerKind { trigger_kind: 6 }, + ) + .expect("derived management-attitude company condition should gate execution"); + + assert_eq!( + state + .world_flags + .get("world.derived_management_attitude_gate_passed"), + Some(&true) + ); + } + #[test] fn book_value_condition_reads_rehosted_direct_company_field_band() { let mut state = RuntimeState {