Refresh chairman wealth from company market state
This commit is contained in:
parent
5198f80cd9
commit
26a7a34ad0
3 changed files with 343 additions and 12 deletions
|
|
@ -315,6 +315,8 @@ pub fn project_save_slice_to_runtime_state_import(
|
|||
..RuntimeServiceState::default()
|
||||
},
|
||||
};
|
||||
let mut state = state;
|
||||
state.refresh_derived_market_state();
|
||||
state.validate()?;
|
||||
|
||||
Ok(RuntimeStateImport {
|
||||
|
|
@ -424,6 +426,8 @@ pub fn project_save_slice_overlay_to_runtime_state_import(
|
|||
..base_state.service_state.clone()
|
||||
},
|
||||
};
|
||||
let mut state = state;
|
||||
state.refresh_derived_market_state();
|
||||
state.validate()?;
|
||||
|
||||
Ok(RuntimeStateImport {
|
||||
|
|
|
|||
|
|
@ -1716,6 +1716,61 @@ impl RuntimeState {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn refresh_derived_market_state(&mut self) {
|
||||
let company_share_prices = self
|
||||
.service_state
|
||||
.company_market_state
|
||||
.iter()
|
||||
.filter_map(|(company_id, market_state)| {
|
||||
rounded_cached_share_price_i64(market_state.cached_share_price_raw_u32)
|
||||
.map(|share_price| (*company_id, share_price))
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
|
||||
for profile in &mut self.chairman_profiles {
|
||||
let preserved_threshold_adjusted_holdings_component = profile
|
||||
.purchasing_power_total
|
||||
.saturating_sub(profile.current_cash)
|
||||
.max(0);
|
||||
if let Some(holdings_value_total) = derive_runtime_chairman_holdings_share_price_total(
|
||||
&profile.company_holdings,
|
||||
&company_share_prices,
|
||||
) {
|
||||
profile.holdings_value_total = holdings_value_total;
|
||||
}
|
||||
profile.net_worth_total = profile
|
||||
.current_cash
|
||||
.saturating_add(profile.holdings_value_total);
|
||||
profile.purchasing_power_total = profile
|
||||
.current_cash
|
||||
.saturating_add(preserved_threshold_adjusted_holdings_component)
|
||||
.max(profile.net_worth_total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rounded_cached_share_price_i64(raw_u32: u32) -> Option<i64> {
|
||||
let value = f32::from_bits(raw_u32);
|
||||
if !value.is_finite() {
|
||||
return None;
|
||||
}
|
||||
if value < i64::MIN as f32 || value > i64::MAX as f32 {
|
||||
return None;
|
||||
}
|
||||
Some(value.round() as i64)
|
||||
}
|
||||
|
||||
fn derive_runtime_chairman_holdings_share_price_total(
|
||||
holdings_by_company: &BTreeMap<u32, u32>,
|
||||
company_share_prices: &BTreeMap<u32, i64>,
|
||||
) -> Option<i64> {
|
||||
let mut total = 0i64;
|
||||
for (company_id, units) in holdings_by_company {
|
||||
let share_price = *company_share_prices.get(company_id)?;
|
||||
total = total.checked_add((*units as i64).checked_mul(share_price)?)?;
|
||||
}
|
||||
Some(total)
|
||||
}
|
||||
|
||||
fn validate_runtime_effect(
|
||||
|
|
@ -3372,4 +3427,209 @@ mod tests {
|
|||
|
||||
assert!(state.validate().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refreshes_chairman_totals_from_company_market_state() {
|
||||
let mut state = RuntimeState {
|
||||
calendar: CalendarPoint {
|
||||
year: 1830,
|
||||
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: 1,
|
||||
current_cash: 0,
|
||||
debt: 0,
|
||||
credit_rating_score: None,
|
||||
prime_rate: None,
|
||||
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||
active: true,
|
||||
available_track_laying_capacity: None,
|
||||
linked_chairman_profile_id: None,
|
||||
book_value_per_share: 0,
|
||||
investor_confidence: 0,
|
||||
management_attitude: 0,
|
||||
takeover_cooldown_year: None,
|
||||
merger_cooldown_year: None,
|
||||
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||
},
|
||||
RuntimeCompany {
|
||||
company_id: 2,
|
||||
current_cash: 0,
|
||||
debt: 0,
|
||||
credit_rating_score: None,
|
||||
prime_rate: None,
|
||||
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||
active: true,
|
||||
available_track_laying_capacity: None,
|
||||
linked_chairman_profile_id: None,
|
||||
book_value_per_share: 0,
|
||||
investor_confidence: 0,
|
||||
management_attitude: 0,
|
||||
takeover_cooldown_year: None,
|
||||
merger_cooldown_year: None,
|
||||
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||
},
|
||||
],
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
chairman_profiles: vec![RuntimeChairmanProfile {
|
||||
profile_id: 1,
|
||||
name: "Chairman One".to_string(),
|
||||
active: true,
|
||||
current_cash: 100,
|
||||
linked_company_id: Some(1),
|
||||
company_holdings: BTreeMap::from([(1, 2), (2, 3)]),
|
||||
holdings_value_total: 0,
|
||||
net_worth_total: 0,
|
||||
purchasing_power_total: 400,
|
||||
}],
|
||||
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([
|
||||
(
|
||||
1,
|
||||
RuntimeCompanyMarketState {
|
||||
cached_share_price_raw_u32: 0x41200000,
|
||||
..RuntimeCompanyMarketState::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
2,
|
||||
RuntimeCompanyMarketState {
|
||||
cached_share_price_raw_u32: 0x41a00000,
|
||||
..RuntimeCompanyMarketState::default()
|
||||
},
|
||||
),
|
||||
]),
|
||||
..RuntimeServiceState::default()
|
||||
},
|
||||
};
|
||||
|
||||
state.refresh_derived_market_state();
|
||||
|
||||
assert_eq!(state.chairman_profiles[0].holdings_value_total, 80);
|
||||
assert_eq!(state.chairman_profiles[0].net_worth_total, 180);
|
||||
assert_eq!(state.chairman_profiles[0].purchasing_power_total, 400);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refreshes_chairman_purchasing_power_when_cash_changes() {
|
||||
let mut state = RuntimeState {
|
||||
calendar: CalendarPoint {
|
||||
year: 1830,
|
||||
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: 1,
|
||||
current_cash: 0,
|
||||
debt: 0,
|
||||
credit_rating_score: None,
|
||||
prime_rate: None,
|
||||
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||
active: true,
|
||||
available_track_laying_capacity: None,
|
||||
linked_chairman_profile_id: None,
|
||||
book_value_per_share: 0,
|
||||
investor_confidence: 0,
|
||||
management_attitude: 0,
|
||||
takeover_cooldown_year: None,
|
||||
merger_cooldown_year: None,
|
||||
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||
}],
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
chairman_profiles: vec![RuntimeChairmanProfile {
|
||||
profile_id: 1,
|
||||
name: "Chairman One".to_string(),
|
||||
active: true,
|
||||
current_cash: 50,
|
||||
linked_company_id: Some(1),
|
||||
company_holdings: BTreeMap::from([(1, 2)]),
|
||||
holdings_value_total: 20,
|
||||
net_worth_total: 70,
|
||||
purchasing_power_total: 130,
|
||||
}],
|
||||
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([(
|
||||
1,
|
||||
RuntimeCompanyMarketState {
|
||||
cached_share_price_raw_u32: 0x41200000,
|
||||
..RuntimeCompanyMarketState::default()
|
||||
},
|
||||
)]),
|
||||
..RuntimeServiceState::default()
|
||||
},
|
||||
};
|
||||
state.chairman_profiles[0].current_cash = 80;
|
||||
|
||||
state.refresh_derived_market_state();
|
||||
|
||||
assert_eq!(state.chairman_profiles[0].holdings_value_total, 20);
|
||||
assert_eq!(state.chairman_profiles[0].net_worth_total, 100);
|
||||
assert_eq!(state.chairman_profiles[0].purchasing_power_total, 130);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ pub fn execute_step_command(
|
|||
0
|
||||
}
|
||||
};
|
||||
state.refresh_derived_market_state();
|
||||
let final_summary = RuntimeSummary::from_state(state);
|
||||
|
||||
Ok(StepResult {
|
||||
|
|
@ -363,7 +364,14 @@ fn apply_runtime_effects(
|
|||
"missing chairman profile_id {profile_id} while applying cash effect"
|
||||
)
|
||||
})?;
|
||||
let preserved_threshold_adjusted_holdings_component = chairman
|
||||
.purchasing_power_total
|
||||
.saturating_sub(chairman.current_cash)
|
||||
.max(0);
|
||||
chairman.current_cash = *value;
|
||||
chairman.purchasing_power_total = chairman
|
||||
.current_cash
|
||||
.saturating_add(preserved_threshold_adjusted_holdings_component);
|
||||
}
|
||||
}
|
||||
RuntimeEffect::SetCompanyGovernanceScalar {
|
||||
|
|
@ -3790,28 +3798,64 @@ mod tests {
|
|||
#[test]
|
||||
fn set_chairman_cash_supports_all_active_target() {
|
||||
let mut state = RuntimeState {
|
||||
companies: vec![
|
||||
RuntimeCompany {
|
||||
company_id: 1,
|
||||
current_cash: 0,
|
||||
debt: 0,
|
||||
credit_rating_score: None,
|
||||
prime_rate: None,
|
||||
active: true,
|
||||
available_track_laying_capacity: None,
|
||||
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||
linked_chairman_profile_id: Some(1),
|
||||
book_value_per_share: 0,
|
||||
investor_confidence: 0,
|
||||
management_attitude: 0,
|
||||
takeover_cooldown_year: None,
|
||||
merger_cooldown_year: None,
|
||||
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||
},
|
||||
RuntimeCompany {
|
||||
company_id: 2,
|
||||
current_cash: 0,
|
||||
debt: 0,
|
||||
credit_rating_score: None,
|
||||
prime_rate: None,
|
||||
active: true,
|
||||
available_track_laying_capacity: None,
|
||||
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||
linked_chairman_profile_id: Some(2),
|
||||
book_value_per_share: 0,
|
||||
investor_confidence: 0,
|
||||
management_attitude: 0,
|
||||
takeover_cooldown_year: None,
|
||||
merger_cooldown_year: None,
|
||||
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||
},
|
||||
],
|
||||
chairman_profiles: vec![
|
||||
RuntimeChairmanProfile {
|
||||
profile_id: 1,
|
||||
name: "Chairman One".to_string(),
|
||||
active: true,
|
||||
current_cash: 10,
|
||||
linked_company_id: None,
|
||||
company_holdings: BTreeMap::new(),
|
||||
holdings_value_total: 0,
|
||||
net_worth_total: 0,
|
||||
purchasing_power_total: 0,
|
||||
linked_company_id: Some(1),
|
||||
company_holdings: BTreeMap::from([(1, 2)]),
|
||||
holdings_value_total: 20,
|
||||
net_worth_total: 30,
|
||||
purchasing_power_total: 70,
|
||||
},
|
||||
RuntimeChairmanProfile {
|
||||
profile_id: 2,
|
||||
name: "Chairman Two".to_string(),
|
||||
active: true,
|
||||
current_cash: 20,
|
||||
linked_company_id: None,
|
||||
company_holdings: BTreeMap::new(),
|
||||
holdings_value_total: 0,
|
||||
net_worth_total: 0,
|
||||
purchasing_power_total: 0,
|
||||
linked_company_id: Some(2),
|
||||
company_holdings: BTreeMap::from([(2, 3)]),
|
||||
holdings_value_total: 60,
|
||||
net_worth_total: 80,
|
||||
purchasing_power_total: 110,
|
||||
},
|
||||
RuntimeChairmanProfile {
|
||||
profile_id: 3,
|
||||
|
|
@ -3821,8 +3865,8 @@ mod tests {
|
|||
linked_company_id: None,
|
||||
company_holdings: BTreeMap::new(),
|
||||
holdings_value_total: 0,
|
||||
net_worth_total: 0,
|
||||
purchasing_power_total: 0,
|
||||
net_worth_total: 30,
|
||||
purchasing_power_total: 30,
|
||||
},
|
||||
],
|
||||
event_runtime_records: vec![RuntimeEventRecord {
|
||||
|
|
@ -3839,6 +3883,25 @@ mod tests {
|
|||
value: 77,
|
||||
}],
|
||||
}],
|
||||
service_state: RuntimeServiceState {
|
||||
company_market_state: BTreeMap::from([
|
||||
(
|
||||
1,
|
||||
crate::RuntimeCompanyMarketState {
|
||||
cached_share_price_raw_u32: 0x41200000,
|
||||
..crate::RuntimeCompanyMarketState::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
2,
|
||||
crate::RuntimeCompanyMarketState {
|
||||
cached_share_price_raw_u32: 0x41a00000,
|
||||
..crate::RuntimeCompanyMarketState::default()
|
||||
},
|
||||
),
|
||||
]),
|
||||
..RuntimeServiceState::default()
|
||||
},
|
||||
..state()
|
||||
};
|
||||
|
||||
|
|
@ -3851,6 +3914,10 @@ mod tests {
|
|||
assert_eq!(state.chairman_profiles[0].current_cash, 77);
|
||||
assert_eq!(state.chairman_profiles[1].current_cash, 77);
|
||||
assert_eq!(state.chairman_profiles[2].current_cash, 30);
|
||||
assert_eq!(state.chairman_profiles[0].net_worth_total, 97);
|
||||
assert_eq!(state.chairman_profiles[0].purchasing_power_total, 137);
|
||||
assert_eq!(state.chairman_profiles[1].net_worth_total, 137);
|
||||
assert_eq!(state.chairman_profiles[1].purchasing_power_total, 167);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue