Derive annual finance timing inputs
This commit is contained in:
parent
53f1078a84
commit
08f44debc7
6 changed files with 194 additions and 3 deletions
|
|
@ -71,7 +71,9 @@ so future issue-`0x38/0x39` closure can build on a broader owned restore-state w
|
||||||
another narrow one-off probe. The next company-side seam is now bundled too: a shared company
|
another narrow one-off probe. The next company-side seam is now bundled too: a shared company
|
||||||
market reader now exposes outstanding shares, assigned shares, public float, rounded cached share
|
market reader now exposes outstanding shares, assigned shares, public float, rounded cached share
|
||||||
price, salary lanes, bonus amount, and issue-calendar words from the owned annual-finance state
|
price, salary lanes, bonus amount, and issue-calendar words from the owned annual-finance state
|
||||||
instead of leaving that logic spread across summary helpers. A checked-in
|
instead of leaving that logic spread across summary helpers. The same annual-finance state now also
|
||||||
|
derives elapsed years since founding, last dividend, and last bankruptcy from the runtime calendar,
|
||||||
|
which lines up directly with the grounded annual finance-policy gates in the atlas. A checked-in
|
||||||
The working rule on the remaining frontier is explicit now too: when a lane is still ambiguous, we
|
The working rule on the remaining frontier is explicit now too: when a lane is still ambiguous, we
|
||||||
should prefer rehosting the owning source state or the real reader/setter family rather than
|
should prefer rehosting the owning source state or the real reader/setter family rather than
|
||||||
guessing one more derived leaf field from nearby offsets. A checked-in
|
guessing one more derived leaf field from nearby offsets. A checked-in
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,18 @@ pub struct ExpectedRuntimeSummary {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub selected_company_stat_band_root_1c47_count: Option<usize>,
|
pub selected_company_stat_band_root_1c47_count: Option<usize>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub selected_company_last_dividend_year: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub selected_company_years_since_founding: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub selected_company_years_since_last_bankruptcy: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub selected_company_years_since_last_dividend: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub selected_company_chairman_bonus_year: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub selected_company_chairman_bonus_amount: Option<i32>,
|
||||||
|
#[serde(default)]
|
||||||
pub player_count: Option<usize>,
|
pub player_count: Option<usize>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub chairman_profile_count: Option<usize>,
|
pub chairman_profile_count: Option<usize>,
|
||||||
|
|
@ -669,6 +681,54 @@ impl ExpectedRuntimeSummary {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(value) = self.selected_company_last_dividend_year {
|
||||||
|
if actual.selected_company_last_dividend_year != Some(value) {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"selected_company_last_dividend_year mismatch: expected {value}, got {:?}",
|
||||||
|
actual.selected_company_last_dividend_year
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(value) = self.selected_company_years_since_founding {
|
||||||
|
if actual.selected_company_years_since_founding != Some(value) {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"selected_company_years_since_founding mismatch: expected {value}, got {:?}",
|
||||||
|
actual.selected_company_years_since_founding
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(value) = self.selected_company_years_since_last_bankruptcy {
|
||||||
|
if actual.selected_company_years_since_last_bankruptcy != Some(value) {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"selected_company_years_since_last_bankruptcy mismatch: expected {value}, got {:?}",
|
||||||
|
actual.selected_company_years_since_last_bankruptcy
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(value) = self.selected_company_years_since_last_dividend {
|
||||||
|
if actual.selected_company_years_since_last_dividend != Some(value) {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"selected_company_years_since_last_dividend mismatch: expected {value}, got {:?}",
|
||||||
|
actual.selected_company_years_since_last_dividend
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(value) = self.selected_company_chairman_bonus_year {
|
||||||
|
if actual.selected_company_chairman_bonus_year != Some(value) {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"selected_company_chairman_bonus_year mismatch: expected {value}, got {:?}",
|
||||||
|
actual.selected_company_chairman_bonus_year
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(value) = self.selected_company_chairman_bonus_amount {
|
||||||
|
if actual.selected_company_chairman_bonus_amount != Some(value) {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"selected_company_chairman_bonus_amount mismatch: expected {value}, got {:?}",
|
||||||
|
actual.selected_company_chairman_bonus_amount
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(count) = self.player_count {
|
if let Some(count) = self.player_count {
|
||||||
if actual.player_count != count {
|
if actual.player_count != count {
|
||||||
mismatches.push(format!(
|
mismatches.push(format!(
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,12 @@ pub struct RuntimeCompanyAnnualFinanceState {
|
||||||
pub founding_year: u32,
|
pub founding_year: u32,
|
||||||
pub last_bankruptcy_year: u32,
|
pub last_bankruptcy_year: u32,
|
||||||
pub last_dividend_year: u32,
|
pub last_dividend_year: u32,
|
||||||
|
#[serde(default)]
|
||||||
|
pub years_since_founding: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub years_since_last_bankruptcy: Option<u32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub years_since_last_dividend: Option<u32>,
|
||||||
pub current_issue_calendar_word: u32,
|
pub current_issue_calendar_word: u32,
|
||||||
pub prior_issue_calendar_word: u32,
|
pub prior_issue_calendar_word: u32,
|
||||||
pub city_connection_latch: bool,
|
pub city_connection_latch: bool,
|
||||||
|
|
@ -1904,6 +1910,16 @@ pub fn runtime_company_annual_finance_state(
|
||||||
let market_state = state.service_state.company_market_state.get(&company_id)?;
|
let market_state = state.service_state.company_market_state.get(&company_id)?;
|
||||||
let assigned_share_pool = runtime_company_assigned_share_pool(state, company_id)?;
|
let assigned_share_pool = runtime_company_assigned_share_pool(state, company_id)?;
|
||||||
let unassigned_share_pool = runtime_company_unassigned_share_pool(state, company_id)?;
|
let unassigned_share_pool = runtime_company_unassigned_share_pool(state, company_id)?;
|
||||||
|
let years_since_founding =
|
||||||
|
derive_runtime_company_elapsed_years(state.calendar.year, market_state.founding_year);
|
||||||
|
let years_since_last_bankruptcy = derive_runtime_company_elapsed_years(
|
||||||
|
state.calendar.year,
|
||||||
|
market_state.last_bankruptcy_year,
|
||||||
|
);
|
||||||
|
let years_since_last_dividend = derive_runtime_company_elapsed_years(
|
||||||
|
state.calendar.year,
|
||||||
|
market_state.last_dividend_year,
|
||||||
|
);
|
||||||
Some(RuntimeCompanyAnnualFinanceState {
|
Some(RuntimeCompanyAnnualFinanceState {
|
||||||
company_id,
|
company_id,
|
||||||
outstanding_shares: market_state.outstanding_shares,
|
outstanding_shares: market_state.outstanding_shares,
|
||||||
|
|
@ -1917,6 +1933,9 @@ pub fn runtime_company_annual_finance_state(
|
||||||
founding_year: market_state.founding_year,
|
founding_year: market_state.founding_year,
|
||||||
last_bankruptcy_year: market_state.last_bankruptcy_year,
|
last_bankruptcy_year: market_state.last_bankruptcy_year,
|
||||||
last_dividend_year: market_state.last_dividend_year,
|
last_dividend_year: market_state.last_dividend_year,
|
||||||
|
years_since_founding,
|
||||||
|
years_since_last_bankruptcy,
|
||||||
|
years_since_last_dividend,
|
||||||
current_issue_calendar_word: market_state.current_issue_calendar_word,
|
current_issue_calendar_word: market_state.current_issue_calendar_word,
|
||||||
prior_issue_calendar_word: market_state.prior_issue_calendar_word,
|
prior_issue_calendar_word: market_state.prior_issue_calendar_word,
|
||||||
city_connection_latch: market_state.city_connection_latch,
|
city_connection_latch: market_state.city_connection_latch,
|
||||||
|
|
@ -1970,6 +1989,13 @@ fn rounded_cached_share_price_i64(raw_u32: u32) -> Option<i64> {
|
||||||
Some(value.round() as i64)
|
Some(value.round() as i64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn derive_runtime_company_elapsed_years(current_year: u32, prior_year: u32) -> Option<u32> {
|
||||||
|
if prior_year == 0 || prior_year > current_year {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(current_year - prior_year)
|
||||||
|
}
|
||||||
|
|
||||||
fn derive_runtime_chairman_holdings_share_price_total(
|
fn derive_runtime_chairman_holdings_share_price_total(
|
||||||
holdings_by_company: &BTreeMap<u32, u32>,
|
holdings_by_company: &BTreeMap<u32, u32>,
|
||||||
company_share_prices: &BTreeMap<u32, i64>,
|
company_share_prices: &BTreeMap<u32, i64>,
|
||||||
|
|
@ -4231,6 +4257,9 @@ mod tests {
|
||||||
founding_year: 1831,
|
founding_year: 1831,
|
||||||
last_bankruptcy_year: 0,
|
last_bankruptcy_year: 0,
|
||||||
last_dividend_year: 1841,
|
last_dividend_year: 1841,
|
||||||
|
years_since_founding: None,
|
||||||
|
years_since_last_bankruptcy: None,
|
||||||
|
years_since_last_dividend: None,
|
||||||
current_issue_calendar_word: 5,
|
current_issue_calendar_word: 5,
|
||||||
prior_issue_calendar_word: 4,
|
prior_issue_calendar_word: 4,
|
||||||
city_connection_latch: true,
|
city_connection_latch: true,
|
||||||
|
|
@ -4385,4 +4414,85 @@ mod tests {
|
||||||
None
|
None
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derives_elapsed_company_finance_years_from_calendar_and_saved_market_state() {
|
||||||
|
let state = RuntimeState {
|
||||||
|
calendar: CalendarPoint {
|
||||||
|
year: 1844,
|
||||||
|
month_slot: 0,
|
||||||
|
phase_slot: 0,
|
||||||
|
tick_slot: 0,
|
||||||
|
},
|
||||||
|
world_flags: BTreeMap::new(),
|
||||||
|
save_profile: RuntimeSaveProfileState::default(),
|
||||||
|
world_restore: RuntimeWorldRestoreState::default(),
|
||||||
|
metadata: BTreeMap::new(),
|
||||||
|
companies: vec![RuntimeCompany {
|
||||||
|
company_id: 3,
|
||||||
|
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([(
|
||||||
|
3,
|
||||||
|
RuntimeCompanyMarketState {
|
||||||
|
outstanding_shares: 10_000,
|
||||||
|
founding_year: 1838,
|
||||||
|
last_bankruptcy_year: 1841,
|
||||||
|
last_dividend_year: 1843,
|
||||||
|
..RuntimeCompanyMarketState::default()
|
||||||
|
},
|
||||||
|
)]),
|
||||||
|
..RuntimeServiceState::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let finance_state =
|
||||||
|
runtime_company_annual_finance_state(&state, 3).expect("finance state should derive");
|
||||||
|
assert_eq!(finance_state.years_since_founding, Some(6));
|
||||||
|
assert_eq!(finance_state.years_since_last_bankruptcy, Some(3));
|
||||||
|
assert_eq!(finance_state.years_since_last_dividend, Some(1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,9 @@ pub struct RuntimeSummary {
|
||||||
pub selected_company_stat_band_root_0d7f_count: usize,
|
pub selected_company_stat_band_root_0d7f_count: usize,
|
||||||
pub selected_company_stat_band_root_1c47_count: usize,
|
pub selected_company_stat_band_root_1c47_count: usize,
|
||||||
pub selected_company_last_dividend_year: Option<u32>,
|
pub selected_company_last_dividend_year: Option<u32>,
|
||||||
|
pub selected_company_years_since_founding: Option<u32>,
|
||||||
|
pub selected_company_years_since_last_bankruptcy: Option<u32>,
|
||||||
|
pub selected_company_years_since_last_dividend: Option<u32>,
|
||||||
pub selected_company_chairman_bonus_year: Option<u32>,
|
pub selected_company_chairman_bonus_year: Option<u32>,
|
||||||
pub selected_company_chairman_bonus_amount: Option<i32>,
|
pub selected_company_chairman_bonus_amount: Option<i32>,
|
||||||
pub player_count: usize,
|
pub player_count: usize,
|
||||||
|
|
@ -282,6 +285,15 @@ impl RuntimeSummary {
|
||||||
selected_company_last_dividend_year: selected_company_market_state
|
selected_company_last_dividend_year: selected_company_market_state
|
||||||
.map(|market_state| market_state.last_dividend_year)
|
.map(|market_state| market_state.last_dividend_year)
|
||||||
.filter(|year| *year != 0),
|
.filter(|year| *year != 0),
|
||||||
|
selected_company_years_since_founding: selected_company_annual_finance_state
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|finance_state| finance_state.years_since_founding),
|
||||||
|
selected_company_years_since_last_bankruptcy: selected_company_annual_finance_state
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|finance_state| finance_state.years_since_last_bankruptcy),
|
||||||
|
selected_company_years_since_last_dividend: selected_company_annual_finance_state
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|finance_state| finance_state.years_since_last_dividend),
|
||||||
selected_company_chairman_bonus_year: selected_company_market_state
|
selected_company_chairman_bonus_year: selected_company_market_state
|
||||||
.map(|market_state| market_state.chairman_bonus_year)
|
.map(|market_state| market_state.chairman_bonus_year)
|
||||||
.filter(|year| *year != 0),
|
.filter(|year| *year != 0),
|
||||||
|
|
@ -2026,6 +2038,9 @@ mod tests {
|
||||||
assert_eq!(summary.selected_company_stat_band_root_0d7f_count, 1);
|
assert_eq!(summary.selected_company_stat_band_root_0d7f_count, 1);
|
||||||
assert_eq!(summary.selected_company_stat_band_root_1c47_count, 1);
|
assert_eq!(summary.selected_company_stat_band_root_1c47_count, 1);
|
||||||
assert_eq!(summary.selected_company_last_dividend_year, Some(1841));
|
assert_eq!(summary.selected_company_last_dividend_year, Some(1841));
|
||||||
|
assert_eq!(summary.selected_company_years_since_founding, None);
|
||||||
|
assert_eq!(summary.selected_company_years_since_last_bankruptcy, None);
|
||||||
|
assert_eq!(summary.selected_company_years_since_last_dividend, None);
|
||||||
assert_eq!(summary.selected_company_chairman_bonus_year, Some(1842));
|
assert_eq!(summary.selected_company_chairman_bonus_year, Some(1842));
|
||||||
assert_eq!(summary.selected_company_chairman_bonus_amount, Some(750));
|
assert_eq!(summary.selected_company_chairman_bonus_amount, Some(750));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,9 @@ The highest-value next passes are now:
|
||||||
reader seam for assigned shares, public float, and rounded cached share price; the fixed-world
|
reader seam for assigned shares, public float, and rounded cached share price; the fixed-world
|
||||||
finance neighborhood is now widened to 16 dwords rooted at `[world+0x11]` so later issue-family
|
finance neighborhood is now widened to 16 dwords rooted at `[world+0x11]` so later issue-family
|
||||||
closure can target a broader owned restore-state window; the same annual-finance state now also
|
closure can target a broader owned restore-state window; the same annual-finance state now also
|
||||||
feeds a shared company market reader for stock-capital, salary, bonus, and issue-calendar values
|
feeds a shared company market reader for stock-capital, salary, bonus, and issue-calendar values,
|
||||||
|
and now derives elapsed years since founding, last dividend, and last bankruptcy for later annual
|
||||||
|
finance-policy rehosting
|
||||||
- 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
|
||||||
is still ambiguous, prefer rehosting the owning source state or real reader/setter family first
|
is still ambiguous, prefer rehosting the owning source state or real reader/setter family first
|
||||||
instead of guessing another derived leaf field from neighboring raw offsets
|
instead of guessing another derived leaf field from neighboring raw offsets
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,9 @@ rooted at `[world+0x11]`, so later issue-`0x38/0x39` closure can build on a broa
|
||||||
restore-state window instead of another narrow probe. The same owned company annual-finance state
|
restore-state window instead of another narrow probe. The same owned company annual-finance state
|
||||||
now also drives a shared company market reader seam for stock-capital, salary, bonus, and
|
now also drives a shared company market reader seam for stock-capital, salary, bonus, and
|
||||||
issue-calendar values, which is a better base for shellless finance simulation than summary-only
|
issue-calendar values, which is a better base for shellless finance simulation than summary-only
|
||||||
helpers.
|
helpers. That same owned annual-finance state now also derives elapsed years since founding, last
|
||||||
|
dividend, and last bankruptcy from the runtime calendar, which lines up directly with the grounded
|
||||||
|
annual finance-policy gates in the atlas.
|
||||||
|
|
||||||
## Why This Boundary
|
## Why This Boundary
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue