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-
|
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.
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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![
|
||||||
|
|
|
||||||
|
|
@ -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![
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue