Rehost annual dividend policy branch
This commit is contained in:
parent
fa86a95f0d
commit
90d213c9ed
6 changed files with 700 additions and 21 deletions
|
|
@ -99,7 +99,11 @@ distress bankruptcy fallback is now rehosted on that same owner surface too, usi
|
||||||
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
|
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
|
cash window plus the linked-transit threshold split to stage `500000` principal issue counts as a
|
||||||
pure runtime reader.
|
pure runtime reader. The annual dividend lane now runs there too: the runtime now rehosts the
|
||||||
|
shared year-or-control-transfer metric seam, the board-approved dividend ceiling helper, and the
|
||||||
|
full annual dividend adjustment branch over owned current cash, public float, current dividend,
|
||||||
|
building-growth policy, and recent profit history instead of leaving that policy on shell-side
|
||||||
|
dialog notes.
|
||||||
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.
|
||||||
|
|
|
||||||
|
|
@ -53,23 +53,24 @@ pub use runtime::{
|
||||||
RuntimeCargoPriceTarget, RuntimeCargoProductionTarget, RuntimeChairmanMetric,
|
RuntimeCargoPriceTarget, RuntimeCargoProductionTarget, RuntimeChairmanMetric,
|
||||||
RuntimeChairmanProfile, RuntimeChairmanTarget, RuntimeCompany,
|
RuntimeChairmanProfile, RuntimeChairmanTarget, RuntimeCompany,
|
||||||
RuntimeCompanyAnnualBondPolicyState, RuntimeCompanyAnnualCreditorPressureState,
|
RuntimeCompanyAnnualBondPolicyState, RuntimeCompanyAnnualCreditorPressureState,
|
||||||
RuntimeCompanyAnnualDeepDistressState, RuntimeCompanyAnnualFinanceState,
|
RuntimeCompanyAnnualDeepDistressState, RuntimeCompanyAnnualDividendPolicyState,
|
||||||
RuntimeCompanyAnnualStockIssueState, RuntimeCompanyAnnualStockRepurchaseState,
|
RuntimeCompanyAnnualFinanceState, RuntimeCompanyAnnualStockIssueState,
|
||||||
RuntimeCompanyBondSlot, RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind,
|
RuntimeCompanyAnnualStockRepurchaseState, RuntimeCompanyBondSlot,
|
||||||
RuntimeCompanyMarketMetric, RuntimeCompanyMarketState, RuntimeCompanyMetric,
|
RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind, RuntimeCompanyMarketMetric,
|
||||||
RuntimeCompanyStatBandCandidate, RuntimeCompanyStatSelector, RuntimeCompanyTarget,
|
RuntimeCompanyMarketState, RuntimeCompanyMetric, 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,
|
||||||
runtime_company_annual_bond_policy_state, runtime_company_annual_creditor_pressure_state,
|
RuntimeWorldIssueState, RuntimeWorldRestoreState, 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_dividend_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_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,
|
||||||
|
|
|
||||||
|
|
@ -339,6 +339,43 @@ pub struct RuntimeCompanyAnnualBondPolicyState {
|
||||||
pub eligible_for_bond_issue_branch: bool,
|
pub eligible_for_bond_issue_branch: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct RuntimeCompanyAnnualDividendPolicyState {
|
||||||
|
pub company_id: u32,
|
||||||
|
#[serde(default)]
|
||||||
|
pub annual_mode_active: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub dividend_adjustment_allowed: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub years_since_last_dividend: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub years_since_founding: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub outstanding_shares: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub unassigned_share_pool: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub weighted_recent_net_profit_total: Option<i64>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub weighted_recent_net_profit_average: Option<i64>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub current_cash: Option<i64>,
|
||||||
|
pub tiny_unassigned_share_cash_supplement_branch: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub tentative_target_dividend_per_share_tenths: Option<i64>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub current_dividend_per_share_tenths: Option<i64>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub building_density_growth_setting: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub growth_adjusted_current_dividend_per_share_tenths: Option<i64>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub board_approved_dividend_rate_ceiling_tenths: Option<i64>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub proposed_dividend_per_share_tenths: Option<i64>,
|
||||||
|
pub eligible_for_dividend_adjustment_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)]
|
||||||
|
|
@ -2615,6 +2652,34 @@ fn runtime_company_trailing_full_year_stat_series(
|
||||||
Some((year_words, values))
|
Some((year_words, values))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn runtime_company_year_or_control_transfer_metric_value_f64(
|
||||||
|
state: &RuntimeState,
|
||||||
|
company_id: u32,
|
||||||
|
year_word: u32,
|
||||||
|
slot_id: u32,
|
||||||
|
) -> Option<f64> {
|
||||||
|
let current_year_word = u32::from(state.world_restore.packed_year_word_raw_u16?);
|
||||||
|
if year_word == current_year_word {
|
||||||
|
runtime_company_stat_value_f64(
|
||||||
|
state,
|
||||||
|
company_id,
|
||||||
|
RuntimeCompanyStatSelector {
|
||||||
|
family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
|
||||||
|
slot_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
runtime_company_stat_value_f64(
|
||||||
|
state,
|
||||||
|
company_id,
|
||||||
|
RuntimeCompanyStatSelector {
|
||||||
|
family_id: year_word,
|
||||||
|
slot_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn runtime_world_issue_opinion_term_sum_raw(
|
pub fn runtime_world_issue_opinion_term_sum_raw(
|
||||||
state: &RuntimeState,
|
state: &RuntimeState,
|
||||||
issue_id: u32,
|
issue_id: u32,
|
||||||
|
|
@ -3115,6 +3180,224 @@ pub fn runtime_company_annual_bond_policy_state(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn runtime_company_board_approved_dividend_rate_ceiling_f64(
|
||||||
|
state: &RuntimeState,
|
||||||
|
company_id: u32,
|
||||||
|
) -> Option<f64> {
|
||||||
|
const REVENUE_GUARD_DIVISOR: f64 = 2.0;
|
||||||
|
const EARLY_SUPPORT_MULTIPLIER: f64 = 0.05;
|
||||||
|
const HISTORICAL_GUARD_SCALE: f64 = 1.25;
|
||||||
|
const ANCHOR_SCALE: f64 = 0.35;
|
||||||
|
|
||||||
|
let market_state = state.service_state.company_market_state.get(&company_id)?;
|
||||||
|
let current_cash = runtime_company_control_transfer_stat_value_f64(
|
||||||
|
state,
|
||||||
|
company_id,
|
||||||
|
RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
|
||||||
|
)?;
|
||||||
|
let shares_plus_one = market_state.outstanding_shares.checked_add(1)?;
|
||||||
|
let shares_plus_one_f64 = shares_plus_one as f64;
|
||||||
|
let current_cash_per_share_ceiling = current_cash / shares_plus_one_f64;
|
||||||
|
let current_year_word = u32::from(state.world_restore.packed_year_word_raw_u16?);
|
||||||
|
let years_since_founding = current_year_word
|
||||||
|
.checked_sub(market_state.founding_year)
|
||||||
|
.unwrap_or(0)
|
||||||
|
.min(3);
|
||||||
|
let start_year_offset = if state.world_restore.partial_year_progress_raw_u8 == Some(0x0c) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut strongest_net_profit_guard = 0.0f64;
|
||||||
|
let mut strongest_revenue_guard = 0.0f64;
|
||||||
|
if start_year_offset <= years_since_founding {
|
||||||
|
for year_offset in start_year_offset..=years_since_founding {
|
||||||
|
let year_word = current_year_word.checked_sub(year_offset)?;
|
||||||
|
let net_profit = runtime_company_year_or_control_transfer_metric_value_f64(
|
||||||
|
state, company_id, year_word, 0x2b,
|
||||||
|
)?;
|
||||||
|
strongest_net_profit_guard = strongest_net_profit_guard.max(net_profit);
|
||||||
|
|
||||||
|
let revenue = runtime_company_year_or_control_transfer_metric_value_f64(
|
||||||
|
state, company_id, year_word, 0x2c,
|
||||||
|
)?;
|
||||||
|
strongest_revenue_guard = strongest_revenue_guard.max(revenue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut historical_guard_total =
|
||||||
|
strongest_net_profit_guard.min(strongest_revenue_guard / REVENUE_GUARD_DIVISOR);
|
||||||
|
if years_since_founding <= 1 {
|
||||||
|
let early_support_guard = market_state.outstanding_shares as f64
|
||||||
|
* runtime_decode_saved_f32_value_f64(
|
||||||
|
market_state.young_company_support_scalar_raw_u32,
|
||||||
|
)?
|
||||||
|
* EARLY_SUPPORT_MULTIPLIER;
|
||||||
|
historical_guard_total = historical_guard_total.max(early_support_guard);
|
||||||
|
}
|
||||||
|
|
||||||
|
let historical_guard_per_share_ceiling =
|
||||||
|
historical_guard_total / shares_plus_one_f64 * HISTORICAL_GUARD_SCALE;
|
||||||
|
let mut ceiling = current_cash_per_share_ceiling.min(historical_guard_per_share_ceiling);
|
||||||
|
let anchor_value = if years_since_founding == 0 {
|
||||||
|
runtime_decode_saved_f32_value_f64(market_state.young_company_support_scalar_raw_u32)?
|
||||||
|
} else {
|
||||||
|
runtime_company_year_or_control_transfer_metric_value_f64(
|
||||||
|
state,
|
||||||
|
company_id,
|
||||||
|
current_year_word.checked_sub(1)?,
|
||||||
|
0x1c,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
ceiling = ceiling.min(anchor_value * ANCHOR_SCALE);
|
||||||
|
Some(ceiling.max(0.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn runtime_company_annual_dividend_policy_state(
|
||||||
|
state: &RuntimeState,
|
||||||
|
company_id: u32,
|
||||||
|
) -> Option<RuntimeCompanyAnnualDividendPolicyState> {
|
||||||
|
const WEIGHTED_NET_PROFIT_DIVISOR: f64 = 6.0;
|
||||||
|
const CASH_SUPPLEMENT_DIVISOR: f64 = 3.0;
|
||||||
|
const STANDARD_TARGET_DIVISOR: f64 = 6.0;
|
||||||
|
const DIVIDEND_DELTA_COLLAPSE_THRESHOLD: f64 = 0.1;
|
||||||
|
const GROWTH_SETTING_ONE_DIVIDEND_SCALE: f64 = 0.66;
|
||||||
|
|
||||||
|
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 current_year_word = u32::from(state.world_restore.packed_year_word_raw_u16?);
|
||||||
|
let current_dividend_per_share =
|
||||||
|
runtime_company_control_transfer_stat_value_f64(state, company_id, 0x20)?;
|
||||||
|
let building_density_growth_setting = runtime_world_building_density_growth_setting(state);
|
||||||
|
let weighted_recent_net_profit_total = Some(
|
||||||
|
runtime_company_year_or_control_transfer_metric_value_f64(
|
||||||
|
state,
|
||||||
|
company_id,
|
||||||
|
current_year_word,
|
||||||
|
0x2b,
|
||||||
|
)
|
||||||
|
.and_then(runtime_round_f64_to_i64)?
|
||||||
|
.checked_mul(3)?
|
||||||
|
.checked_add(
|
||||||
|
runtime_company_year_or_control_transfer_metric_value_f64(
|
||||||
|
state,
|
||||||
|
company_id,
|
||||||
|
current_year_word.checked_sub(1)?,
|
||||||
|
0x2b,
|
||||||
|
)
|
||||||
|
.and_then(runtime_round_f64_to_i64)?
|
||||||
|
.checked_mul(2)?,
|
||||||
|
)?
|
||||||
|
.checked_add(
|
||||||
|
runtime_company_year_or_control_transfer_metric_value_f64(
|
||||||
|
state,
|
||||||
|
company_id,
|
||||||
|
current_year_word.checked_sub(2)?,
|
||||||
|
0x2b,
|
||||||
|
)
|
||||||
|
.and_then(runtime_round_f64_to_i64)?,
|
||||||
|
)?,
|
||||||
|
);
|
||||||
|
let weighted_recent_net_profit_average = weighted_recent_net_profit_total
|
||||||
|
.and_then(|value| runtime_round_f64_to_i64(value as f64 / WEIGHTED_NET_PROFIT_DIVISOR));
|
||||||
|
let tiny_unassigned_share_cash_supplement_branch =
|
||||||
|
annual_finance_state.unassigned_share_pool <= 1_000;
|
||||||
|
let tentative_target_dividend_per_share =
|
||||||
|
weighted_recent_net_profit_average.and_then(|value| {
|
||||||
|
if annual_finance_state.outstanding_shares == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let shares = annual_finance_state.outstanding_shares as f64;
|
||||||
|
if tiny_unassigned_share_cash_supplement_branch {
|
||||||
|
let cash_component = current_cash.unwrap_or(0).max(0) as f64;
|
||||||
|
Some(
|
||||||
|
((value as f64 / CASH_SUPPLEMENT_DIVISOR)
|
||||||
|
+ cash_component / CASH_SUPPLEMENT_DIVISOR)
|
||||||
|
/ shares,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Some((value as f64 / STANDARD_TARGET_DIVISOR) / shares)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let growth_adjusted_current_dividend_per_share = Some(match building_density_growth_setting {
|
||||||
|
Some(1) => current_dividend_per_share * GROWTH_SETTING_ONE_DIVIDEND_SCALE,
|
||||||
|
Some(2) => 0.0,
|
||||||
|
_ => current_dividend_per_share,
|
||||||
|
});
|
||||||
|
let proposed_dividend_per_share = if tentative_target_dividend_per_share
|
||||||
|
.is_some_and(|value| value <= DIVIDEND_DELTA_COLLAPSE_THRESHOLD)
|
||||||
|
{
|
||||||
|
Some(0.0)
|
||||||
|
} else {
|
||||||
|
growth_adjusted_current_dividend_per_share
|
||||||
|
.zip(tentative_target_dividend_per_share)
|
||||||
|
.map(|(current_dividend, target)| {
|
||||||
|
((current_dividend + target + DIVIDEND_DELTA_COLLAPSE_THRESHOLD) / 2.0 * 10.0)
|
||||||
|
.round()
|
||||||
|
/ 10.0
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let board_approved_dividend_rate_ceiling =
|
||||||
|
runtime_company_board_approved_dividend_rate_ceiling_f64(state, company_id);
|
||||||
|
let proposed_dividend_per_share = proposed_dividend_per_share
|
||||||
|
.zip(board_approved_dividend_rate_ceiling)
|
||||||
|
.map(|(proposed, ceiling)| proposed.min(ceiling));
|
||||||
|
let current_dividend_per_share_tenths =
|
||||||
|
runtime_round_f64_to_i64(current_dividend_per_share * 10.0);
|
||||||
|
let eligible_for_dividend_adjustment_branch = runtime_world_annual_finance_mode_active(state)
|
||||||
|
== Some(true)
|
||||||
|
&& runtime_world_dividend_adjustment_allowed(state) == Some(true)
|
||||||
|
&& annual_finance_state
|
||||||
|
.years_since_last_dividend
|
||||||
|
.is_some_and(|years| years >= 1)
|
||||||
|
&& annual_finance_state
|
||||||
|
.years_since_founding
|
||||||
|
.is_some_and(|years| years >= 2)
|
||||||
|
&& !runtime_company_annual_creditor_pressure_state(state, company_id)?
|
||||||
|
.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
|
||||||
|
&& !runtime_company_annual_stock_issue_state(state, company_id)?
|
||||||
|
.eligible_for_double_tranche_issue
|
||||||
|
&& proposed_dividend_per_share.and_then(|value| runtime_round_f64_to_i64(value * 10.0))
|
||||||
|
!= current_dividend_per_share_tenths;
|
||||||
|
Some(RuntimeCompanyAnnualDividendPolicyState {
|
||||||
|
company_id,
|
||||||
|
annual_mode_active: runtime_world_annual_finance_mode_active(state),
|
||||||
|
dividend_adjustment_allowed: runtime_world_dividend_adjustment_allowed(state),
|
||||||
|
years_since_last_dividend: annual_finance_state.years_since_last_dividend,
|
||||||
|
years_since_founding: annual_finance_state.years_since_founding,
|
||||||
|
outstanding_shares: Some(annual_finance_state.outstanding_shares),
|
||||||
|
unassigned_share_pool: Some(annual_finance_state.unassigned_share_pool),
|
||||||
|
weighted_recent_net_profit_total,
|
||||||
|
weighted_recent_net_profit_average,
|
||||||
|
current_cash,
|
||||||
|
tiny_unassigned_share_cash_supplement_branch,
|
||||||
|
tentative_target_dividend_per_share_tenths: tentative_target_dividend_per_share
|
||||||
|
.and_then(|value| runtime_round_f64_to_i64(value * 10.0)),
|
||||||
|
current_dividend_per_share_tenths,
|
||||||
|
building_density_growth_setting,
|
||||||
|
growth_adjusted_current_dividend_per_share_tenths:
|
||||||
|
growth_adjusted_current_dividend_per_share
|
||||||
|
.and_then(|value| runtime_round_f64_to_i64(value * 10.0)),
|
||||||
|
board_approved_dividend_rate_ceiling_tenths: board_approved_dividend_rate_ceiling
|
||||||
|
.and_then(|value| runtime_round_f64_to_i64(value * 10.0)),
|
||||||
|
proposed_dividend_per_share_tenths: proposed_dividend_per_share
|
||||||
|
.and_then(|value| runtime_round_f64_to_i64(value * 10.0)),
|
||||||
|
eligible_for_dividend_adjustment_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,
|
||||||
|
|
@ -8019,6 +8302,163 @@ mod tests {
|
||||||
assert!(stock_issue_state.eligible_for_double_tranche_issue);
|
assert!(stock_issue_state.eligible_for_double_tranche_issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derives_annual_dividend_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();
|
||||||
|
};
|
||||||
|
let write_prior_year_value =
|
||||||
|
|bits: &mut Vec<u64>, slot_id: u32, year_delta: u32, value: f64| {
|
||||||
|
let index = (slot_id * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN + year_delta) as usize;
|
||||||
|
bits[index] = value.to_bits();
|
||||||
|
};
|
||||||
|
write_current_value(&mut year_stat_family_qword_bits, 0x0d, 300_000.0);
|
||||||
|
write_current_value(&mut year_stat_family_qword_bits, 0x01, 300_000.0);
|
||||||
|
write_current_value(&mut year_stat_family_qword_bits, 0x09, -180_000.0);
|
||||||
|
write_prior_year_value(&mut year_stat_family_qword_bits, 0x01, 1, 280_000.0);
|
||||||
|
write_prior_year_value(&mut year_stat_family_qword_bits, 0x09, 1, -190_000.0);
|
||||||
|
write_prior_year_value(&mut year_stat_family_qword_bits, 0x01, 2, 260_000.0);
|
||||||
|
write_prior_year_value(&mut year_stat_family_qword_bits, 0x09, 2, -200_000.0);
|
||||||
|
write_prior_year_value(&mut year_stat_family_qword_bits, 0x1c, 1, 5.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 {
|
||||||
|
packed_year_word_raw_u16: Some(1845),
|
||||||
|
partial_year_progress_raw_u8: Some(0x0c),
|
||||||
|
dividend_policy_raw_u8: Some(0),
|
||||||
|
dividend_adjustment_allowed: Some(true),
|
||||||
|
stock_issue_and_buyback_policy_raw_u8: Some(0),
|
||||||
|
stock_issue_and_buyback_allowed: Some(true),
|
||||||
|
bond_issue_and_repayment_policy_raw_u8: Some(0),
|
||||||
|
bond_issue_and_repayment_allowed: Some(true),
|
||||||
|
bankruptcy_policy_raw_u8: Some(0),
|
||||||
|
bankruptcy_allowed: Some(true),
|
||||||
|
building_density_growth_setting_raw_u32: Some(1),
|
||||||
|
..RuntimeWorldRestoreState::default()
|
||||||
|
},
|
||||||
|
metadata: BTreeMap::new(),
|
||||||
|
companies: vec![RuntimeCompany {
|
||||||
|
company_id: 15,
|
||||||
|
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![RuntimeChairmanProfile {
|
||||||
|
profile_id: 3,
|
||||||
|
name: "Chairman Three".to_string(),
|
||||||
|
active: true,
|
||||||
|
current_cash: 0,
|
||||||
|
linked_company_id: Some(15),
|
||||||
|
company_holdings: BTreeMap::from([(15, 9_500)]),
|
||||||
|
holdings_value_total: 0,
|
||||||
|
net_worth_total: 0,
|
||||||
|
purchasing_power_total: 0,
|
||||||
|
}],
|
||||||
|
selected_chairman_profile_id: None,
|
||||||
|
trains: Vec::new(),
|
||||||
|
locomotive_catalog: Vec::new(),
|
||||||
|
cargo_catalog: Vec::new(),
|
||||||
|
territories: Vec::new(),
|
||||||
|
company_territory_track_piece_counts: Vec::new(),
|
||||||
|
company_territory_access: Vec::new(),
|
||||||
|
packed_event_collection: None,
|
||||||
|
event_runtime_records: Vec::new(),
|
||||||
|
candidate_availability: BTreeMap::new(),
|
||||||
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
|
all_cargo_price_override: None,
|
||||||
|
named_cargo_price_overrides: BTreeMap::new(),
|
||||||
|
all_cargo_production_override: None,
|
||||||
|
factory_cargo_production_override: None,
|
||||||
|
farm_mine_cargo_production_override: None,
|
||||||
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
|
special_conditions: BTreeMap::new(),
|
||||||
|
service_state: RuntimeServiceState {
|
||||||
|
company_market_state: BTreeMap::from([(
|
||||||
|
15,
|
||||||
|
RuntimeCompanyMarketState {
|
||||||
|
outstanding_shares: 10_000,
|
||||||
|
founding_year: 1840,
|
||||||
|
last_dividend_year: 1844,
|
||||||
|
year_stat_family_qword_bits,
|
||||||
|
direct_control_transfer_float_fields_raw_u32: BTreeMap::from([(
|
||||||
|
0x33f,
|
||||||
|
0.4f32.to_bits(),
|
||||||
|
)]),
|
||||||
|
..RuntimeCompanyMarketState::default()
|
||||||
|
},
|
||||||
|
)]),
|
||||||
|
..RuntimeServiceState::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let dividend_state = runtime_company_annual_dividend_policy_state(&state, 15)
|
||||||
|
.expect("annual dividend policy state");
|
||||||
|
assert_eq!(dividend_state.years_since_last_dividend, Some(1));
|
||||||
|
assert_eq!(dividend_state.years_since_founding, Some(5));
|
||||||
|
assert_eq!(dividend_state.outstanding_shares, Some(10_000));
|
||||||
|
assert_eq!(dividend_state.unassigned_share_pool, Some(500));
|
||||||
|
assert_eq!(
|
||||||
|
dividend_state.weighted_recent_net_profit_total,
|
||||||
|
Some(600_000)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
dividend_state.weighted_recent_net_profit_average,
|
||||||
|
Some(100_000)
|
||||||
|
);
|
||||||
|
assert_eq!(dividend_state.current_cash, Some(300_000));
|
||||||
|
assert!(dividend_state.tiny_unassigned_share_cash_supplement_branch);
|
||||||
|
assert_eq!(
|
||||||
|
dividend_state.tentative_target_dividend_per_share_tenths,
|
||||||
|
Some(133)
|
||||||
|
);
|
||||||
|
assert_eq!(dividend_state.current_dividend_per_share_tenths, Some(4));
|
||||||
|
assert_eq!(
|
||||||
|
dividend_state.growth_adjusted_current_dividend_per_share_tenths,
|
||||||
|
Some(3)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
dividend_state.board_approved_dividend_rate_ceiling_tenths,
|
||||||
|
Some(18)
|
||||||
|
);
|
||||||
|
assert_eq!(dividend_state.proposed_dividend_per_share_tenths, Some(18));
|
||||||
|
assert!(dividend_state.eligible_for_dividend_adjustment_branch);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reads_company_market_metrics_from_annual_finance_reader() {
|
fn reads_company_market_metrics_from_annual_finance_reader() {
|
||||||
let current_issue_calendar_word = 0x0101_0726;
|
let current_issue_calendar_word = 0x0101_0726;
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@ use serde::{Deserialize, Serialize};
|
||||||
use crate::{
|
use crate::{
|
||||||
CalendarPoint, RuntimeState, runtime_company_annual_bond_policy_state,
|
CalendarPoint, RuntimeState, 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,
|
||||||
runtime_company_annual_finance_state, runtime_company_annual_stock_issue_state,
|
runtime_company_annual_dividend_policy_state, runtime_company_annual_finance_state,
|
||||||
runtime_company_annual_stock_repurchase_state, runtime_company_unassigned_share_pool,
|
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 {
|
fn raw_u32_to_f32_text(raw: u32) -> String {
|
||||||
|
|
@ -156,6 +157,16 @@ pub struct RuntimeSummary {
|
||||||
pub selected_company_stock_issue_passes_issue_cooldown_gate: Option<bool>,
|
pub selected_company_stock_issue_passes_issue_cooldown_gate: Option<bool>,
|
||||||
pub selected_company_stock_issue_passes_coupon_price_to_book_gate: Option<bool>,
|
pub selected_company_stock_issue_passes_coupon_price_to_book_gate: Option<bool>,
|
||||||
pub selected_company_stock_issue_eligible_for_double_tranche: Option<bool>,
|
pub selected_company_stock_issue_eligible_for_double_tranche: Option<bool>,
|
||||||
|
pub selected_company_dividend_weighted_recent_net_profit_total: Option<i64>,
|
||||||
|
pub selected_company_dividend_weighted_recent_net_profit_average: Option<i64>,
|
||||||
|
pub selected_company_dividend_current_cash: Option<i64>,
|
||||||
|
pub selected_company_dividend_tiny_unassigned_share_cash_supplement_branch: Option<bool>,
|
||||||
|
pub selected_company_dividend_tentative_target_per_share_tenths: Option<i64>,
|
||||||
|
pub selected_company_dividend_current_per_share_tenths: Option<i64>,
|
||||||
|
pub selected_company_dividend_growth_adjusted_current_per_share_tenths: Option<i64>,
|
||||||
|
pub selected_company_dividend_board_approved_ceiling_tenths: Option<i64>,
|
||||||
|
pub selected_company_dividend_proposed_per_share_tenths: Option<i64>,
|
||||||
|
pub selected_company_dividend_eligible_for_adjustment_branch: Option<bool>,
|
||||||
pub player_count: usize,
|
pub player_count: usize,
|
||||||
pub chairman_profile_count: usize,
|
pub chairman_profile_count: usize,
|
||||||
pub active_chairman_profile_count: usize,
|
pub active_chairman_profile_count: usize,
|
||||||
|
|
@ -262,6 +273,9 @@ impl RuntimeSummary {
|
||||||
let selected_company_stock_issue_state = state
|
let selected_company_stock_issue_state = state
|
||||||
.selected_company_id
|
.selected_company_id
|
||||||
.and_then(|company_id| runtime_company_annual_stock_issue_state(state, company_id));
|
.and_then(|company_id| runtime_company_annual_stock_issue_state(state, company_id));
|
||||||
|
let selected_company_dividend_state = state
|
||||||
|
.selected_company_id
|
||||||
|
.and_then(|company_id| runtime_company_annual_dividend_policy_state(state, company_id));
|
||||||
Self {
|
Self {
|
||||||
calendar: state.calendar,
|
calendar: state.calendar,
|
||||||
calendar_projection_source: state.metadata.get("save_slice.calendar_source").cloned(),
|
calendar_projection_source: state.metadata.get("save_slice.calendar_source").cloned(),
|
||||||
|
|
@ -702,6 +716,51 @@ impl RuntimeSummary {
|
||||||
selected_company_stock_issue_state
|
selected_company_stock_issue_state
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|issue_state| issue_state.eligible_for_double_tranche_issue),
|
.map(|issue_state| issue_state.eligible_for_double_tranche_issue),
|
||||||
|
selected_company_dividend_weighted_recent_net_profit_total:
|
||||||
|
selected_company_dividend_state
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|dividend_state| dividend_state.weighted_recent_net_profit_total),
|
||||||
|
selected_company_dividend_weighted_recent_net_profit_average:
|
||||||
|
selected_company_dividend_state
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|dividend_state| dividend_state.weighted_recent_net_profit_average),
|
||||||
|
selected_company_dividend_current_cash: selected_company_dividend_state
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|dividend_state| dividend_state.current_cash),
|
||||||
|
selected_company_dividend_tiny_unassigned_share_cash_supplement_branch:
|
||||||
|
selected_company_dividend_state
|
||||||
|
.as_ref()
|
||||||
|
.map(|dividend_state| {
|
||||||
|
dividend_state.tiny_unassigned_share_cash_supplement_branch
|
||||||
|
}),
|
||||||
|
selected_company_dividend_tentative_target_per_share_tenths:
|
||||||
|
selected_company_dividend_state
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|dividend_state| {
|
||||||
|
dividend_state.tentative_target_dividend_per_share_tenths
|
||||||
|
}),
|
||||||
|
selected_company_dividend_current_per_share_tenths: selected_company_dividend_state
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|dividend_state| dividend_state.current_dividend_per_share_tenths),
|
||||||
|
selected_company_dividend_growth_adjusted_current_per_share_tenths:
|
||||||
|
selected_company_dividend_state
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|dividend_state| {
|
||||||
|
dividend_state.growth_adjusted_current_dividend_per_share_tenths
|
||||||
|
}),
|
||||||
|
selected_company_dividend_board_approved_ceiling_tenths:
|
||||||
|
selected_company_dividend_state
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|dividend_state| {
|
||||||
|
dividend_state.board_approved_dividend_rate_ceiling_tenths
|
||||||
|
}),
|
||||||
|
selected_company_dividend_proposed_per_share_tenths: selected_company_dividend_state
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|dividend_state| dividend_state.proposed_dividend_per_share_tenths),
|
||||||
|
selected_company_dividend_eligible_for_adjustment_branch:
|
||||||
|
selected_company_dividend_state
|
||||||
|
.as_ref()
|
||||||
|
.map(|dividend_state| dividend_state.eligible_for_dividend_adjustment_branch),
|
||||||
player_count: state.players.len(),
|
player_count: state.players.len(),
|
||||||
chairman_profile_count: state.chairman_profiles.len(),
|
chairman_profile_count: state.chairman_profiles.len(),
|
||||||
active_chairman_profile_count: state
|
active_chairman_profile_count: state
|
||||||
|
|
@ -3322,4 +3381,173 @@ mod tests {
|
||||||
Some(true)
|
Some(true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn summarizes_selected_company_annual_dividend_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
|
||||||
|
];
|
||||||
|
let write_current_value = |bits: &mut Vec<u64>, slot_id: u32, value: f64| {
|
||||||
|
let index = (slot_id * crate::RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN) as usize;
|
||||||
|
bits[index] = value.to_bits();
|
||||||
|
};
|
||||||
|
let write_prior_year_value =
|
||||||
|
|bits: &mut Vec<u64>, slot_id: u32, year_delta: u32, value: f64| {
|
||||||
|
let index =
|
||||||
|
(slot_id * crate::RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN + year_delta) as usize;
|
||||||
|
bits[index] = value.to_bits();
|
||||||
|
};
|
||||||
|
write_current_value(&mut year_stat_family_qword_bits, 0x0d, 300_000.0);
|
||||||
|
write_current_value(&mut year_stat_family_qword_bits, 0x01, 300_000.0);
|
||||||
|
write_current_value(&mut year_stat_family_qword_bits, 0x09, -180_000.0);
|
||||||
|
write_prior_year_value(&mut year_stat_family_qword_bits, 0x01, 1, 280_000.0);
|
||||||
|
write_prior_year_value(&mut year_stat_family_qword_bits, 0x09, 1, -190_000.0);
|
||||||
|
write_prior_year_value(&mut year_stat_family_qword_bits, 0x01, 2, 260_000.0);
|
||||||
|
write_prior_year_value(&mut year_stat_family_qword_bits, 0x09, 2, -200_000.0);
|
||||||
|
write_prior_year_value(&mut year_stat_family_qword_bits, 0x1c, 1, 5.0);
|
||||||
|
|
||||||
|
let state = RuntimeState {
|
||||||
|
calendar: CalendarPoint {
|
||||||
|
year: 1845,
|
||||||
|
month_slot: 0,
|
||||||
|
phase_slot: 0,
|
||||||
|
tick_slot: 0,
|
||||||
|
},
|
||||||
|
world_flags: BTreeMap::new(),
|
||||||
|
save_profile: crate::RuntimeSaveProfileState::default(),
|
||||||
|
world_restore: crate::RuntimeWorldRestoreState {
|
||||||
|
packed_year_word_raw_u16: Some(1845),
|
||||||
|
partial_year_progress_raw_u8: Some(0x0c),
|
||||||
|
dividend_policy_raw_u8: Some(0),
|
||||||
|
dividend_adjustment_allowed: Some(true),
|
||||||
|
stock_issue_and_buyback_policy_raw_u8: Some(0),
|
||||||
|
stock_issue_and_buyback_allowed: Some(true),
|
||||||
|
bond_issue_and_repayment_policy_raw_u8: Some(0),
|
||||||
|
bond_issue_and_repayment_allowed: Some(true),
|
||||||
|
bankruptcy_policy_raw_u8: Some(0),
|
||||||
|
bankruptcy_allowed: Some(true),
|
||||||
|
building_density_growth_setting_raw_u32: Some(1),
|
||||||
|
..crate::RuntimeWorldRestoreState::default()
|
||||||
|
},
|
||||||
|
metadata: BTreeMap::new(),
|
||||||
|
companies: vec![crate::RuntimeCompany {
|
||||||
|
company_id: 15,
|
||||||
|
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: crate::RuntimeTrackPieceCounts::default(),
|
||||||
|
}],
|
||||||
|
selected_company_id: Some(15),
|
||||||
|
players: Vec::new(),
|
||||||
|
selected_player_id: None,
|
||||||
|
chairman_profiles: vec![crate::RuntimeChairmanProfile {
|
||||||
|
profile_id: 3,
|
||||||
|
name: "Chairman Three".to_string(),
|
||||||
|
active: true,
|
||||||
|
current_cash: 0,
|
||||||
|
linked_company_id: Some(15),
|
||||||
|
company_holdings: BTreeMap::from([(15, 9_500)]),
|
||||||
|
holdings_value_total: 0,
|
||||||
|
net_worth_total: 0,
|
||||||
|
purchasing_power_total: 0,
|
||||||
|
}],
|
||||||
|
selected_chairman_profile_id: None,
|
||||||
|
trains: Vec::new(),
|
||||||
|
locomotive_catalog: Vec::new(),
|
||||||
|
cargo_catalog: Vec::new(),
|
||||||
|
territories: Vec::new(),
|
||||||
|
company_territory_track_piece_counts: Vec::new(),
|
||||||
|
company_territory_access: Vec::new(),
|
||||||
|
packed_event_collection: None,
|
||||||
|
event_runtime_records: Vec::new(),
|
||||||
|
candidate_availability: BTreeMap::new(),
|
||||||
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
|
all_cargo_price_override: None,
|
||||||
|
named_cargo_price_overrides: BTreeMap::new(),
|
||||||
|
all_cargo_production_override: None,
|
||||||
|
factory_cargo_production_override: None,
|
||||||
|
farm_mine_cargo_production_override: None,
|
||||||
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
|
special_conditions: BTreeMap::new(),
|
||||||
|
service_state: crate::RuntimeServiceState {
|
||||||
|
company_market_state: BTreeMap::from([(
|
||||||
|
15,
|
||||||
|
crate::RuntimeCompanyMarketState {
|
||||||
|
outstanding_shares: 10_000,
|
||||||
|
founding_year: 1840,
|
||||||
|
last_dividend_year: 1844,
|
||||||
|
year_stat_family_qword_bits,
|
||||||
|
direct_control_transfer_float_fields_raw_u32: BTreeMap::from([(
|
||||||
|
0x33f,
|
||||||
|
0.4f32.to_bits(),
|
||||||
|
)]),
|
||||||
|
..crate::RuntimeCompanyMarketState::default()
|
||||||
|
},
|
||||||
|
)]),
|
||||||
|
..crate::RuntimeServiceState::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let summary = RuntimeSummary::from_state(&state);
|
||||||
|
assert_eq!(
|
||||||
|
summary.selected_company_dividend_weighted_recent_net_profit_total,
|
||||||
|
Some(600_000)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
summary.selected_company_dividend_weighted_recent_net_profit_average,
|
||||||
|
Some(100_000)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
summary.selected_company_dividend_current_cash,
|
||||||
|
Some(300_000)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
summary.selected_company_dividend_tiny_unassigned_share_cash_supplement_branch,
|
||||||
|
Some(true)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
summary.selected_company_dividend_tentative_target_per_share_tenths,
|
||||||
|
Some(133)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
summary.selected_company_dividend_current_per_share_tenths,
|
||||||
|
Some(4)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
summary.selected_company_dividend_growth_adjusted_current_per_share_tenths,
|
||||||
|
Some(3)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
summary.selected_company_dividend_board_approved_ceiling_tenths,
|
||||||
|
Some(18)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
summary.selected_company_dividend_proposed_per_share_tenths,
|
||||||
|
Some(18)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
summary.selected_company_dividend_eligible_for_adjustment_branch,
|
||||||
|
Some(true)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,9 @@ The highest-value next passes are 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 bond, 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 annual dividend-adjustment branch now does as well through the
|
||||||
|
shared year-or-control-transfer reader and board-approved dividend ceiling helper; 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
|
||||||
- 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
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,10 @@ deep-distress bankruptcy fallback now rides the same owner-state seam too, using
|
||||||
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
|
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.
|
linked-transit threshold split to stage `500000` principal issue counts without shell ownership.
|
||||||
|
The annual dividend-adjustment lane now rides that same seam too: the runtime now rehosts the
|
||||||
|
shared year-or-control-transfer metric reader, the board-approved dividend ceiling helper, and the
|
||||||
|
full annual dividend branch over owned cash, public float, current dividend, and building-growth
|
||||||
|
policy instead of treating dividend changes as shell-dialog-only logic.
|
||||||
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