Rehost periodic route preference service seam

This commit is contained in:
Jan Petykiewicz 2026-04-18 07:42:59 -07:00
commit f7fde709f7
9 changed files with 578 additions and 49 deletions

View file

@ -141,6 +141,9 @@ shellless repayment and bond-burden simulation instead of another round of raw-s
The same save-native company direct-record seam now also carries the full outer periodic-company The same save-native company direct-record seam now also carries the full outer periodic-company
side-latch trio rooted at `0x0d17/0x0d18/0x0d56`, including the preferred-locomotive engine-type side-latch trio rooted at `0x0d17/0x0d18/0x0d56`, including the preferred-locomotive engine-type
chooser byte that sits beside the city-connection and linked-transit finance gates. chooser byte that sits beside the city-connection and linked-transit finance gates.
That same seam now also resolves the base world route-preference byte at `[world+0x4c74]`, the
effective electric-only override fed by `0x0d17`, and the matching `1.4x` versus `1.8x`
route-quality multiplier as a normal runtime reader instead of leaving that bridge in atlas notes.
That same seam now also derives the current live coupon burden directly from owned bond slots, so That same seam now also derives the current live coupon burden directly from owned bond slots, so
later finance service work can consume a runtime reader instead of recomputing from scattered raw later finance service work can consume a runtime reader instead of recomputing from scattered raw
fields. fields.

View file

@ -855,6 +855,34 @@ fn project_save_slice_components(
.as_ref() .as_ref()
.and_then(|state| state.linked_site_removal_follow_on_gate_raw_u8) .and_then(|state| state.linked_site_removal_follow_on_gate_raw_u8)
.map(|raw| raw != 0), .map(|raw| raw != 0),
auto_show_grade_during_track_lay_raw_u8: save_slice
.world_locomotive_policy_state
.as_ref()
.and_then(|state| state.auto_show_grade_during_track_lay_raw_u8),
starting_building_density_level_raw_u8: save_slice
.world_locomotive_policy_state
.as_ref()
.and_then(|state| state.starting_building_density_level_raw_u8),
post_text_building_density_growth_raw_u8: save_slice
.world_locomotive_policy_state
.as_ref()
.and_then(|state| state.building_density_growth_raw_u8),
leftover_simulation_time_accumulator_raw_u32: save_slice
.world_locomotive_policy_state
.as_ref()
.and_then(|state| state.leftover_simulation_time_accumulator_raw_u32),
leftover_simulation_time_accumulator_value_f32_text: save_slice
.world_locomotive_policy_state
.as_ref()
.and_then(|state| {
state
.leftover_simulation_time_accumulator_value_f32_text
.clone()
}),
selected_year_lane_snapshot_raw_u8: save_slice
.world_locomotive_policy_state
.as_ref()
.and_then(|state| state.selected_year_lane_snapshot_raw_u8),
all_steam_locomotives_available_raw_u8: save_slice all_steam_locomotives_available_raw_u8: save_slice
.world_locomotive_policy_state .world_locomotive_policy_state
.as_ref() .as_ref()
@ -6191,6 +6219,17 @@ mod tests {
selected_year_gap_scalar_value_f32_text: Some("0.333333".to_string()), selected_year_gap_scalar_value_f32_text: Some("0.333333".to_string()),
linked_site_removal_follow_on_gate_raw_u8: Some(1), linked_site_removal_follow_on_gate_raw_u8: Some(1),
linked_site_removal_follow_on_gate_raw_hex: Some("0x01".to_string()), linked_site_removal_follow_on_gate_raw_hex: Some("0x01".to_string()),
auto_show_grade_during_track_lay_raw_u8: Some(2),
auto_show_grade_during_track_lay_raw_hex: Some("0x02".to_string()),
starting_building_density_level_raw_u8: Some(3),
starting_building_density_level_raw_hex: Some("0x03".to_string()),
building_density_growth_raw_u8: Some(1),
building_density_growth_raw_hex: Some("0x01".to_string()),
leftover_simulation_time_accumulator_raw_u32: Some(0x3f000000),
leftover_simulation_time_accumulator_raw_hex: Some("0x3f000000".to_string()),
leftover_simulation_time_accumulator_value_f32_text: Some("0.500000".to_string()),
selected_year_lane_snapshot_raw_u8: Some(7),
selected_year_lane_snapshot_raw_hex: Some("0x07".to_string()),
all_steam_locomotives_available_raw_u8: Some(1), all_steam_locomotives_available_raw_u8: Some(1),
all_steam_locomotives_available_raw_hex: Some("0x01".to_string()), all_steam_locomotives_available_raw_hex: Some("0x01".to_string()),
all_diesel_locomotives_available_raw_u8: Some(0), all_diesel_locomotives_available_raw_u8: Some(0),
@ -6368,6 +6407,49 @@ mod tests {
.absolute_counter_reconstructible_from_save, .absolute_counter_reconstructible_from_save,
Some(true) Some(true)
); );
assert_eq!(
import
.state
.world_restore
.auto_show_grade_during_track_lay_raw_u8,
Some(2)
);
assert_eq!(
import
.state
.world_restore
.starting_building_density_level_raw_u8,
Some(3)
);
assert_eq!(
import
.state
.world_restore
.post_text_building_density_growth_raw_u8,
Some(1)
);
assert_eq!(
import
.state
.world_restore
.leftover_simulation_time_accumulator_raw_u32,
Some(0x3f000000)
);
assert_eq!(
import
.state
.world_restore
.leftover_simulation_time_accumulator_value_f32_text
.as_deref(),
Some("0.500000")
);
assert_eq!(
import
.state
.world_restore
.selected_year_lane_snapshot_raw_u8,
Some(7)
);
assert_eq!( assert_eq!(
import.state.world_restore.packed_year_word_raw_u16, import.state.world_restore.packed_year_word_raw_u16,
Some(0x0201) Some(0x0201)

View file

@ -58,18 +58,19 @@ pub use runtime::{
RuntimeCompanyAnnualFinanceState, RuntimeCompanyAnnualStockIssueState, RuntimeCompanyAnnualFinanceState, RuntimeCompanyAnnualStockIssueState,
RuntimeCompanyAnnualStockRepurchaseState, RuntimeCompanyBondSlot, RuntimeCompanyAnnualStockRepurchaseState, RuntimeCompanyBondSlot,
RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind, RuntimeCompanyMarketMetric, RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind, RuntimeCompanyMarketMetric,
RuntimeCompanyMarketState, RuntimeCompanyMetric, RuntimeCompanyPeriodicSideLatchState, RuntimeCompanyMarketState, RuntimeCompanyMetric, RuntimeCompanyPeriodicServiceState,
RuntimeCompanyStatBandCandidate, RuntimeCompanyStatSelector, RuntimeCompanyTarget, RuntimeCompanyPeriodicSideLatchState, RuntimeCompanyStatBandCandidate,
RuntimeCompanyTerritoryAccess, RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition, RuntimeCompanyStatSelector, RuntimeCompanyTarget, RuntimeCompanyTerritoryAccess,
RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate, RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition, RuntimeConditionComparator,
RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate, RuntimeLocomotiveCatalogEntry,
RuntimePackedEventCompactControlSummary, RuntimePackedEventConditionRowSummary, RuntimePackedEventCollectionSummary, RuntimePackedEventCompactControlSummary,
RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventNegativeSentinelScopeSummary, RuntimePackedEventConditionRowSummary, RuntimePackedEventGroupedEffectRowSummary,
RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary, RuntimePlayer, RuntimePackedEventNegativeSentinelScopeSummary, RuntimePackedEventRecordSummary,
RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeSaveProfileState, RuntimePackedEventTextBandSummary, RuntimePlayer, RuntimePlayerConditionTestScope,
RuntimeServiceState, RuntimeState, RuntimeTerritory, RuntimeTerritoryMetric, RuntimePlayerTarget, RuntimeSaveProfileState, RuntimeServiceState, RuntimeState,
RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts, RuntimeTrain, RuntimeTerritory, RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric,
RuntimeWorldFinanceNeighborhoodCandidate, RuntimeWorldIssueState, RuntimeWorldRestoreState, RuntimeTrackPieceCounts, RuntimeTrain, RuntimeWorldFinanceNeighborhoodCandidate,
RuntimeWorldIssueState, RuntimeWorldRestoreState,
runtime_annual_bond_principal_flow_relation_label, runtime_annual_bond_principal_flow_relation_label,
runtime_annual_finance_news_family_candidate_label, runtime_company_annual_bond_policy_state, runtime_annual_finance_news_family_candidate_label, runtime_company_annual_bond_policy_state,
runtime_company_annual_creditor_pressure_state, runtime_company_annual_deep_distress_state, runtime_company_annual_creditor_pressure_state, runtime_company_annual_deep_distress_state,
@ -80,14 +81,15 @@ pub use runtime::{
runtime_company_assigned_share_pool, runtime_company_average_live_bond_coupon, runtime_company_assigned_share_pool, runtime_company_average_live_bond_coupon,
runtime_company_book_value_per_share, runtime_company_credit_rating, runtime_company_book_value_per_share, runtime_company_credit_rating,
runtime_company_investor_confidence, runtime_company_management_attitude, runtime_company_investor_confidence, runtime_company_management_attitude,
runtime_company_market_value, runtime_company_prime_rate, runtime_company_market_value, runtime_company_periodic_service_state,
runtime_company_recent_per_share_subscore, runtime_company_stat_value, runtime_company_prime_rate, runtime_company_recent_per_share_subscore,
runtime_company_stat_value_f64, runtime_company_unassigned_share_pool, runtime_company_stat_value, runtime_company_stat_value_f64,
runtime_world_annual_finance_mode_active, runtime_world_bankruptcy_allowed, runtime_company_unassigned_share_pool, runtime_world_annual_finance_mode_active,
runtime_world_bond_issue_and_repayment_allowed, runtime_world_building_density_growth_setting, runtime_world_bankruptcy_allowed, runtime_world_bond_issue_and_repayment_allowed,
runtime_world_dividend_adjustment_allowed, runtime_world_issue_opinion_multiplier, runtime_world_building_density_growth_setting, runtime_world_dividend_adjustment_allowed,
runtime_world_issue_opinion_term_sum_raw, runtime_world_issue_state, runtime_world_issue_opinion_multiplier, runtime_world_issue_opinion_term_sum_raw,
runtime_world_prime_rate_baseline, runtime_world_stock_issue_and_buyback_allowed, runtime_world_issue_state, runtime_world_prime_rate_baseline,
runtime_world_stock_issue_and_buyback_allowed,
}; };
pub use smp::{ pub use smp::{
SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION, SmpAlignedRuntimeRuleBandLane, SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION, SmpAlignedRuntimeRuleBandLane,

View file

@ -194,6 +194,21 @@ pub struct RuntimeCompanyPeriodicSideLatchState {
pub linked_transit_latch: bool, pub linked_transit_latch: bool,
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeCompanyPeriodicServiceState {
pub company_id: u32,
#[serde(default)]
pub preferred_locomotive_engine_type_raw_u8: Option<u8>,
pub city_connection_latch: bool,
pub linked_transit_latch: bool,
#[serde(default)]
pub base_route_preference_raw_u8: Option<u8>,
#[serde(default)]
pub effective_route_preference_raw_u8: Option<u8>,
pub electric_route_preference_override_active: bool,
pub effective_route_quality_multiplier_basis_points: i64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeCompanyAnnualCreditorPressureState { pub struct RuntimeCompanyAnnualCreditorPressureState {
pub company_id: u32, pub company_id: u32,
@ -1377,6 +1392,18 @@ pub struct RuntimeWorldRestoreState {
#[serde(default)] #[serde(default)]
pub linked_site_removal_follow_on_gate_enabled: Option<bool>, pub linked_site_removal_follow_on_gate_enabled: Option<bool>,
#[serde(default)] #[serde(default)]
pub auto_show_grade_during_track_lay_raw_u8: Option<u8>,
#[serde(default)]
pub starting_building_density_level_raw_u8: Option<u8>,
#[serde(default)]
pub post_text_building_density_growth_raw_u8: Option<u8>,
#[serde(default)]
pub leftover_simulation_time_accumulator_raw_u32: Option<u32>,
#[serde(default)]
pub leftover_simulation_time_accumulator_value_f32_text: Option<String>,
#[serde(default)]
pub selected_year_lane_snapshot_raw_u8: Option<u8>,
#[serde(default)]
pub all_steam_locomotives_available_raw_u8: Option<u8>, pub all_steam_locomotives_available_raw_u8: Option<u8>,
#[serde(default)] #[serde(default)]
pub all_steam_locomotives_available_enabled: Option<bool>, pub all_steam_locomotives_available_enabled: Option<bool>,
@ -4523,10 +4550,7 @@ pub fn runtime_company_annual_finance_state(
company_id: u32, company_id: u32,
) -> Option<RuntimeCompanyAnnualFinanceState> { ) -> Option<RuntimeCompanyAnnualFinanceState> {
let market_state = state.service_state.company_market_state.get(&company_id)?; let market_state = state.service_state.company_market_state.get(&company_id)?;
let periodic_side_latch_state = state let periodic_service_state = runtime_company_periodic_service_state(state, company_id);
.service_state
.company_periodic_side_latch_state
.get(&company_id);
let assigned_share_pool = runtime_company_assigned_share_pool(state, company_id)?; let assigned_share_pool = runtime_company_assigned_share_pool(state, company_id)?;
let unassigned_share_pool = runtime_company_unassigned_share_pool(state, company_id)?; let unassigned_share_pool = runtime_company_unassigned_share_pool(state, company_id)?;
let years_since_founding = let years_since_founding =
@ -4601,14 +4625,61 @@ pub fn runtime_company_annual_finance_state(
current_issue_calendar_word_2: market_state.current_issue_calendar_word_2, current_issue_calendar_word_2: market_state.current_issue_calendar_word_2,
prior_issue_calendar_word: market_state.prior_issue_calendar_word, prior_issue_calendar_word: market_state.prior_issue_calendar_word,
prior_issue_calendar_word_2: market_state.prior_issue_calendar_word_2, prior_issue_calendar_word_2: market_state.prior_issue_calendar_word_2,
preferred_locomotive_engine_type_raw_u8: periodic_side_latch_state preferred_locomotive_engine_type_raw_u8: periodic_service_state
.and_then(|latch_state| latch_state.preferred_locomotive_engine_type_raw_u8), .as_ref()
.and_then(|service_state| service_state.preferred_locomotive_engine_type_raw_u8),
city_connection_latch: periodic_service_state
.as_ref()
.map(|service_state| service_state.city_connection_latch)
.unwrap_or(market_state.city_connection_latch),
linked_transit_latch: periodic_service_state
.as_ref()
.map(|service_state| service_state.linked_transit_latch)
.unwrap_or(market_state.linked_transit_latch),
})
}
pub fn runtime_company_periodic_service_state(
state: &RuntimeState,
company_id: u32,
) -> Option<RuntimeCompanyPeriodicServiceState> {
const DEFAULT_ROUTE_QUALITY_MULTIPLIER_BASIS_POINTS: i64 = 140;
const ELECTRIC_ROUTE_QUALITY_MULTIPLIER_BASIS_POINTS: i64 = 180;
const ELECTRIC_ENGINE_TYPE_RAW_U8: u8 = 2;
let market_state = state.service_state.company_market_state.get(&company_id)?;
let periodic_side_latch_state = state
.service_state
.company_periodic_side_latch_state
.get(&company_id);
let preferred_locomotive_engine_type_raw_u8 = periodic_side_latch_state
.and_then(|latch_state| latch_state.preferred_locomotive_engine_type_raw_u8);
let base_route_preference_raw_u8 = state.world_restore.auto_show_grade_during_track_lay_raw_u8;
let electric_route_preference_override_active =
preferred_locomotive_engine_type_raw_u8 == Some(ELECTRIC_ENGINE_TYPE_RAW_U8);
let effective_route_preference_raw_u8 = if electric_route_preference_override_active {
Some(ELECTRIC_ENGINE_TYPE_RAW_U8)
} else {
base_route_preference_raw_u8
};
Some(RuntimeCompanyPeriodicServiceState {
company_id,
preferred_locomotive_engine_type_raw_u8,
city_connection_latch: periodic_side_latch_state city_connection_latch: periodic_side_latch_state
.map(|latch_state| latch_state.city_connection_latch) .map(|latch_state| latch_state.city_connection_latch)
.unwrap_or(market_state.city_connection_latch), .unwrap_or(market_state.city_connection_latch),
linked_transit_latch: periodic_side_latch_state linked_transit_latch: periodic_side_latch_state
.map(|latch_state| latch_state.linked_transit_latch) .map(|latch_state| latch_state.linked_transit_latch)
.unwrap_or(market_state.linked_transit_latch), .unwrap_or(market_state.linked_transit_latch),
base_route_preference_raw_u8,
effective_route_preference_raw_u8,
electric_route_preference_override_active,
effective_route_quality_multiplier_basis_points:
if electric_route_preference_override_active {
ELECTRIC_ROUTE_QUALITY_MULTIPLIER_BASIS_POINTS
} else {
DEFAULT_ROUTE_QUALITY_MULTIPLIER_BASIS_POINTS
},
}) })
} }
@ -5259,6 +5330,12 @@ mod tests {
territory_access_cost: None, territory_access_cost: None,
linked_site_removal_follow_on_gate_raw_u8: None, linked_site_removal_follow_on_gate_raw_u8: None,
linked_site_removal_follow_on_gate_enabled: None, linked_site_removal_follow_on_gate_enabled: None,
auto_show_grade_during_track_lay_raw_u8: None,
starting_building_density_level_raw_u8: None,
post_text_building_density_growth_raw_u8: None,
leftover_simulation_time_accumulator_raw_u32: None,
leftover_simulation_time_accumulator_value_f32_text: None,
selected_year_lane_snapshot_raw_u8: None,
all_steam_locomotives_available_raw_u8: None, all_steam_locomotives_available_raw_u8: None,
all_steam_locomotives_available_enabled: None, all_steam_locomotives_available_enabled: None,
all_diesel_locomotives_available_raw_u8: None, all_diesel_locomotives_available_raw_u8: None,
@ -8865,6 +8942,195 @@ mod tests {
assert_eq!(runtime_company_annual_finance_state(&state, 99), None); assert_eq!(runtime_company_annual_finance_state(&state, 99), None);
} }
#[test]
fn derives_company_periodic_service_state_from_side_latches_and_world_route_preference() {
let state = RuntimeState {
calendar: CalendarPoint {
year: 1845,
month_slot: 0,
phase_slot: 0,
tick_slot: 0,
},
world_flags: BTreeMap::new(),
save_profile: RuntimeSaveProfileState::default(),
world_restore: RuntimeWorldRestoreState {
auto_show_grade_during_track_lay_raw_u8: Some(1),
..RuntimeWorldRestoreState::default()
},
metadata: BTreeMap::new(),
companies: vec![RuntimeCompany {
company_id: 4,
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: None,
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: Some(4),
players: Vec::new(),
selected_player_id: None,
chairman_profiles: Vec::new(),
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 {
company_market_state: BTreeMap::from([(
4,
RuntimeCompanyMarketState {
city_connection_latch: true,
linked_transit_latch: false,
..RuntimeCompanyMarketState::default()
},
)]),
company_periodic_side_latch_state: BTreeMap::from([(
4,
RuntimeCompanyPeriodicSideLatchState {
preferred_locomotive_engine_type_raw_u8: Some(2),
city_connection_latch: false,
linked_transit_latch: true,
},
)]),
..RuntimeServiceState::default()
},
};
assert_eq!(
runtime_company_periodic_service_state(&state, 4),
Some(RuntimeCompanyPeriodicServiceState {
company_id: 4,
preferred_locomotive_engine_type_raw_u8: Some(2),
city_connection_latch: false,
linked_transit_latch: true,
base_route_preference_raw_u8: Some(1),
effective_route_preference_raw_u8: Some(2),
electric_route_preference_override_active: true,
effective_route_quality_multiplier_basis_points: 180,
})
);
assert_eq!(runtime_company_periodic_service_state(&state, 99), None);
}
#[test]
fn periodic_service_state_falls_back_to_market_latches_and_world_base_route_preference() {
let state = RuntimeState {
calendar: CalendarPoint {
year: 1845,
month_slot: 0,
phase_slot: 0,
tick_slot: 0,
},
world_flags: BTreeMap::new(),
save_profile: RuntimeSaveProfileState::default(),
world_restore: RuntimeWorldRestoreState {
auto_show_grade_during_track_lay_raw_u8: Some(3),
..RuntimeWorldRestoreState::default()
},
metadata: BTreeMap::new(),
companies: vec![RuntimeCompany {
company_id: 8,
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: None,
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: Some(8),
players: Vec::new(),
selected_player_id: None,
chairman_profiles: Vec::new(),
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 {
company_market_state: BTreeMap::from([(
8,
RuntimeCompanyMarketState {
city_connection_latch: true,
linked_transit_latch: false,
..RuntimeCompanyMarketState::default()
},
)]),
..RuntimeServiceState::default()
},
};
assert_eq!(
runtime_company_periodic_service_state(&state, 8),
Some(RuntimeCompanyPeriodicServiceState {
company_id: 8,
preferred_locomotive_engine_type_raw_u8: None,
city_connection_latch: true,
linked_transit_latch: false,
base_route_preference_raw_u8: Some(3),
effective_route_preference_raw_u8: Some(3),
electric_route_preference_override_active: false,
effective_route_quality_multiplier_basis_points: 140,
})
);
}
#[test] #[test]
fn derives_annual_creditor_pressure_from_rehosted_finance_owner_state() { fn derives_annual_creditor_pressure_from_rehosted_finance_owner_state() {
let mut year_stat_family_qword_bits = vec![ let mut year_stat_family_qword_bits = vec![

View file

@ -2304,6 +2304,28 @@ pub struct SmpLoadedWorldLocomotivePolicyState {
#[serde(default)] #[serde(default)]
pub linked_site_removal_follow_on_gate_raw_hex: Option<String>, pub linked_site_removal_follow_on_gate_raw_hex: Option<String>,
#[serde(default)] #[serde(default)]
pub auto_show_grade_during_track_lay_raw_u8: Option<u8>,
#[serde(default)]
pub auto_show_grade_during_track_lay_raw_hex: Option<String>,
#[serde(default)]
pub starting_building_density_level_raw_u8: Option<u8>,
#[serde(default)]
pub starting_building_density_level_raw_hex: Option<String>,
#[serde(default)]
pub building_density_growth_raw_u8: Option<u8>,
#[serde(default)]
pub building_density_growth_raw_hex: Option<String>,
#[serde(default)]
pub leftover_simulation_time_accumulator_raw_u32: Option<u32>,
#[serde(default)]
pub leftover_simulation_time_accumulator_raw_hex: Option<String>,
#[serde(default)]
pub leftover_simulation_time_accumulator_value_f32_text: Option<String>,
#[serde(default)]
pub selected_year_lane_snapshot_raw_u8: Option<u8>,
#[serde(default)]
pub selected_year_lane_snapshot_raw_hex: Option<String>,
#[serde(default)]
pub all_steam_locomotives_available_raw_u8: Option<u8>, pub all_steam_locomotives_available_raw_u8: Option<u8>,
#[serde(default)] #[serde(default)]
pub all_steam_locomotives_available_raw_hex: Option<String>, pub all_steam_locomotives_available_raw_hex: Option<String>,
@ -2932,10 +2954,10 @@ pub fn load_save_slice_from_report(
.save_world_finance_neighborhood_probe .save_world_finance_neighborhood_probe
.as_ref() .as_ref()
.map(derive_loaded_world_finance_neighborhood_state_from_probe); .map(derive_loaded_world_finance_neighborhood_state_from_probe);
let world_locomotive_policy_state = report let world_locomotive_policy_state = derive_loaded_world_locomotive_policy_state_from_probes(
.locomotive_policy_neighborhood_probe report.post_text_field_neighborhood_probe.as_ref(),
.as_ref() report.locomotive_policy_neighborhood_probe.as_ref(),
.map(derive_loaded_world_locomotive_policy_state_from_probe); );
let company_roster = report.save_company_roster_probe.clone().or_else(|| { let company_roster = report.save_company_roster_probe.clone().or_else(|| {
report report
.save_world_selection_context_probe .save_world_selection_context_probe
@ -3638,23 +3660,37 @@ fn derive_loaded_world_finance_neighborhood_state_from_probe(
} }
} }
fn derive_loaded_world_locomotive_policy_state_from_probe( fn derive_loaded_world_locomotive_policy_state_from_probes(
probe: &SmpLocomotivePolicyNeighborhoodProbe, post_text_probe: Option<&SmpPostTextFieldNeighborhoodProbe>,
) -> SmpLoadedWorldLocomotivePolicyState { locomotive_policy_probe: Option<&SmpLocomotivePolicyNeighborhoodProbe>,
) -> Option<SmpLoadedWorldLocomotivePolicyState> {
let field_by_name = |name: &str| { let field_by_name = |name: &str| {
probe locomotive_policy_probe?
.grounded_field_observations
.iter()
.find(|field| field.field_name == name)
};
let post_text_field_by_name = |name: &str| {
post_text_probe?
.grounded_field_observations .grounded_field_observations
.iter() .iter()
.find(|field| field.field_name == name) .find(|field| field.field_name == name)
}; };
let selected_year_gap_scalar = field_by_name("selected-year bucket companion scalar"); let selected_year_gap_scalar = field_by_name("selected-year bucket companion scalar");
let linked_site_gate = field_by_name("linked-site removal follow-on gate"); let linked_site_gate = field_by_name("linked-site removal follow-on gate");
let auto_show_grade = post_text_field_by_name("Auto-Show Grade During Track Lay");
let starting_building_density = post_text_field_by_name("Starting Building Density Level");
let building_density_growth = post_text_field_by_name("Building Density Growth");
let leftover_simulation_time = post_text_field_by_name("leftover simulation time accumulator");
let selected_year_snapshot = post_text_field_by_name("selected-year lane snapshot");
let all_steam = field_by_name("All Steam Locos Avail."); let all_steam = field_by_name("All Steam Locos Avail.");
let all_diesel = field_by_name("All Diesel Locos Avail."); let all_diesel = field_by_name("All Diesel Locos Avail.");
let all_electric = field_by_name("All Electric Locos Avail."); let all_electric = field_by_name("All Electric Locos Avail.");
let cached_available_rating = field_by_name("cached available-locomotive rating"); let cached_available_rating = field_by_name("cached available-locomotive rating");
SmpLoadedWorldLocomotivePolicyState { Some(SmpLoadedWorldLocomotivePolicyState {
source_kind: probe.source_kind.clone(), source_kind: locomotive_policy_probe
.map(|probe| probe.source_kind.clone())
.or_else(|| post_text_probe.map(|probe| probe.source_kind.clone()))?,
semantic_family: "world-locomotive-policy".to_string(), semantic_family: "world-locomotive-policy".to_string(),
selected_year_gap_scalar_raw_u32: selected_year_gap_scalar selected_year_gap_scalar_raw_u32: selected_year_gap_scalar
.and_then(|field| field.value_u32), .and_then(|field| field.value_u32),
@ -3666,6 +3702,25 @@ fn derive_loaded_world_locomotive_policy_state_from_probe(
.and_then(|field| field.value_u8), .and_then(|field| field.value_u8),
linked_site_removal_follow_on_gate_raw_hex: linked_site_gate linked_site_removal_follow_on_gate_raw_hex: linked_site_gate
.and_then(|field| field.value_u8_hex.clone()), .and_then(|field| field.value_u8_hex.clone()),
auto_show_grade_during_track_lay_raw_u8: auto_show_grade.and_then(|field| field.value_u8),
auto_show_grade_during_track_lay_raw_hex: auto_show_grade
.and_then(|field| field.value_u8_hex.clone()),
starting_building_density_level_raw_u8: starting_building_density
.and_then(|field| field.value_u8),
starting_building_density_level_raw_hex: starting_building_density
.and_then(|field| field.value_u8_hex.clone()),
building_density_growth_raw_u8: building_density_growth.and_then(|field| field.value_u8),
building_density_growth_raw_hex: building_density_growth
.and_then(|field| field.value_u8_hex.clone()),
leftover_simulation_time_accumulator_raw_u32: leftover_simulation_time
.and_then(|field| field.value_u32),
leftover_simulation_time_accumulator_raw_hex: leftover_simulation_time
.and_then(|field| field.value_u32_hex.clone()),
leftover_simulation_time_accumulator_value_f32_text: leftover_simulation_time
.and_then(|field| field.probable_f32_le.clone()),
selected_year_lane_snapshot_raw_u8: selected_year_snapshot.and_then(|field| field.value_u8),
selected_year_lane_snapshot_raw_hex: selected_year_snapshot
.and_then(|field| field.value_u8_hex.clone()),
all_steam_locomotives_available_raw_u8: all_steam.and_then(|field| field.value_u8), all_steam_locomotives_available_raw_u8: all_steam.and_then(|field| field.value_u8),
all_steam_locomotives_available_raw_hex: all_steam all_steam_locomotives_available_raw_hex: all_steam
.and_then(|field| field.value_u8_hex.clone()), .and_then(|field| field.value_u8_hex.clone()),
@ -3681,7 +3736,7 @@ fn derive_loaded_world_locomotive_policy_state_from_probe(
.and_then(|field| field.value_u32_hex.clone()), .and_then(|field| field.value_u32_hex.clone()),
cached_available_locomotive_rating_value_f32_text: cached_available_rating cached_available_locomotive_rating_value_f32_text: cached_available_rating
.and_then(|field| field.probable_f32_le.clone()), .and_then(|field| field.probable_f32_le.clone()),
} })
} }
fn derive_selection_only_company_roster_from_save_world_probe( fn derive_selection_only_company_roster_from_save_world_probe(

View file

@ -7,7 +7,7 @@ use crate::{
runtime_company_annual_finance_policy_action_label, runtime_company_annual_finance_policy_action_label,
runtime_company_annual_finance_policy_state, runtime_company_annual_finance_state, runtime_company_annual_finance_policy_state, runtime_company_annual_finance_state,
runtime_company_annual_stock_issue_state, runtime_company_annual_stock_repurchase_state, runtime_company_annual_stock_issue_state, runtime_company_annual_stock_repurchase_state,
runtime_company_unassigned_share_pool, runtime_company_periodic_service_state, runtime_company_unassigned_share_pool,
}; };
fn raw_u32_to_f32_text(raw: u32) -> String { fn raw_u32_to_f32_text(raw: u32) -> String {
@ -51,6 +51,12 @@ pub struct RuntimeSummary {
pub world_restore_territory_access_cost: Option<u32>, pub world_restore_territory_access_cost: Option<u32>,
pub world_restore_linked_site_removal_follow_on_gate_raw_u8: Option<u8>, pub world_restore_linked_site_removal_follow_on_gate_raw_u8: Option<u8>,
pub world_restore_linked_site_removal_follow_on_gate_enabled: Option<bool>, pub world_restore_linked_site_removal_follow_on_gate_enabled: Option<bool>,
pub world_restore_auto_show_grade_during_track_lay_raw_u8: Option<u8>,
pub world_restore_starting_building_density_level_raw_u8: Option<u8>,
pub world_restore_post_text_building_density_growth_raw_u8: Option<u8>,
pub world_restore_leftover_simulation_time_accumulator_raw_u32: Option<u32>,
pub world_restore_leftover_simulation_time_accumulator_value_f32_text: Option<String>,
pub world_restore_selected_year_lane_snapshot_raw_u8: Option<u8>,
pub world_restore_all_steam_locomotives_available_raw_u8: Option<u8>, pub world_restore_all_steam_locomotives_available_raw_u8: Option<u8>,
pub world_restore_all_steam_locomotives_available_enabled: Option<bool>, pub world_restore_all_steam_locomotives_available_enabled: Option<bool>,
pub world_restore_all_diesel_locomotives_available_raw_u8: Option<u8>, pub world_restore_all_diesel_locomotives_available_raw_u8: Option<u8>,
@ -122,6 +128,10 @@ pub struct RuntimeSummary {
pub selected_company_periodic_side_latch_preferred_locomotive_engine_type_raw_u8: Option<u8>, pub selected_company_periodic_side_latch_preferred_locomotive_engine_type_raw_u8: Option<u8>,
pub selected_company_periodic_side_latch_city_connection_latch: Option<bool>, pub selected_company_periodic_side_latch_city_connection_latch: Option<bool>,
pub selected_company_periodic_side_latch_linked_transit_latch: Option<bool>, pub selected_company_periodic_side_latch_linked_transit_latch: Option<bool>,
pub selected_company_periodic_service_base_route_preference_raw_u8: Option<u8>,
pub selected_company_periodic_service_effective_route_preference_raw_u8: Option<u8>,
pub selected_company_periodic_service_electric_route_preference_override_active: Option<bool>,
pub selected_company_periodic_service_route_quality_multiplier_basis_points: Option<i64>,
pub selected_company_chairman_bonus_year: Option<u32>, pub selected_company_chairman_bonus_year: Option<u32>,
pub selected_company_chairman_bonus_amount: Option<i32>, pub selected_company_chairman_bonus_amount: Option<i32>,
pub selected_company_creditor_pressure_recent_bad_net_profit_year_count: Option<u32>, pub selected_company_creditor_pressure_recent_bad_net_profit_year_count: Option<u32>,
@ -307,6 +317,9 @@ impl RuntimeSummary {
.company_periodic_side_latch_state .company_periodic_side_latch_state
.get(&company_id) .get(&company_id)
}); });
let selected_company_periodic_service_state = state
.selected_company_id
.and_then(|company_id| runtime_company_periodic_service_state(state, company_id));
let selected_company_annual_finance_state = state let selected_company_annual_finance_state = state
.selected_company_id .selected_company_id
.and_then(|company_id| runtime_company_annual_finance_state(state, company_id)); .and_then(|company_id| runtime_company_annual_finance_state(state, company_id));
@ -464,6 +477,25 @@ impl RuntimeSummary {
world_restore_linked_site_removal_follow_on_gate_enabled: state world_restore_linked_site_removal_follow_on_gate_enabled: state
.world_restore .world_restore
.linked_site_removal_follow_on_gate_enabled, .linked_site_removal_follow_on_gate_enabled,
world_restore_auto_show_grade_during_track_lay_raw_u8: state
.world_restore
.auto_show_grade_during_track_lay_raw_u8,
world_restore_starting_building_density_level_raw_u8: state
.world_restore
.starting_building_density_level_raw_u8,
world_restore_post_text_building_density_growth_raw_u8: state
.world_restore
.post_text_building_density_growth_raw_u8,
world_restore_leftover_simulation_time_accumulator_raw_u32: state
.world_restore
.leftover_simulation_time_accumulator_raw_u32,
world_restore_leftover_simulation_time_accumulator_value_f32_text: state
.world_restore
.leftover_simulation_time_accumulator_value_f32_text
.clone(),
world_restore_selected_year_lane_snapshot_raw_u8: state
.world_restore
.selected_year_lane_snapshot_raw_u8,
world_restore_all_steam_locomotives_available_raw_u8: state world_restore_all_steam_locomotives_available_raw_u8: state
.world_restore .world_restore
.all_steam_locomotives_available_raw_u8, .all_steam_locomotives_available_raw_u8,
@ -622,6 +654,24 @@ impl RuntimeSummary {
selected_company_periodic_side_latch_linked_transit_latch: selected_company_periodic_side_latch_linked_transit_latch:
selected_company_periodic_side_latch_state selected_company_periodic_side_latch_state
.map(|latch_state| latch_state.linked_transit_latch), .map(|latch_state| latch_state.linked_transit_latch),
selected_company_periodic_service_base_route_preference_raw_u8:
selected_company_periodic_service_state
.as_ref()
.and_then(|service_state| service_state.base_route_preference_raw_u8),
selected_company_periodic_service_effective_route_preference_raw_u8:
selected_company_periodic_service_state
.as_ref()
.and_then(|service_state| service_state.effective_route_preference_raw_u8),
selected_company_periodic_service_electric_route_preference_override_active:
selected_company_periodic_service_state
.as_ref()
.map(|service_state| service_state.electric_route_preference_override_active),
selected_company_periodic_service_route_quality_multiplier_basis_points:
selected_company_periodic_service_state
.as_ref()
.map(|service_state| {
service_state.effective_route_quality_multiplier_basis_points
}),
selected_company_chairman_bonus_year: selected_company_market_state selected_company_chairman_bonus_year: selected_company_market_state
.map(|market_state| market_state.chairman_bonus_year) .map(|market_state| market_state.chairman_bonus_year)
.filter(|year| *year != 0), .filter(|year| *year != 0),
@ -1578,7 +1628,10 @@ mod tests {
}, },
world_flags: BTreeMap::new(), world_flags: BTreeMap::new(),
save_profile: RuntimeSaveProfileState::default(), save_profile: RuntimeSaveProfileState::default(),
world_restore: RuntimeWorldRestoreState::default(), world_restore: RuntimeWorldRestoreState {
auto_show_grade_during_track_lay_raw_u8: Some(2),
..RuntimeWorldRestoreState::default()
},
metadata: BTreeMap::new(), metadata: BTreeMap::new(),
companies: Vec::new(), companies: Vec::new(),
selected_company_id: None, selected_company_id: None,
@ -1857,6 +1910,12 @@ mod tests {
], ],
linked_site_removal_follow_on_gate_raw_u8: Some(1), linked_site_removal_follow_on_gate_raw_u8: Some(1),
linked_site_removal_follow_on_gate_enabled: Some(true), linked_site_removal_follow_on_gate_enabled: Some(true),
auto_show_grade_during_track_lay_raw_u8: Some(2),
starting_building_density_level_raw_u8: Some(3),
post_text_building_density_growth_raw_u8: Some(1),
leftover_simulation_time_accumulator_raw_u32: Some(0x3f000000),
leftover_simulation_time_accumulator_value_f32_text: Some("0.500000".to_string()),
selected_year_lane_snapshot_raw_u8: Some(7),
all_steam_locomotives_available_raw_u8: Some(1), all_steam_locomotives_available_raw_u8: Some(1),
all_steam_locomotives_available_enabled: Some(true), all_steam_locomotives_available_enabled: Some(true),
all_diesel_locomotives_available_raw_u8: Some(0), all_diesel_locomotives_available_raw_u8: Some(0),
@ -2017,6 +2076,32 @@ mod tests {
summary.world_restore_linked_site_removal_follow_on_gate_enabled, summary.world_restore_linked_site_removal_follow_on_gate_enabled,
Some(true) Some(true)
); );
assert_eq!(
summary.world_restore_auto_show_grade_during_track_lay_raw_u8,
Some(2)
);
assert_eq!(
summary.world_restore_starting_building_density_level_raw_u8,
Some(3)
);
assert_eq!(
summary.world_restore_post_text_building_density_growth_raw_u8,
Some(1)
);
assert_eq!(
summary.world_restore_leftover_simulation_time_accumulator_raw_u32,
Some(0x3f000000)
);
assert_eq!(
summary
.world_restore_leftover_simulation_time_accumulator_value_f32_text
.as_deref(),
Some("0.500000")
);
assert_eq!(
summary.world_restore_selected_year_lane_snapshot_raw_u8,
Some(7)
);
assert_eq!( assert_eq!(
summary.world_restore_all_steam_locomotives_available_raw_u8, summary.world_restore_all_steam_locomotives_available_raw_u8,
Some(1) Some(1)
@ -2113,7 +2198,10 @@ mod tests {
}, },
world_flags: BTreeMap::new(), world_flags: BTreeMap::new(),
save_profile: RuntimeSaveProfileState::default(), save_profile: RuntimeSaveProfileState::default(),
world_restore: RuntimeWorldRestoreState::default(), world_restore: RuntimeWorldRestoreState {
auto_show_grade_during_track_lay_raw_u8: Some(2),
..RuntimeWorldRestoreState::default()
},
metadata: BTreeMap::new(), metadata: BTreeMap::new(),
companies: vec![ companies: vec![
RuntimeCompany { RuntimeCompany {
@ -2218,7 +2306,10 @@ mod tests {
}, },
world_flags: BTreeMap::new(), world_flags: BTreeMap::new(),
save_profile: RuntimeSaveProfileState::default(), save_profile: RuntimeSaveProfileState::default(),
world_restore: RuntimeWorldRestoreState::default(), world_restore: RuntimeWorldRestoreState {
auto_show_grade_during_track_lay_raw_u8: Some(2),
..RuntimeWorldRestoreState::default()
},
metadata: BTreeMap::new(), metadata: BTreeMap::new(),
companies: Vec::new(), companies: Vec::new(),
selected_company_id: None, selected_company_id: None,
@ -2770,7 +2861,10 @@ mod tests {
}, },
world_flags: BTreeMap::new(), world_flags: BTreeMap::new(),
save_profile: RuntimeSaveProfileState::default(), save_profile: RuntimeSaveProfileState::default(),
world_restore: RuntimeWorldRestoreState::default(), world_restore: RuntimeWorldRestoreState {
auto_show_grade_during_track_lay_raw_u8: Some(2),
..RuntimeWorldRestoreState::default()
},
metadata: BTreeMap::new(), metadata: BTreeMap::new(),
companies: vec![RuntimeCompany { companies: vec![RuntimeCompany {
company_id: 1, company_id: 1,
@ -2972,6 +3066,22 @@ mod tests {
summary.selected_company_periodic_side_latch_linked_transit_latch, summary.selected_company_periodic_side_latch_linked_transit_latch,
Some(false) Some(false)
); );
assert_eq!(
summary.selected_company_periodic_service_base_route_preference_raw_u8,
Some(2)
);
assert_eq!(
summary.selected_company_periodic_service_effective_route_preference_raw_u8,
Some(2)
);
assert_eq!(
summary.selected_company_periodic_service_electric_route_preference_override_active,
Some(true)
);
assert_eq!(
summary.selected_company_periodic_service_route_quality_multiplier_basis_points,
Some(180)
);
assert_eq!(summary.selected_company_chairman_bonus_year, Some(1842)); assert_eq!(summary.selected_company_chairman_bonus_year, Some(1842));
assert_eq!(summary.selected_company_chairman_bonus_amount, Some(750)); assert_eq!(summary.selected_company_chairman_bonus_amount, Some(750));
} }

View file

@ -184,6 +184,9 @@ The highest-value next passes are now:
- the same save-native company direct-record seam now also carries the full outer periodic-company - the same save-native company direct-record seam now also carries the full outer periodic-company
side-latch trio rooted at `0x0d17/0x0d18/0x0d56`, including the preferred-locomotive side-latch trio rooted at `0x0d17/0x0d18/0x0d56`, including the preferred-locomotive
engine-type chooser byte beside the city-connection and linked-transit finance gates engine-type chooser byte beside the city-connection and linked-transit finance gates
- that same seam now also resolves the base world route-preference byte at `[world+0x4c74]`, the
effective electric-only override fed by `0x0d17`, and the matching `1.4x` versus `1.8x`
route-quality multiplier as a normal runtime reader instead of a pure atlas note
- the project rule on the remaining closure work is now explicit too: when one runtime-facing field - the project rule on the remaining closure work is now explicit too: when one runtime-facing field
is still ambiguous, prefer rehosting the owning source state or real reader/setter family first is still ambiguous, prefer rehosting the owning source state or real reader/setter family first
instead of guessing another derived leaf field from neighboring raw offsets instead of guessing another derived leaf field from neighboring raw offsets

View file

@ -9,13 +9,13 @@ Working rule:
## Next ## Next
- Rehost the outer periodic company-service seam around - Rehost the next live branch inside
`company_service_periodic_city_connection_finance_and_linked_transit_lanes`, using the now `company_service_periodic_city_connection_finance_and_linked_transit_lanes`, especially the
save-native side-latch trio `0x0d17/0x0d18/0x0d56` as owned runtime state instead of leaving city-connection announcement / linked-transit roster-maintenance side that now sits on top of
that pass split across annual-finance readers and atlas notes. the owned periodic-service seam instead of loose atlas notes.
- Rehost the world-side `[world+0x4c74]` post-text owner lane so the temporary route-preference - Keep widening the temporary world route-preference owner around `[world+0x4c74]` from a pure
override fed by company-side `0x0d17` can eventually move through a real runtime seam instead reader seam into a real service mutation seam when the linked-transit route search / balancing
of staying atlas-only. branch is grounded strongly enough.
- Keep widening selected-year world-owner state only when a full owning reader/rebuild family is - Keep widening selected-year world-owner state only when a full owning reader/rebuild family is
grounded strongly enough to avoid one-off leaf guesses. grounded strongly enough to avoid one-off leaf guesses.
@ -66,6 +66,11 @@ Working rule:
- The periodic-boundary owner now also clears the transient preferred-locomotive side latch every - The periodic-boundary owner now also clears the transient preferred-locomotive side latch every
cycle and reseeds the finance latches from market state where present, while preserving cycle and reseeds the finance latches from market state where present, while preserving
side-latch-only company context when no market projection exists. side-latch-only company context when no market projection exists.
- The outer periodic-company seam now also has a first-class runtime reader:
selected-company summaries and finance readers can resolve the base `[world+0x4c74]`
route-preference byte, the effective electric-only override fed by `0x0d17`, and the matching
`1.4x` versus `1.8x` route-quality multiplier through owned periodic-service state instead of
leaving that bridge in atlas notes.
- Company cash, confiscation, and major governance effects now write through owner state instead of - Company cash, confiscation, and major governance effects now write through owner state instead of
drifting from market/cache readers. drifting from market/cache readers.
- Company credit rating, prime rate, book value per share, investor confidence, and management - Company credit rating, prime rate, book value per share, investor confidence, and management

View file

@ -261,6 +261,9 @@ policy instead of treating dividend changes as shell-dialog-only logic.
The same save-native company direct-record seam now also carries the full outer periodic-company The same save-native company direct-record seam now also carries the full outer periodic-company
side-latch trio rooted at `0x0d17/0x0d18/0x0d56`, including the preferred-locomotive side-latch trio rooted at `0x0d17/0x0d18/0x0d56`, including the preferred-locomotive
engine-type chooser byte beside the city-connection and linked-transit finance gates. engine-type chooser byte beside the city-connection and linked-transit finance gates.
That same seam now also resolves the base world route-preference byte at `[world+0x4c74]`, the
effective electric-only override fed by `0x0d17`, and the matching `1.4x` versus `1.8x`
route-quality multiplier as a first-class runtime reader rather than a loose atlas-only bridge.
That same seam now also carries the fixed-world building-density growth setting plus the linked That same seam now also carries the fixed-world building-density growth setting plus the linked
chairman personality byte, which is enough to rehost the annual stock-repurchase gate on owned chairman personality byte, which is enough to rehost the annual stock-repurchase gate on owned
save/runtime state instead of another threshold-only note. The stock-capital issue branch now save/runtime state instead of another threshold-only note. The stock-capital issue branch now