Rehost annual bond policy branch

This commit is contained in:
Jan Petykiewicz 2026-04-18 00:45:35 -07:00
commit fa86a95f0d
6 changed files with 449 additions and 27 deletions

View file

@ -97,6 +97,9 @@ headlessly as a pure runtime reader over owned annual-finance state, support-adj
and current world finance policy rather than as a notes-only atlas fragment. The later deep- and current world finance policy rather than as a notes-only atlas fragment. The later deep-
distress bankruptcy fallback is now rehosted on that same owner surface too, using the save-native distress bankruptcy fallback is now rehosted on that same owner surface too, using the save-native
cash reader seam plus the first three trailing net-profit years instead of another ad hoc probe. cash reader seam plus the first three trailing net-profit years instead of another ad hoc probe.
The annual bond lane now runs on that same owner surface too, using the simulated post-repayment
cash window plus the linked-transit threshold split to stage `500000` principal issue counts as a
pure runtime reader.
The same seam now also carries the fixed-world building-density growth setting plus the linked The same seam now also carries the fixed-world building-density growth setting plus the linked
chairman personality byte, which is enough to run the annual stock-repurchase gate as another chairman personality byte, which is enough to run the annual stock-repurchase gate as another
pure reader over owned save-native state instead of a guessed finance-side approximation. pure reader over owned save-native state instead of a guessed finance-side approximation.

View file

@ -52,28 +52,29 @@ pub use runtime::{
RUNTIME_WORLD_ISSUE_PRIME_RATE, RuntimeCargoCatalogEntry, RuntimeCargoClass, RUNTIME_WORLD_ISSUE_PRIME_RATE, RuntimeCargoCatalogEntry, RuntimeCargoClass,
RuntimeCargoPriceTarget, RuntimeCargoProductionTarget, RuntimeChairmanMetric, RuntimeCargoPriceTarget, RuntimeCargoProductionTarget, RuntimeChairmanMetric,
RuntimeChairmanProfile, RuntimeChairmanTarget, RuntimeCompany, RuntimeChairmanProfile, RuntimeChairmanTarget, RuntimeCompany,
RuntimeCompanyAnnualCreditorPressureState, RuntimeCompanyAnnualDeepDistressState, RuntimeCompanyAnnualBondPolicyState, RuntimeCompanyAnnualCreditorPressureState,
RuntimeCompanyAnnualFinanceState, RuntimeCompanyAnnualStockIssueState, RuntimeCompanyAnnualDeepDistressState, RuntimeCompanyAnnualFinanceState,
RuntimeCompanyAnnualStockRepurchaseState, RuntimeCompanyBondSlot, RuntimeCompanyAnnualStockIssueState, RuntimeCompanyAnnualStockRepurchaseState,
RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind, RuntimeCompanyMarketMetric, RuntimeCompanyBondSlot, RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind,
RuntimeCompanyMarketState, RuntimeCompanyMetric, RuntimeCompanyStatBandCandidate, RuntimeCompanyMarketMetric, RuntimeCompanyMarketState, RuntimeCompanyMetric,
RuntimeCompanyStatSelector, RuntimeCompanyTarget, RuntimeCompanyTerritoryAccess, RuntimeCompanyStatBandCandidate, RuntimeCompanyStatSelector, RuntimeCompanyTarget,
RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition, RuntimeConditionComparator, RuntimeCompanyTerritoryAccess, RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition,
RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate, RuntimeLocomotiveCatalogEntry, RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate,
RuntimePackedEventCollectionSummary, RuntimePackedEventCompactControlSummary, RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary,
RuntimePackedEventConditionRowSummary, RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventCompactControlSummary, RuntimePackedEventConditionRowSummary,
RuntimePackedEventNegativeSentinelScopeSummary, RuntimePackedEventRecordSummary, RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventNegativeSentinelScopeSummary,
RuntimePackedEventTextBandSummary, RuntimePlayer, RuntimePlayerConditionTestScope, RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary, RuntimePlayer,
RuntimePlayerTarget, RuntimeSaveProfileState, RuntimeServiceState, RuntimeState, RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeSaveProfileState,
RuntimeTerritory, RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeServiceState, RuntimeState, RuntimeTerritory, RuntimeTerritoryMetric,
RuntimeTrackPieceCounts, RuntimeTrain, RuntimeWorldFinanceNeighborhoodCandidate, RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts, RuntimeTrain,
RuntimeWorldIssueState, RuntimeWorldRestoreState, RuntimeWorldFinanceNeighborhoodCandidate, RuntimeWorldIssueState, RuntimeWorldRestoreState,
runtime_company_annual_creditor_pressure_state, runtime_company_annual_deep_distress_state, runtime_company_annual_bond_policy_state, runtime_company_annual_creditor_pressure_state,
runtime_company_annual_finance_state, runtime_company_annual_stock_issue_state, runtime_company_annual_deep_distress_state, runtime_company_annual_finance_state,
runtime_company_annual_stock_repurchase_state, runtime_company_assigned_share_pool, runtime_company_annual_stock_issue_state, runtime_company_annual_stock_repurchase_state,
runtime_company_average_live_bond_coupon, runtime_company_book_value_per_share, runtime_company_assigned_share_pool, runtime_company_average_live_bond_coupon,
runtime_company_credit_rating, runtime_company_investor_confidence, runtime_company_book_value_per_share, runtime_company_credit_rating,
runtime_company_management_attitude, runtime_company_market_value, runtime_company_prime_rate, runtime_company_investor_confidence, runtime_company_management_attitude,
runtime_company_market_value, runtime_company_prime_rate,
runtime_company_recent_per_share_subscore, runtime_company_stat_value, runtime_company_recent_per_share_subscore, runtime_company_stat_value,
runtime_company_stat_value_f64, runtime_company_unassigned_share_pool, runtime_company_stat_value_f64, runtime_company_unassigned_share_pool,
runtime_world_annual_finance_mode_active, runtime_world_bankruptcy_allowed, runtime_world_annual_finance_mode_active, runtime_world_bankruptcy_allowed,

View file

@ -310,6 +310,35 @@ pub struct RuntimeCompanyAnnualStockIssueState {
pub eligible_for_double_tranche_issue: bool, pub eligible_for_double_tranche_issue: bool,
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeCompanyAnnualBondPolicyState {
pub company_id: u32,
#[serde(default)]
pub annual_mode_active: Option<bool>,
#[serde(default)]
pub bond_issue_and_repayment_allowed: Option<bool>,
pub linked_transit_latch: bool,
#[serde(default)]
pub live_bond_count: Option<u8>,
#[serde(default)]
pub live_bond_principal_total: Option<u32>,
#[serde(default)]
pub current_cash: Option<i64>,
#[serde(default)]
pub cash_after_full_repayment: Option<i64>,
#[serde(default)]
pub issue_cash_floor: Option<i64>,
#[serde(default)]
pub issue_principal_step: Option<u32>,
#[serde(default)]
pub proposed_issue_bond_count: Option<u32>,
#[serde(default)]
pub proposed_issue_total_principal: Option<u32>,
#[serde(default)]
pub proposed_issue_years_to_maturity: Option<u32>,
pub eligible_for_bond_issue_branch: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct RuntimeTrackPieceCounts { pub struct RuntimeTrackPieceCounts {
#[serde(default)] #[serde(default)]
@ -2235,6 +2264,17 @@ fn runtime_company_highest_live_bond_coupon_rate_f64(
.max_by(|left, right| left.partial_cmp(right).unwrap_or(std::cmp::Ordering::Equal)) .max_by(|left, right| left.partial_cmp(right).unwrap_or(std::cmp::Ordering::Equal))
} }
fn runtime_company_total_live_bond_principal(state: &RuntimeState, company_id: u32) -> Option<u32> {
let market_state = state.service_state.company_market_state.get(&company_id)?;
Some(
market_state
.live_bond_slots
.iter()
.map(|slot| slot.principal)
.sum(),
)
}
fn runtime_company_support_adjusted_share_price_scalar_with_pressure_f64( fn runtime_company_support_adjusted_share_price_scalar_with_pressure_f64(
state: &RuntimeState, state: &RuntimeState,
company_id: u32, company_id: u32,
@ -3016,6 +3056,65 @@ pub fn runtime_company_annual_stock_repurchase_state(
}) })
} }
pub fn runtime_company_annual_bond_policy_state(
state: &RuntimeState,
company_id: u32,
) -> Option<RuntimeCompanyAnnualBondPolicyState> {
const STANDARD_CASH_FLOOR: i64 = -250_000;
const LINKED_TRANSIT_CASH_FLOOR: i64 = -30_000;
const ISSUE_PRINCIPAL_STEP: u32 = 500_000;
const ISSUE_YEARS_TO_MATURITY: u32 = 30;
let annual_finance_state = runtime_company_annual_finance_state(state, company_id)?;
let current_cash = runtime_company_control_transfer_stat_value_f64(
state,
company_id,
RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
)
.and_then(runtime_round_f64_to_i64);
let live_bond_principal_total = runtime_company_total_live_bond_principal(state, company_id);
let cash_after_full_repayment = current_cash
.zip(live_bond_principal_total)
.map(|(cash, principal)| cash - i64::from(principal));
let issue_cash_floor = Some(if annual_finance_state.linked_transit_latch {
LINKED_TRANSIT_CASH_FLOOR
} else {
STANDARD_CASH_FLOOR
});
let proposed_issue_bond_count = cash_after_full_repayment.zip(issue_cash_floor).map(
|(cash_after_repayment, cash_floor)| {
if cash_after_repayment >= cash_floor {
0
} else {
let deficit = (cash_floor - cash_after_repayment) as u64;
deficit.div_ceil(u64::from(ISSUE_PRINCIPAL_STEP)) as u32
}
},
);
let proposed_issue_total_principal =
proposed_issue_bond_count.and_then(|count| count.checked_mul(ISSUE_PRINCIPAL_STEP));
let eligible_for_bond_issue_branch = runtime_world_annual_finance_mode_active(state)
== Some(true)
&& runtime_world_bond_issue_and_repayment_allowed(state) == Some(true)
&& proposed_issue_bond_count.is_some_and(|count| count > 0);
Some(RuntimeCompanyAnnualBondPolicyState {
company_id,
annual_mode_active: runtime_world_annual_finance_mode_active(state),
bond_issue_and_repayment_allowed: runtime_world_bond_issue_and_repayment_allowed(state),
linked_transit_latch: annual_finance_state.linked_transit_latch,
live_bond_count: Some(annual_finance_state.bond_count),
live_bond_principal_total,
current_cash,
cash_after_full_repayment,
issue_cash_floor,
issue_principal_step: Some(ISSUE_PRINCIPAL_STEP),
proposed_issue_bond_count,
proposed_issue_total_principal,
proposed_issue_years_to_maturity: Some(ISSUE_YEARS_TO_MATURITY),
eligible_for_bond_issue_branch,
})
}
fn runtime_company_stock_issue_price_to_book_ratio_f64( fn runtime_company_stock_issue_price_to_book_ratio_f64(
pressured_support_adjusted_share_price_scalar: f64, pressured_support_adjusted_share_price_scalar: f64,
book_value_per_share: f64, book_value_per_share: f64,
@ -3144,6 +3243,8 @@ pub fn runtime_company_annual_stock_issue_state(
.eligible_for_bankruptcy_branch .eligible_for_bankruptcy_branch
&& !runtime_company_annual_deep_distress_state(state, company_id)? && !runtime_company_annual_deep_distress_state(state, company_id)?
.eligible_for_bankruptcy_fallback .eligible_for_bankruptcy_fallback
&& !runtime_company_annual_bond_policy_state(state, company_id)?
.eligible_for_bond_issue_branch
&& !runtime_company_annual_stock_repurchase_state(state, company_id)? && !runtime_company_annual_stock_repurchase_state(state, company_id)?
.eligible_for_single_batch_repurchase .eligible_for_single_batch_repurchase
&& passes_share_price_floor == Some(true) && passes_share_price_floor == Some(true)
@ -7621,6 +7722,121 @@ mod tests {
assert!(!repurchase_state.eligible_for_single_batch_repurchase); assert!(!repurchase_state.eligible_for_single_batch_repurchase);
} }
#[test]
fn derives_annual_bond_policy_state_from_rehosted_owner_state() {
let mut year_stat_family_qword_bits = vec![
0u64;
((RUNTIME_COMPANY_STAT_SLOT_COUNT + 2) * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)
as usize
];
let write_current_value = |bits: &mut Vec<u64>, slot_id: u32, value: f64| {
let index = (slot_id * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN) as usize;
bits[index] = value.to_bits();
};
write_current_value(&mut year_stat_family_qword_bits, 0x0d, -400_000.0);
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 {
partial_year_progress_raw_u8: Some(0x0c),
bond_issue_and_repayment_policy_raw_u8: Some(0),
bond_issue_and_repayment_allowed: Some(true),
..RuntimeWorldRestoreState::default()
},
metadata: BTreeMap::new(),
companies: vec![RuntimeCompany {
company_id: 11,
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: None,
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([(
11,
RuntimeCompanyMarketState {
bond_count: 2,
linked_transit_latch: true,
live_bond_slots: vec![
RuntimeCompanyBondSlot {
slot_index: 0,
principal: 200_000,
coupon_rate_raw_u32: 0.09f32.to_bits(),
},
RuntimeCompanyBondSlot {
slot_index: 1,
principal: 150_000,
coupon_rate_raw_u32: 0.08f32.to_bits(),
},
],
year_stat_family_qword_bits,
..RuntimeCompanyMarketState::default()
},
)]),
..RuntimeServiceState::default()
},
};
let bond_state =
runtime_company_annual_bond_policy_state(&state, 11).expect("bond policy state");
assert_eq!(bond_state.live_bond_count, Some(2));
assert_eq!(bond_state.live_bond_principal_total, Some(350_000));
assert_eq!(bond_state.current_cash, Some(-400_000));
assert_eq!(bond_state.cash_after_full_repayment, Some(-750_000));
assert_eq!(bond_state.issue_cash_floor, Some(-30_000));
assert_eq!(bond_state.issue_principal_step, Some(500_000));
assert_eq!(bond_state.proposed_issue_bond_count, Some(2));
assert_eq!(bond_state.proposed_issue_total_principal, Some(1_000_000));
assert_eq!(bond_state.proposed_issue_years_to_maturity, Some(30));
assert!(bond_state.eligible_for_bond_issue_branch);
}
#[test] #[test]
fn derives_annual_stock_issue_state_from_rehosted_owner_state() { fn derives_annual_stock_issue_state_from_rehosted_owner_state() {
let mut year_stat_family_qword_bits = vec![ let mut year_stat_family_qword_bits = vec![

View file

@ -1,10 +1,10 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
CalendarPoint, RuntimeState, runtime_company_annual_creditor_pressure_state, CalendarPoint, RuntimeState, runtime_company_annual_bond_policy_state,
runtime_company_annual_deep_distress_state, runtime_company_annual_finance_state, runtime_company_annual_creditor_pressure_state, runtime_company_annual_deep_distress_state,
runtime_company_annual_stock_issue_state, runtime_company_annual_stock_repurchase_state, runtime_company_annual_finance_state, runtime_company_annual_stock_issue_state,
runtime_company_unassigned_share_pool, runtime_company_annual_stock_repurchase_state, runtime_company_unassigned_share_pool,
}; };
fn raw_u32_to_f32_text(raw: u32) -> String { fn raw_u32_to_f32_text(raw: u32) -> String {
@ -113,6 +113,17 @@ pub struct RuntimeSummary {
pub selected_company_deep_distress_cash_floor: Option<i64>, pub selected_company_deep_distress_cash_floor: Option<i64>,
pub selected_company_deep_distress_net_profit_floor: Option<i64>, pub selected_company_deep_distress_net_profit_floor: Option<i64>,
pub selected_company_deep_distress_eligible_for_bankruptcy_fallback: Option<bool>, pub selected_company_deep_distress_eligible_for_bankruptcy_fallback: Option<bool>,
pub selected_company_annual_bond_linked_transit_latch: Option<bool>,
pub selected_company_annual_bond_live_bond_count: Option<u8>,
pub selected_company_annual_bond_live_bond_principal_total: Option<u32>,
pub selected_company_annual_bond_current_cash: Option<i64>,
pub selected_company_annual_bond_cash_after_full_repayment: Option<i64>,
pub selected_company_annual_bond_issue_cash_floor: Option<i64>,
pub selected_company_annual_bond_issue_principal_step: Option<u32>,
pub selected_company_annual_bond_proposed_issue_bond_count: Option<u32>,
pub selected_company_annual_bond_proposed_issue_total_principal: Option<u32>,
pub selected_company_annual_bond_proposed_issue_years_to_maturity: Option<u32>,
pub selected_company_annual_bond_eligible_for_issue_branch: Option<bool>,
pub selected_company_stock_repurchase_city_connection_latch: Option<bool>, pub selected_company_stock_repurchase_city_connection_latch: Option<bool>,
pub selected_company_stock_repurchase_building_density_growth_setting: Option<u32>, pub selected_company_stock_repurchase_building_density_growth_setting: Option<u32>,
pub selected_company_stock_repurchase_linked_chairman_profile_id: Option<u32>, pub selected_company_stock_repurchase_linked_chairman_profile_id: Option<u32>,
@ -241,6 +252,9 @@ impl RuntimeSummary {
let selected_company_deep_distress_state = state let selected_company_deep_distress_state = state
.selected_company_id .selected_company_id
.and_then(|company_id| runtime_company_annual_deep_distress_state(state, company_id)); .and_then(|company_id| runtime_company_annual_deep_distress_state(state, company_id));
let selected_company_annual_bond_state = state
.selected_company_id
.and_then(|company_id| runtime_company_annual_bond_policy_state(state, company_id));
let selected_company_stock_repurchase_state = let selected_company_stock_repurchase_state =
state.selected_company_id.and_then(|company_id| { state.selected_company_id.and_then(|company_id| {
runtime_company_annual_stock_repurchase_state(state, company_id) runtime_company_annual_stock_repurchase_state(state, company_id)
@ -524,6 +538,45 @@ impl RuntimeSummary {
selected_company_deep_distress_state selected_company_deep_distress_state
.as_ref() .as_ref()
.map(|pressure_state| pressure_state.eligible_for_bankruptcy_fallback), .map(|pressure_state| pressure_state.eligible_for_bankruptcy_fallback),
selected_company_annual_bond_linked_transit_latch: selected_company_annual_bond_state
.as_ref()
.map(|bond_state| bond_state.linked_transit_latch),
selected_company_annual_bond_live_bond_count: selected_company_annual_bond_state
.as_ref()
.and_then(|bond_state| bond_state.live_bond_count),
selected_company_annual_bond_live_bond_principal_total:
selected_company_annual_bond_state
.as_ref()
.and_then(|bond_state| bond_state.live_bond_principal_total),
selected_company_annual_bond_current_cash: selected_company_annual_bond_state
.as_ref()
.and_then(|bond_state| bond_state.current_cash),
selected_company_annual_bond_cash_after_full_repayment:
selected_company_annual_bond_state
.as_ref()
.and_then(|bond_state| bond_state.cash_after_full_repayment),
selected_company_annual_bond_issue_cash_floor: selected_company_annual_bond_state
.as_ref()
.and_then(|bond_state| bond_state.issue_cash_floor),
selected_company_annual_bond_issue_principal_step: selected_company_annual_bond_state
.as_ref()
.and_then(|bond_state| bond_state.issue_principal_step),
selected_company_annual_bond_proposed_issue_bond_count:
selected_company_annual_bond_state
.as_ref()
.and_then(|bond_state| bond_state.proposed_issue_bond_count),
selected_company_annual_bond_proposed_issue_total_principal:
selected_company_annual_bond_state
.as_ref()
.and_then(|bond_state| bond_state.proposed_issue_total_principal),
selected_company_annual_bond_proposed_issue_years_to_maturity:
selected_company_annual_bond_state
.as_ref()
.and_then(|bond_state| bond_state.proposed_issue_years_to_maturity),
selected_company_annual_bond_eligible_for_issue_branch:
selected_company_annual_bond_state
.as_ref()
.map(|bond_state| bond_state.eligible_for_bond_issue_branch),
selected_company_stock_repurchase_city_connection_latch: selected_company_stock_repurchase_city_connection_latch:
selected_company_stock_repurchase_state selected_company_stock_repurchase_state
.as_ref() .as_ref()
@ -2911,6 +2964,153 @@ mod tests {
); );
} }
#[test]
fn summarizes_selected_company_annual_bond_policy_state() {
let mut year_stat_family_qword_bits = vec![
0u64;
((crate::RUNTIME_COMPANY_STAT_SLOT_COUNT + 2)
* crate::RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)
as usize
];
year_stat_family_qword_bits[(crate::RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH
* crate::RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)
as usize] = (-400_000.0f64).to_bits();
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 {
partial_year_progress_raw_u8: Some(0x0c),
bond_issue_and_repayment_policy_raw_u8: Some(0),
bond_issue_and_repayment_allowed: Some(true),
..RuntimeWorldRestoreState::default()
},
metadata: BTreeMap::new(),
companies: vec![RuntimeCompany {
company_id: 11,
current_cash: 0,
debt: 0,
credit_rating_score: None,
prime_rate: None,
active: true,
available_track_laying_capacity: None,
controller_kind: crate::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(11),
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: Vec::new().into_iter().collect(),
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([(
11,
crate::RuntimeCompanyMarketState {
bond_count: 2,
linked_transit_latch: true,
live_bond_slots: vec![
crate::RuntimeCompanyBondSlot {
slot_index: 0,
principal: 200_000,
coupon_rate_raw_u32: 0.09f32.to_bits(),
},
crate::RuntimeCompanyBondSlot {
slot_index: 1,
principal: 150_000,
coupon_rate_raw_u32: 0.08f32.to_bits(),
},
],
year_stat_family_qword_bits,
..crate::RuntimeCompanyMarketState::default()
},
)]),
..RuntimeServiceState::default()
},
};
let summary = RuntimeSummary::from_state(&state);
assert_eq!(
summary.selected_company_annual_bond_linked_transit_latch,
Some(true)
);
assert_eq!(
summary.selected_company_annual_bond_live_bond_count,
Some(2)
);
assert_eq!(
summary.selected_company_annual_bond_live_bond_principal_total,
Some(350_000)
);
assert_eq!(
summary.selected_company_annual_bond_current_cash,
Some(-400_000)
);
assert_eq!(
summary.selected_company_annual_bond_cash_after_full_repayment,
Some(-750_000)
);
assert_eq!(
summary.selected_company_annual_bond_issue_cash_floor,
Some(-30_000)
);
assert_eq!(
summary.selected_company_annual_bond_issue_principal_step,
Some(500_000)
);
assert_eq!(
summary.selected_company_annual_bond_proposed_issue_bond_count,
Some(2)
);
assert_eq!(
summary.selected_company_annual_bond_proposed_issue_total_principal,
Some(1_000_000)
);
assert_eq!(
summary.selected_company_annual_bond_proposed_issue_years_to_maturity,
Some(30)
);
assert_eq!(
summary.selected_company_annual_bond_eligible_for_issue_branch,
Some(true)
);
}
#[test] #[test]
fn summarizes_selected_company_stock_issue_state() { fn summarizes_selected_company_stock_issue_state() {
let mut year_stat_family_qword_bits = vec![ let mut year_stat_family_qword_bits = vec![

View file

@ -139,7 +139,7 @@ The highest-value next passes are now:
bankruptcy, and dividend finance-policy bytes, and the first annual creditor-pressure branch now bankruptcy, and dividend finance-policy bytes, and the first annual creditor-pressure branch now
executes as a pure runtime reader over that owner state instead of remaining atlas-only; the executes as a pure runtime reader over that owner state instead of remaining atlas-only; the
later deep-distress bankruptcy fallback now runs on that same save-native cash and trailing- later deep-distress bankruptcy fallback now runs on that same save-native cash and trailing-
profit seam; the annual stock-repurchase and stock-capital issue branches now do too profit seam; the annual bond, stock-repurchase, and stock-capital issue branches now do too
net-profit surface too; the same owner seam now also carries the fixed-world building-density net-profit surface too; the same owner seam now also carries the fixed-world building-density
growth setting plus the linked chairman personality byte, which is enough to run the annual growth setting plus the linked chairman personality byte, which is enough to run the annual
stock-repurchase gate headlessly as another pure reader stock-repurchase gate headlessly as another pure reader

View file

@ -232,6 +232,8 @@ bankruptcy branch now runs as a pure runtime reader over owned annual-finance st
adjusted share price, and those policy bytes rather than staying in atlas prose only. The later adjusted share price, and those policy bytes rather than staying in atlas prose only. The later
deep-distress bankruptcy fallback now rides the same owner-state seam too, using the save-native deep-distress bankruptcy fallback now rides the same owner-state seam too, using the save-native
cash reader plus the first three trailing net-profit years instead of a parallel raw-offset guess. cash reader plus the first three trailing net-profit years instead of a parallel raw-offset guess.
The annual bond lane now rides it as well, using the simulated post-repayment cash window plus the
linked-transit threshold split to stage `500000` principal issue counts without shell ownership.
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