Rehost company prime rate reader
This commit is contained in:
parent
29df4e0080
commit
5372a11118
6 changed files with 383 additions and 70 deletions
|
|
@ -6186,15 +6186,9 @@ mod tests {
|
|||
.current_calendar_tuple_word_2_raw_u32,
|
||||
Some(2)
|
||||
);
|
||||
assert_eq!(import.state.world_restore.absolute_counter_raw_u32, Some(3));
|
||||
assert_eq!(
|
||||
import.state.world_restore.absolute_counter_raw_u32,
|
||||
Some(3)
|
||||
);
|
||||
assert_eq!(
|
||||
import
|
||||
.state
|
||||
.world_restore
|
||||
.absolute_counter_mirror_raw_u32,
|
||||
import.state.world_restore.absolute_counter_mirror_raw_u32,
|
||||
Some(4)
|
||||
);
|
||||
assert_eq!(
|
||||
|
|
|
|||
|
|
@ -65,10 +65,11 @@ pub use runtime::{
|
|||
RuntimeTerritory, RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric,
|
||||
RuntimeTrackPieceCounts, RuntimeTrain, RuntimeWorldFinanceNeighborhoodCandidate,
|
||||
RuntimeWorldIssueState, RuntimeWorldRestoreState, runtime_company_annual_finance_state,
|
||||
runtime_company_assigned_share_pool, runtime_company_market_value, runtime_company_stat_value,
|
||||
runtime_company_stat_value_f64, runtime_company_unassigned_share_pool,
|
||||
runtime_world_issue_opinion_multiplier, runtime_world_issue_opinion_term_sum_raw,
|
||||
runtime_world_issue_state,
|
||||
runtime_company_assigned_share_pool, runtime_company_market_value, runtime_company_prime_rate,
|
||||
runtime_company_stat_value, runtime_company_stat_value_f64,
|
||||
runtime_company_unassigned_share_pool, runtime_world_issue_opinion_multiplier,
|
||||
runtime_world_issue_opinion_term_sum_raw, runtime_world_issue_state,
|
||||
runtime_world_prime_rate_baseline,
|
||||
};
|
||||
pub use smp::{
|
||||
SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION, SmpAlignedRuntimeRuleBandLane,
|
||||
|
|
|
|||
|
|
@ -1857,7 +1857,11 @@ impl RuntimeState {
|
|||
));
|
||||
}
|
||||
}
|
||||
for chairman_profile_id in self.service_state.chairman_issue_opinion_terms_raw_i32.keys() {
|
||||
for chairman_profile_id in self
|
||||
.service_state
|
||||
.chairman_issue_opinion_terms_raw_i32
|
||||
.keys()
|
||||
{
|
||||
if !seen_chairman_profile_ids.contains(chairman_profile_id) {
|
||||
return Err(format!(
|
||||
"service_state.chairman_issue_opinion_terms_raw_i32 references unknown chairman_profile_id {}",
|
||||
|
|
@ -1972,7 +1976,9 @@ pub fn runtime_company_stat_value_f64(
|
|||
RUNTIME_COMPANY_STAT_FAMILY_SPECIAL_232A => {
|
||||
runtime_company_special_stat_family_232a_value_f64(state, company_id, selector.slot_id)
|
||||
}
|
||||
family_id => runtime_company_year_stat_value_f64(state, company_id, family_id, selector.slot_id),
|
||||
family_id => {
|
||||
runtime_company_year_stat_value_f64(state, company_id, family_id, selector.slot_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2235,6 +2241,38 @@ pub fn runtime_world_issue_state(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn runtime_world_prime_rate_baseline(state: &RuntimeState) -> Option<f64> {
|
||||
let raw = state.world_restore.issue_37_value?;
|
||||
let value = f32::from_bits(raw) as f64;
|
||||
if !value.is_finite() {
|
||||
return None;
|
||||
}
|
||||
let scaled = (value + 0.001) * 100.0;
|
||||
if !scaled.is_finite() {
|
||||
return None;
|
||||
}
|
||||
Some(scaled.round() / 100.0)
|
||||
}
|
||||
|
||||
pub fn runtime_company_prime_rate(state: &RuntimeState, company_id: u32) -> Option<i64> {
|
||||
let company = state
|
||||
.companies
|
||||
.iter()
|
||||
.find(|company| company.company_id == company_id)?;
|
||||
if let Some(prime_rate) = company.prime_rate {
|
||||
return Some(prime_rate);
|
||||
}
|
||||
let baseline = runtime_world_prime_rate_baseline(state)?;
|
||||
let raw_issue_sum = runtime_world_issue_opinion_term_sum_raw(
|
||||
state,
|
||||
RUNTIME_WORLD_ISSUE_PRIME_RATE,
|
||||
company.linked_chairman_profile_id,
|
||||
Some(company_id),
|
||||
None,
|
||||
)?;
|
||||
runtime_round_f64_to_i64(baseline + (raw_issue_sum as f64) * 0.01)
|
||||
}
|
||||
|
||||
pub fn runtime_world_absolute_counter(state: &RuntimeState) -> Option<u32> {
|
||||
state.world_restore.absolute_counter_raw_u32
|
||||
}
|
||||
|
|
@ -2334,13 +2372,15 @@ pub fn runtime_company_annual_finance_state(
|
|||
market_state.prior_issue_calendar_word_2,
|
||||
),
|
||||
);
|
||||
let current_issue_age_absolute_counter_delta =
|
||||
match (runtime_world_absolute_counter(state), current_issue_absolute_counter) {
|
||||
(Some(world_counter), Some(issue_counter)) if world_counter >= issue_counter => {
|
||||
Some(i64::from(world_counter - issue_counter))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let current_issue_age_absolute_counter_delta = match (
|
||||
runtime_world_absolute_counter(state),
|
||||
current_issue_absolute_counter,
|
||||
) {
|
||||
(Some(world_counter), Some(issue_counter)) if world_counter >= issue_counter => {
|
||||
Some(i64::from(world_counter - issue_counter))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let (trailing_full_year_year_words, trailing_full_year_net_profits) =
|
||||
runtime_company_trailing_full_year_stat_series(state, company_id, 0x2b, 4)
|
||||
.unwrap_or_default();
|
||||
|
|
@ -4471,8 +4511,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn reads_year_relative_company_stat_family_from_saved_market_matrix() {
|
||||
let mut year_stat_family_qword_bits =
|
||||
vec![0u64; (RUNTIME_COMPANY_STAT_SLOT_COUNT * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN) as usize];
|
||||
let mut year_stat_family_qword_bits = vec![
|
||||
0u64;
|
||||
(RUNTIME_COMPANY_STAT_SLOT_COUNT * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)
|
||||
as usize
|
||||
];
|
||||
let write_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();
|
||||
|
|
@ -4585,7 +4628,10 @@ mod tests {
|
|||
family_id: 1844,
|
||||
slot_id: 0x09,
|
||||
};
|
||||
assert_eq!(runtime_company_stat_value_f64(&state, 7, prior_year), Some(9.0));
|
||||
assert_eq!(
|
||||
runtime_company_stat_value_f64(&state, 7, prior_year),
|
||||
Some(9.0)
|
||||
);
|
||||
assert_eq!(
|
||||
runtime_company_stat_value_f64(
|
||||
&state,
|
||||
|
|
@ -4645,22 +4691,42 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn carries_trailing_full_year_finance_lanes_into_annual_finance_state() {
|
||||
let mut year_stat_family_qword_bits =
|
||||
vec![0u64; (RUNTIME_COMPANY_STAT_SLOT_COUNT * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN) as usize];
|
||||
let mut year_stat_family_qword_bits = vec![
|
||||
0u64;
|
||||
(RUNTIME_COMPANY_STAT_SLOT_COUNT * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)
|
||||
as usize
|
||||
];
|
||||
let write_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();
|
||||
};
|
||||
for (year_delta, revenue_parts, extra_profit_parts, fuel_cost) in [
|
||||
(1, [60.0, 50.0, 40.0, 30.0], [10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0], 18.0),
|
||||
(2, [50.0, 45.0, 40.0, 35.0], [9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0], 17.0),
|
||||
(3, [50.0, 40.0, 35.0, 35.0], [8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0], 16.0),
|
||||
(4, [45.0, 40.0, 35.0, 30.0], [7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0], 15.0),
|
||||
(
|
||||
1,
|
||||
[60.0, 50.0, 40.0, 30.0],
|
||||
[10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0],
|
||||
18.0,
|
||||
),
|
||||
(
|
||||
2,
|
||||
[50.0, 45.0, 40.0, 35.0],
|
||||
[9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0],
|
||||
17.0,
|
||||
),
|
||||
(
|
||||
3,
|
||||
[50.0, 40.0, 35.0, 35.0],
|
||||
[8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0],
|
||||
16.0,
|
||||
),
|
||||
(
|
||||
4,
|
||||
[45.0, 40.0, 35.0, 30.0],
|
||||
[7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0],
|
||||
15.0,
|
||||
),
|
||||
] {
|
||||
for (slot_id, value) in [0x01, 0x02, 0x03, 0x04]
|
||||
.into_iter()
|
||||
.zip(revenue_parts)
|
||||
{
|
||||
for (slot_id, value) in [0x01, 0x02, 0x03, 0x04].into_iter().zip(revenue_parts) {
|
||||
write_year_value(&mut year_stat_family_qword_bits, slot_id, year_delta, value);
|
||||
}
|
||||
for (slot_id, value) in [0x05, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0c]
|
||||
|
|
@ -4669,7 +4735,12 @@ mod tests {
|
|||
{
|
||||
write_year_value(&mut year_stat_family_qword_bits, slot_id, year_delta, value);
|
||||
}
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x09, year_delta, fuel_cost);
|
||||
write_year_value(
|
||||
&mut year_stat_family_qword_bits,
|
||||
0x09,
|
||||
year_delta,
|
||||
fuel_cost,
|
||||
);
|
||||
}
|
||||
|
||||
let state = RuntimeState {
|
||||
|
|
@ -4755,8 +4826,14 @@ mod tests {
|
|||
finance_state.trailing_full_year_net_profits,
|
||||
vec![247, 229, 211, 193]
|
||||
);
|
||||
assert_eq!(finance_state.trailing_full_year_revenues, vec![180, 170, 160, 150]);
|
||||
assert_eq!(finance_state.trailing_full_year_fuel_costs, vec![18, 17, 16, 15]);
|
||||
assert_eq!(
|
||||
finance_state.trailing_full_year_revenues,
|
||||
vec![180, 170, 160, 150]
|
||||
);
|
||||
assert_eq!(
|
||||
finance_state.trailing_full_year_fuel_costs,
|
||||
vec![18, 17, 16, 15]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -4911,11 +4988,15 @@ mod tests {
|
|||
world_scalar_overrides: BTreeMap::new(),
|
||||
special_conditions: BTreeMap::new(),
|
||||
service_state: RuntimeServiceState {
|
||||
world_issue_opinion_base_terms_raw_i32: (0..0x3b).map(|value| value as i32).collect(),
|
||||
world_issue_opinion_base_terms_raw_i32: (0..0x3b)
|
||||
.map(|value| value as i32)
|
||||
.collect(),
|
||||
company_market_state: BTreeMap::from([(
|
||||
7,
|
||||
RuntimeCompanyMarketState {
|
||||
issue_opinion_terms_raw_i32: (0..0x3b).map(|value| (value as i32) * 2).collect(),
|
||||
issue_opinion_terms_raw_i32: (0..0x3b)
|
||||
.map(|value| (value as i32) * 2)
|
||||
.collect(),
|
||||
..RuntimeCompanyMarketState::default()
|
||||
},
|
||||
)]),
|
||||
|
|
@ -5023,14 +5104,11 @@ mod tests {
|
|||
..RuntimeCompanyMarketState::default()
|
||||
},
|
||||
)]),
|
||||
chairman_issue_opinion_terms_raw_i32: BTreeMap::from([(
|
||||
9,
|
||||
{
|
||||
let mut values = vec![0; 0x3b];
|
||||
values[0x38] = 50;
|
||||
values
|
||||
},
|
||||
)]),
|
||||
chairman_issue_opinion_terms_raw_i32: BTreeMap::from([(9, {
|
||||
let mut values = vec![0; 0x3b];
|
||||
values[0x38] = 50;
|
||||
values
|
||||
})]),
|
||||
..RuntimeServiceState::default()
|
||||
},
|
||||
};
|
||||
|
|
@ -5095,13 +5173,163 @@ mod tests {
|
|||
};
|
||||
|
||||
assert_eq!(runtime_world_absolute_counter(&state), Some(5));
|
||||
assert_eq!(runtime_world_partial_year_weight_numerator(&state), Some(35));
|
||||
assert_eq!(
|
||||
runtime_world_partial_year_weight_numerator(&state),
|
||||
Some(35)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derives_prime_rate_baseline_from_saved_world_raw_word() {
|
||||
let 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 {
|
||||
issue_37_value: Some(5.0f32.to_bits()),
|
||||
..RuntimeWorldRestoreState::default()
|
||||
},
|
||||
metadata: BTreeMap::new(),
|
||||
companies: Vec::new(),
|
||||
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::default(),
|
||||
};
|
||||
|
||||
assert_eq!(runtime_world_prime_rate_baseline(&state), Some(5.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derives_company_prime_rate_from_issue39_owner_state() {
|
||||
let mut company_terms = vec![0; 0x3b];
|
||||
company_terms[RUNTIME_WORLD_ISSUE_PRIME_RATE as usize] = 50;
|
||||
let mut chairman_terms = vec![0; 0x3b];
|
||||
chairman_terms[RUNTIME_WORLD_ISSUE_PRIME_RATE as usize] = 25;
|
||||
let mut world_terms = vec![0; 0x3b];
|
||||
world_terms[RUNTIME_WORLD_ISSUE_PRIME_RATE as usize] = 100;
|
||||
|
||||
let 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 {
|
||||
issue_37_value: Some(5.0f32.to_bits()),
|
||||
..RuntimeWorldRestoreState::default()
|
||||
},
|
||||
metadata: BTreeMap::new(),
|
||||
companies: vec![RuntimeCompany {
|
||||
company_id: 7,
|
||||
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: Some(3),
|
||||
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".to_string(),
|
||||
active: true,
|
||||
current_cash: 0,
|
||||
linked_company_id: Some(7),
|
||||
company_holdings: BTreeMap::new(),
|
||||
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 {
|
||||
world_issue_opinion_base_terms_raw_i32: world_terms,
|
||||
company_market_state: BTreeMap::from([(
|
||||
7,
|
||||
RuntimeCompanyMarketState {
|
||||
issue_opinion_terms_raw_i32: company_terms,
|
||||
..RuntimeCompanyMarketState::default()
|
||||
},
|
||||
)]),
|
||||
chairman_issue_opinion_terms_raw_i32: BTreeMap::from([(3, chairman_terms)]),
|
||||
..RuntimeServiceState::default()
|
||||
},
|
||||
};
|
||||
|
||||
assert_eq!(runtime_company_prime_rate(&state, 7), Some(7));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decodes_and_packs_company_issue_calendar_tuple() {
|
||||
let tuple =
|
||||
runtime_decode_packed_calendar_tuple(0x0101_0726, 0x0001_0001);
|
||||
let tuple = runtime_decode_packed_calendar_tuple(0x0101_0726, 0x0001_0001);
|
||||
assert_eq!(
|
||||
tuple,
|
||||
RuntimePackedCalendarTuple {
|
||||
|
|
|
|||
|
|
@ -15820,27 +15820,45 @@ mod tests {
|
|||
probe.dword_candidates.len(),
|
||||
RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_WINDOW_LEN_DWORDS
|
||||
);
|
||||
assert_eq!(probe.current_calendar_tuple_word_lane.relative_offset_hex, "0xd");
|
||||
assert_eq!(
|
||||
probe.current_calendar_tuple_word_lane.relative_offset_hex,
|
||||
"0xd"
|
||||
);
|
||||
assert_eq!(probe.packed_year_word_raw_u16, 1);
|
||||
assert_eq!(probe.packed_year_word_raw_hex, "0x0001");
|
||||
assert_eq!(probe.partial_year_progress_raw_u8, 0);
|
||||
assert_eq!(probe.partial_year_progress_raw_hex, "0x00");
|
||||
assert_eq!(probe.current_calendar_tuple_word_lane.value_i32, 1);
|
||||
assert_eq!(probe.current_calendar_tuple_word_2_lane.relative_offset_hex, "0x11");
|
||||
assert_eq!(
|
||||
probe.current_calendar_tuple_word_2_lane.relative_offset_hex,
|
||||
"0x11"
|
||||
);
|
||||
assert_eq!(probe.current_calendar_tuple_word_2_lane.value_i32, 2);
|
||||
assert_eq!(probe.absolute_counter_lane.relative_offset_hex, "0x15");
|
||||
assert_eq!(probe.absolute_counter_lane.value_i32, 3);
|
||||
assert_eq!(probe.absolute_counter_mirror_lane.relative_offset_hex, "0x19");
|
||||
assert_eq!(
|
||||
probe.absolute_counter_mirror_lane.relative_offset_hex,
|
||||
"0x19"
|
||||
);
|
||||
assert_eq!(probe.absolute_counter_mirror_lane.value_i32, 4);
|
||||
assert_eq!(probe.dword_candidates[0].label, "current_calendar_tuple_word");
|
||||
assert_eq!(
|
||||
probe.dword_candidates[0].label,
|
||||
"current_calendar_tuple_word"
|
||||
);
|
||||
assert_eq!(probe.dword_candidates[0].relative_offset_hex, "0xd");
|
||||
assert_eq!(probe.dword_candidates[0].value_i32, 1);
|
||||
assert_eq!(probe.dword_candidates[6].label, "issue_0x37_multiplier");
|
||||
assert_eq!(probe.dword_candidates[6].relative_offset_hex, "0x25");
|
||||
assert_eq!(probe.dword_candidates[10].label, "issue_neighbor_candidate_2");
|
||||
assert_eq!(
|
||||
probe.dword_candidates[10].label,
|
||||
"issue_neighbor_candidate_2"
|
||||
);
|
||||
assert_eq!(probe.dword_candidates[10].relative_offset_hex, "0x35");
|
||||
assert_eq!(probe.dword_candidates[10].value_i32, 11);
|
||||
assert_eq!(probe.dword_candidates[11].label, "finance_neighborhood_word_12");
|
||||
assert_eq!(
|
||||
probe.dword_candidates[11].label,
|
||||
"finance_neighborhood_word_12"
|
||||
);
|
||||
assert_eq!(probe.dword_candidates[11].relative_offset_hex, "0x39");
|
||||
assert_eq!(probe.dword_candidates[11].value_i32, 12);
|
||||
assert_eq!(
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCondition, RuntimeConditionComparator,
|
||||
RuntimeEffect, RuntimeEventRecordTemplate, RuntimePlayerTarget, RuntimeState, RuntimeSummary,
|
||||
RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts,
|
||||
calendar::BoundaryEventKind,
|
||||
calendar::BoundaryEventKind, runtime_company_prime_rate,
|
||||
};
|
||||
|
||||
const PERIODIC_TRIGGER_KIND_ORDER: [u8; 6] = [1, 0, 3, 2, 5, 4];
|
||||
|
|
@ -829,7 +829,7 @@ fn evaluate_record_conditions(
|
|||
.find(|company| company.company_id == *company_id)
|
||||
.is_some_and(|company| {
|
||||
compare_condition_value(
|
||||
company_metric_value(company, *metric),
|
||||
company_metric_value(state, company, *metric),
|
||||
*comparator,
|
||||
*value,
|
||||
)
|
||||
|
|
@ -1508,12 +1508,18 @@ fn resolve_territory_target_ids(
|
|||
}
|
||||
}
|
||||
|
||||
fn company_metric_value(company: &crate::RuntimeCompany, metric: RuntimeCompanyMetric) -> i64 {
|
||||
fn company_metric_value(
|
||||
state: &RuntimeState,
|
||||
company: &crate::RuntimeCompany,
|
||||
metric: RuntimeCompanyMetric,
|
||||
) -> i64 {
|
||||
match metric {
|
||||
RuntimeCompanyMetric::CurrentCash => company.current_cash,
|
||||
RuntimeCompanyMetric::TotalDebt => company.debt as i64,
|
||||
RuntimeCompanyMetric::CreditRating => company.credit_rating_score.unwrap_or(0),
|
||||
RuntimeCompanyMetric::PrimeRate => company.prime_rate.unwrap_or(0),
|
||||
RuntimeCompanyMetric::PrimeRate => {
|
||||
runtime_company_prime_rate(state, company.company_id).unwrap_or(0)
|
||||
}
|
||||
RuntimeCompanyMetric::BookValuePerShare => company.book_value_per_share,
|
||||
RuntimeCompanyMetric::InvestorConfidence => company.investor_confidence,
|
||||
RuntimeCompanyMetric::ManagementAttitude => company.management_attitude,
|
||||
|
|
@ -4069,6 +4075,73 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derived_prime_rate_condition_reads_rehosted_issue_owner_state() {
|
||||
let mut issue_terms = vec![0; 0x3b];
|
||||
issue_terms[crate::RUNTIME_WORLD_ISSUE_PRIME_RATE as usize] = 100;
|
||||
let mut state = RuntimeState {
|
||||
companies: vec![RuntimeCompany {
|
||||
company_id: 1,
|
||||
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||
current_cash: 100,
|
||||
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: 2620,
|
||||
investor_confidence: 37,
|
||||
management_attitude: 58,
|
||||
takeover_cooldown_year: Some(1844),
|
||||
merger_cooldown_year: Some(1845),
|
||||
}],
|
||||
selected_company_id: Some(1),
|
||||
world_restore: RuntimeWorldRestoreState {
|
||||
issue_37_value: Some(5.0f32.to_bits()),
|
||||
..RuntimeWorldRestoreState::default()
|
||||
},
|
||||
service_state: RuntimeServiceState {
|
||||
world_issue_opinion_base_terms_raw_i32: issue_terms,
|
||||
..RuntimeServiceState::default()
|
||||
},
|
||||
event_runtime_records: vec![RuntimeEventRecord {
|
||||
record_id: 195,
|
||||
trigger_kind: 6,
|
||||
active: true,
|
||||
service_count: 0,
|
||||
marks_collection_dirty: false,
|
||||
one_shot: false,
|
||||
has_fired: false,
|
||||
conditions: vec![RuntimeCondition::CompanyNumericThreshold {
|
||||
target: RuntimeCompanyTarget::SelectedCompany,
|
||||
metric: crate::RuntimeCompanyMetric::PrimeRate,
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 6,
|
||||
}],
|
||||
effects: vec![RuntimeEffect::SetWorldFlag {
|
||||
key: "world.derived_prime_rate_gate_passed".to_string(),
|
||||
value: true,
|
||||
}],
|
||||
}],
|
||||
..state()
|
||||
};
|
||||
|
||||
execute_step_command(
|
||||
&mut state,
|
||||
&StepCommand::ServiceTriggerKind { trigger_kind: 6 },
|
||||
)
|
||||
.expect("derived prime-rate company condition should gate execution");
|
||||
|
||||
assert_eq!(
|
||||
state
|
||||
.world_flags
|
||||
.get("world.derived_prime_rate_gate_passed"),
|
||||
Some(&true)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chairman_metric_conditions_support_all_active_target() {
|
||||
let mut state = RuntimeState {
|
||||
|
|
|
|||
|
|
@ -191,9 +191,7 @@ impl RuntimeSummary {
|
|||
world_restore_absolute_counter_reconstructible_from_save: state
|
||||
.world_restore
|
||||
.absolute_counter_reconstructible_from_save,
|
||||
world_restore_packed_year_word_raw_u16: state
|
||||
.world_restore
|
||||
.packed_year_word_raw_u16,
|
||||
world_restore_packed_year_word_raw_u16: state.world_restore.packed_year_word_raw_u16,
|
||||
world_restore_partial_year_progress_raw_u8: state
|
||||
.world_restore
|
||||
.partial_year_progress_raw_u8,
|
||||
|
|
@ -203,9 +201,7 @@ impl RuntimeSummary {
|
|||
world_restore_current_calendar_tuple_word_2_raw_u32: state
|
||||
.world_restore
|
||||
.current_calendar_tuple_word_2_raw_u32,
|
||||
world_restore_absolute_counter_raw_u32: state
|
||||
.world_restore
|
||||
.absolute_counter_raw_u32,
|
||||
world_restore_absolute_counter_raw_u32: state.world_restore.absolute_counter_raw_u32,
|
||||
world_restore_absolute_counter_mirror_raw_u32: state
|
||||
.world_restore
|
||||
.absolute_counter_mirror_raw_u32,
|
||||
|
|
@ -337,9 +333,10 @@ impl RuntimeSummary {
|
|||
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_current_partial_year_weight_numerator: selected_company_annual_finance_state
|
||||
.as_ref()
|
||||
.and_then(|finance_state| finance_state.current_partial_year_weight_numerator),
|
||||
selected_company_current_partial_year_weight_numerator:
|
||||
selected_company_annual_finance_state
|
||||
.as_ref()
|
||||
.and_then(|finance_state| finance_state.current_partial_year_weight_numerator),
|
||||
selected_company_current_issue_absolute_counter: selected_company_annual_finance_state
|
||||
.as_ref()
|
||||
.and_then(|finance_state| finance_state.current_issue_absolute_counter),
|
||||
|
|
@ -349,7 +346,9 @@ impl RuntimeSummary {
|
|||
selected_company_current_issue_age_absolute_counter_delta:
|
||||
selected_company_annual_finance_state
|
||||
.as_ref()
|
||||
.and_then(|finance_state| finance_state.current_issue_age_absolute_counter_delta),
|
||||
.and_then(|finance_state| {
|
||||
finance_state.current_issue_age_absolute_counter_delta
|
||||
}),
|
||||
selected_company_chairman_bonus_year: selected_company_market_state
|
||||
.map(|market_state| market_state.chairman_bonus_year)
|
||||
.filter(|year| *year != 0),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue