168 lines
6.6 KiB
Rust
168 lines
6.6 KiB
Rust
use crate::derived::{
|
|
runtime_company_annual_finance_state, runtime_company_control_transfer_stat_value_f64,
|
|
runtime_company_stat_value_f64, runtime_company_support_adjusted_share_price_scalar,
|
|
runtime_round_f64_to_i64, runtime_world_annual_finance_mode_active,
|
|
runtime_world_bankruptcy_allowed,
|
|
};
|
|
use crate::event::metrics::{
|
|
RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER, RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
|
|
RuntimeCompanyStatSelector,
|
|
};
|
|
use crate::state::{
|
|
RuntimeCompanyAnnualCreditorPressureState, RuntimeCompanyAnnualDeepDistressState, RuntimeState,
|
|
};
|
|
|
|
pub fn runtime_company_annual_creditor_pressure_state(
|
|
state: &RuntimeState,
|
|
company_id: u32,
|
|
) -> Option<RuntimeCompanyAnnualCreditorPressureState> {
|
|
let annual_finance_state = runtime_company_annual_finance_state(state, company_id)?;
|
|
let current_cash_plus_slot_12_total =
|
|
runtime_company_control_transfer_stat_value_f64(state, company_id, 0x12)
|
|
.and_then(runtime_round_f64_to_i64)
|
|
.and_then(|slot_12| {
|
|
runtime_company_control_transfer_stat_value_f64(
|
|
state,
|
|
company_id,
|
|
RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
|
|
)
|
|
.and_then(runtime_round_f64_to_i64)
|
|
.map(|current_cash| current_cash + slot_12)
|
|
});
|
|
let support_adjusted_share_price_scalar =
|
|
runtime_company_support_adjusted_share_price_scalar(state, company_id)
|
|
.and_then(runtime_round_f64_to_i64);
|
|
let current_fuel_cost = runtime_company_stat_value_f64(
|
|
state,
|
|
company_id,
|
|
RuntimeCompanyStatSelector {
|
|
family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
|
|
slot_id: 0x09,
|
|
},
|
|
)
|
|
.and_then(runtime_round_f64_to_i64);
|
|
let recent_bad_net_profit_year_count = annual_finance_state
|
|
.trailing_full_year_net_profits
|
|
.iter()
|
|
.take(3)
|
|
.filter(|value| **value < -10_000)
|
|
.count() as u32;
|
|
let recent_peak_revenue = annual_finance_state
|
|
.trailing_full_year_revenues
|
|
.iter()
|
|
.take(3)
|
|
.copied()
|
|
.max();
|
|
let recent_three_year_net_profit_total =
|
|
if annual_finance_state.trailing_full_year_net_profits.len() >= 3 {
|
|
Some(
|
|
annual_finance_state
|
|
.trailing_full_year_net_profits
|
|
.iter()
|
|
.take(3)
|
|
.sum::<i64>(),
|
|
)
|
|
} else {
|
|
None
|
|
};
|
|
let pressure_ladder_cash_floor = recent_peak_revenue.map(|revenue| {
|
|
if revenue < 120_000 {
|
|
-600_000
|
|
} else if revenue < 230_000 {
|
|
-1_100_000
|
|
} else if revenue < 340_000 {
|
|
-1_600_000
|
|
} else {
|
|
-2_000_000
|
|
}
|
|
});
|
|
let support_adjusted_share_price_floor = Some(if recent_bad_net_profit_year_count == 3 {
|
|
20
|
|
} else {
|
|
15
|
|
});
|
|
let current_fuel_cost_floor = pressure_ladder_cash_floor.map(|floor| floor * 8 / 100);
|
|
let eligible_for_bankruptcy_branch = runtime_world_annual_finance_mode_active(state)
|
|
== Some(true)
|
|
&& runtime_world_bankruptcy_allowed(state) == Some(true)
|
|
&& annual_finance_state
|
|
.years_since_last_bankruptcy
|
|
.is_some_and(|years| years >= 13)
|
|
&& annual_finance_state
|
|
.years_since_founding
|
|
.is_some_and(|years| years >= 4)
|
|
&& recent_bad_net_profit_year_count >= 2
|
|
&& current_cash_plus_slot_12_total
|
|
.zip(pressure_ladder_cash_floor)
|
|
.is_some_and(|(value, floor)| value <= floor)
|
|
&& support_adjusted_share_price_scalar
|
|
.zip(support_adjusted_share_price_floor)
|
|
.is_some_and(|(value, floor)| value >= floor)
|
|
&& current_fuel_cost
|
|
.zip(current_fuel_cost_floor)
|
|
.is_some_and(|(value, floor)| value <= floor)
|
|
&& recent_three_year_net_profit_total.is_some_and(|value| value <= -60_000);
|
|
Some(RuntimeCompanyAnnualCreditorPressureState {
|
|
company_id,
|
|
annual_mode_active: runtime_world_annual_finance_mode_active(state),
|
|
bankruptcy_allowed: runtime_world_bankruptcy_allowed(state),
|
|
years_since_last_bankruptcy: annual_finance_state.years_since_last_bankruptcy,
|
|
years_since_founding: annual_finance_state.years_since_founding,
|
|
recent_bad_net_profit_year_count,
|
|
recent_peak_revenue,
|
|
recent_three_year_net_profit_total,
|
|
pressure_ladder_cash_floor,
|
|
current_cash_plus_slot_12_total,
|
|
support_adjusted_share_price_floor,
|
|
support_adjusted_share_price_scalar,
|
|
current_fuel_cost,
|
|
current_fuel_cost_floor,
|
|
eligible_for_bankruptcy_branch,
|
|
})
|
|
}
|
|
|
|
pub fn runtime_company_annual_deep_distress_state(
|
|
state: &RuntimeState,
|
|
company_id: u32,
|
|
) -> Option<RuntimeCompanyAnnualDeepDistressState> {
|
|
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 recent_first_three_net_profit_years = annual_finance_state
|
|
.trailing_full_year_net_profits
|
|
.iter()
|
|
.take(3)
|
|
.copied()
|
|
.collect::<Vec<_>>();
|
|
let deep_distress_cash_floor = Some(-300_000);
|
|
let deep_distress_net_profit_floor = Some(-20_000);
|
|
let eligible_for_bankruptcy_fallback = runtime_world_bankruptcy_allowed(state) == Some(true)
|
|
&& current_cash
|
|
.zip(deep_distress_cash_floor)
|
|
.is_some_and(|(value, floor)| value <= floor)
|
|
&& annual_finance_state
|
|
.years_since_founding
|
|
.is_some_and(|years| years >= 3)
|
|
&& recent_first_three_net_profit_years.len() == 3
|
|
&& recent_first_three_net_profit_years
|
|
.iter()
|
|
.all(|value| *value <= deep_distress_net_profit_floor.unwrap())
|
|
&& annual_finance_state
|
|
.years_since_last_bankruptcy
|
|
.is_some_and(|years| years >= 5);
|
|
Some(RuntimeCompanyAnnualDeepDistressState {
|
|
company_id,
|
|
bankruptcy_allowed: runtime_world_bankruptcy_allowed(state),
|
|
years_since_founding: annual_finance_state.years_since_founding,
|
|
years_since_last_bankruptcy: annual_finance_state.years_since_last_bankruptcy,
|
|
current_cash,
|
|
recent_first_three_net_profit_years,
|
|
deep_distress_cash_floor,
|
|
deep_distress_net_profit_floor,
|
|
eligible_for_bankruptcy_fallback,
|
|
})
|
|
}
|