Rehost annual bond policy branch
This commit is contained in:
parent
d303ee994b
commit
fa86a95f0d
6 changed files with 449 additions and 27 deletions
|
|
@ -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-
|
||||
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.
|
||||
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
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -52,28 +52,29 @@ pub use runtime::{
|
|||
RUNTIME_WORLD_ISSUE_PRIME_RATE, RuntimeCargoCatalogEntry, RuntimeCargoClass,
|
||||
RuntimeCargoPriceTarget, RuntimeCargoProductionTarget, RuntimeChairmanMetric,
|
||||
RuntimeChairmanProfile, RuntimeChairmanTarget, RuntimeCompany,
|
||||
RuntimeCompanyAnnualCreditorPressureState, RuntimeCompanyAnnualDeepDistressState,
|
||||
RuntimeCompanyAnnualFinanceState, RuntimeCompanyAnnualStockIssueState,
|
||||
RuntimeCompanyAnnualStockRepurchaseState, RuntimeCompanyBondSlot,
|
||||
RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind, RuntimeCompanyMarketMetric,
|
||||
RuntimeCompanyMarketState, RuntimeCompanyMetric, RuntimeCompanyStatBandCandidate,
|
||||
RuntimeCompanyStatSelector, RuntimeCompanyTarget, RuntimeCompanyTerritoryAccess,
|
||||
RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition, RuntimeConditionComparator,
|
||||
RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate, RuntimeLocomotiveCatalogEntry,
|
||||
RuntimePackedEventCollectionSummary, RuntimePackedEventCompactControlSummary,
|
||||
RuntimePackedEventConditionRowSummary, RuntimePackedEventGroupedEffectRowSummary,
|
||||
RuntimePackedEventNegativeSentinelScopeSummary, RuntimePackedEventRecordSummary,
|
||||
RuntimePackedEventTextBandSummary, RuntimePlayer, RuntimePlayerConditionTestScope,
|
||||
RuntimePlayerTarget, RuntimeSaveProfileState, RuntimeServiceState, RuntimeState,
|
||||
RuntimeTerritory, RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric,
|
||||
RuntimeTrackPieceCounts, RuntimeTrain, RuntimeWorldFinanceNeighborhoodCandidate,
|
||||
RuntimeWorldIssueState, RuntimeWorldRestoreState,
|
||||
runtime_company_annual_creditor_pressure_state, runtime_company_annual_deep_distress_state,
|
||||
runtime_company_annual_finance_state, runtime_company_annual_stock_issue_state,
|
||||
runtime_company_annual_stock_repurchase_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_management_attitude, runtime_company_market_value, runtime_company_prime_rate,
|
||||
RuntimeCompanyAnnualBondPolicyState, RuntimeCompanyAnnualCreditorPressureState,
|
||||
RuntimeCompanyAnnualDeepDistressState, RuntimeCompanyAnnualFinanceState,
|
||||
RuntimeCompanyAnnualStockIssueState, RuntimeCompanyAnnualStockRepurchaseState,
|
||||
RuntimeCompanyBondSlot, RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind,
|
||||
RuntimeCompanyMarketMetric, RuntimeCompanyMarketState, RuntimeCompanyMetric,
|
||||
RuntimeCompanyStatBandCandidate, RuntimeCompanyStatSelector, RuntimeCompanyTarget,
|
||||
RuntimeCompanyTerritoryAccess, RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition,
|
||||
RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate,
|
||||
RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary,
|
||||
RuntimePackedEventCompactControlSummary, RuntimePackedEventConditionRowSummary,
|
||||
RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventNegativeSentinelScopeSummary,
|
||||
RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary, RuntimePlayer,
|
||||
RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeSaveProfileState,
|
||||
RuntimeServiceState, RuntimeState, RuntimeTerritory, RuntimeTerritoryMetric,
|
||||
RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts, RuntimeTrain,
|
||||
RuntimeWorldFinanceNeighborhoodCandidate, RuntimeWorldIssueState, RuntimeWorldRestoreState,
|
||||
runtime_company_annual_bond_policy_state, runtime_company_annual_creditor_pressure_state,
|
||||
runtime_company_annual_deep_distress_state, runtime_company_annual_finance_state,
|
||||
runtime_company_annual_stock_issue_state, runtime_company_annual_stock_repurchase_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_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_annual_finance_mode_active, runtime_world_bankruptcy_allowed,
|
||||
|
|
|
|||
|
|
@ -310,6 +310,35 @@ pub struct RuntimeCompanyAnnualStockIssueState {
|
|||
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)]
|
||||
pub struct RuntimeTrackPieceCounts {
|
||||
#[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))
|
||||
}
|
||||
|
||||
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(
|
||||
state: &RuntimeState,
|
||||
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(
|
||||
pressured_support_adjusted_share_price_scalar: f64,
|
||||
book_value_per_share: f64,
|
||||
|
|
@ -3144,6 +3243,8 @@ pub fn runtime_company_annual_stock_issue_state(
|
|||
.eligible_for_bankruptcy_branch
|
||||
&& !runtime_company_annual_deep_distress_state(state, company_id)?
|
||||
.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)?
|
||||
.eligible_for_single_batch_repurchase
|
||||
&& passes_share_price_floor == Some(true)
|
||||
|
|
@ -7621,6 +7722,121 @@ mod tests {
|
|||
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]
|
||||
fn derives_annual_stock_issue_state_from_rehosted_owner_state() {
|
||||
let mut year_stat_family_qword_bits = vec![
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
CalendarPoint, RuntimeState, runtime_company_annual_creditor_pressure_state,
|
||||
runtime_company_annual_deep_distress_state, runtime_company_annual_finance_state,
|
||||
runtime_company_annual_stock_issue_state, runtime_company_annual_stock_repurchase_state,
|
||||
runtime_company_unassigned_share_pool,
|
||||
CalendarPoint, RuntimeState, runtime_company_annual_bond_policy_state,
|
||||
runtime_company_annual_creditor_pressure_state, runtime_company_annual_deep_distress_state,
|
||||
runtime_company_annual_finance_state, runtime_company_annual_stock_issue_state,
|
||||
runtime_company_annual_stock_repurchase_state, runtime_company_unassigned_share_pool,
|
||||
};
|
||||
|
||||
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_net_profit_floor: Option<i64>,
|
||||
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_building_density_growth_setting: 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
|
||||
.selected_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 =
|
||||
state.selected_company_id.and_then(|company_id| {
|
||||
runtime_company_annual_stock_repurchase_state(state, company_id)
|
||||
|
|
@ -524,6 +538,45 @@ impl RuntimeSummary {
|
|||
selected_company_deep_distress_state
|
||||
.as_ref()
|
||||
.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_state
|
||||
.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]
|
||||
fn summarizes_selected_company_stock_issue_state() {
|
||||
let mut year_stat_family_qword_bits = vec![
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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-
|
||||
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
|
||||
growth setting plus the linked chairman personality byte, which is enough to run the annual
|
||||
stock-repurchase gate headlessly as another pure reader
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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.
|
||||
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
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue