Execute descriptor 3 as territory access rights

This commit is contained in:
Jan Petykiewicz 2026-04-15 20:53:35 -07:00
commit e9c8bfbb9c
20 changed files with 1226 additions and 89 deletions

View file

@ -342,6 +342,21 @@ fn apply_runtime_effects(
mutated_player_ids.insert(player_id);
}
}
RuntimeEffect::SetCompanyTerritoryAccess {
target,
territory,
value,
} => {
let company_ids = resolve_company_target_ids(state, target, condition_context)?;
let territory_ids = resolve_territory_target_ids(state, territory)?;
set_company_territory_access_pairs(
&mut state.company_territory_access,
&company_ids,
&territory_ids,
*value,
);
mutated_company_ids.extend(company_ids);
}
RuntimeEffect::ConfiscateCompanyAssets { target } => {
let company_ids = resolve_company_target_ids(state, target, condition_context)?;
for company_id in company_ids.iter().copied() {
@ -1003,6 +1018,32 @@ fn retire_matching_trains(
}
}
fn set_company_territory_access_pairs(
access_entries: &mut Vec<crate::RuntimeCompanyTerritoryAccess>,
company_ids: &[u32],
territory_ids: &[u32],
value: bool,
) {
if value {
for company_id in company_ids {
for territory_id in territory_ids {
if !access_entries.iter().any(|entry| {
entry.company_id == *company_id && entry.territory_id == *territory_id
}) {
access_entries.push(crate::RuntimeCompanyTerritoryAccess {
company_id: *company_id,
territory_id: *territory_id,
});
}
}
}
} else {
access_entries.retain(|entry| {
!(company_ids.contains(&entry.company_id) && territory_ids.contains(&entry.territory_id))
});
}
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
@ -1044,6 +1085,7 @@ mod tests {
trains: 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(),
@ -1603,6 +1645,117 @@ mod tests {
assert_eq!(result.service_events[0].mutated_company_ids, vec![2]);
}
#[test]
fn sets_and_clears_company_territory_access_for_resolved_targets() {
let mut state = RuntimeState {
companies: vec![
RuntimeCompany {
company_id: 1,
controller_kind: RuntimeCompanyControllerKind::Human,
current_cash: 10,
debt: 0,
credit_rating_score: None,
prime_rate: None,
track_piece_counts: RuntimeTrackPieceCounts::default(),
active: true,
available_track_laying_capacity: None,
},
RuntimeCompany {
company_id: 2,
controller_kind: RuntimeCompanyControllerKind::Ai,
current_cash: 20,
debt: 0,
credit_rating_score: None,
prime_rate: None,
track_piece_counts: RuntimeTrackPieceCounts::default(),
active: true,
available_track_laying_capacity: None,
},
],
territories: vec![
RuntimeTerritory {
territory_id: 7,
name: Some("Appalachia".to_string()),
track_piece_counts: RuntimeTrackPieceCounts::default(),
},
RuntimeTerritory {
territory_id: 8,
name: Some("Great Plains".to_string()),
track_piece_counts: RuntimeTrackPieceCounts::default(),
},
],
event_runtime_records: vec![
RuntimeEventRecord {
record_id: 21,
trigger_kind: 7,
active: true,
service_count: 0,
marks_collection_dirty: false,
one_shot: true,
has_fired: false,
conditions: Vec::new(),
effects: vec![RuntimeEffect::SetCompanyTerritoryAccess {
target: RuntimeCompanyTarget::SelectedCompany,
territory: RuntimeTerritoryTarget::Ids { ids: vec![7, 8] },
value: true,
}],
},
RuntimeEventRecord {
record_id: 22,
trigger_kind: 8,
active: true,
service_count: 0,
marks_collection_dirty: false,
one_shot: true,
has_fired: false,
conditions: Vec::new(),
effects: vec![RuntimeEffect::SetCompanyTerritoryAccess {
target: RuntimeCompanyTarget::SelectedCompany,
territory: RuntimeTerritoryTarget::Ids { ids: vec![8] },
value: false,
}],
},
],
selected_company_id: Some(1),
..state()
};
let first = execute_step_command(
&mut state,
&StepCommand::ServiceTriggerKind { trigger_kind: 7 },
)
.expect("territory access grant should succeed");
assert_eq!(
state.company_territory_access,
vec![
crate::RuntimeCompanyTerritoryAccess {
company_id: 1,
territory_id: 7,
},
crate::RuntimeCompanyTerritoryAccess {
company_id: 1,
territory_id: 8,
},
]
);
assert_eq!(first.service_events[0].mutated_company_ids, vec![1]);
execute_step_command(
&mut state,
&StepCommand::ServiceTriggerKind { trigger_kind: 8 },
)
.expect("territory access clear should succeed");
assert_eq!(
state.company_territory_access,
vec![crate::RuntimeCompanyTerritoryAccess {
company_id: 1,
territory_id: 7,
}]
);
}
#[test]
fn rejects_condition_true_company_target_without_condition_context() {
let mut state = RuntimeState {