Add territory and player packed event import

This commit is contained in:
Jan Petykiewicz 2026-04-15 19:15:47 -07:00
commit ca208f74e0
26 changed files with 1912 additions and 272 deletions

View file

@ -7,7 +7,8 @@ use sha2::{Digest, Sha256};
use crate::{
RuntimeCompanyConditionTestScope, RuntimeCompanyMetric, RuntimeCompanyTarget,
RuntimeCondition, RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecordTemplate,
RuntimePlayerConditionTestScope, RuntimeTerritoryMetric, RuntimeTrackMetric,
RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeTerritoryMetric,
RuntimeTerritoryTarget, RuntimeTrackMetric,
};
pub const SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION: u32 = 0x03ec;
@ -132,7 +133,7 @@ const REAL_GROUPED_EFFECT_DESCRIPTOR_METADATA: [RealGroupedEffectDescriptorMetad
label: "Player Cash",
target_mask_bits: 0x02,
parameter_family: "player_finance_scalar",
executable_in_runtime: false,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 2,
@ -2471,6 +2472,7 @@ fn decode_real_condition_row(
negative_sentinel_scope
.filter(|scope| scope.territory_scope_selector_is_0x63)
.map(|_| RuntimeCondition::TerritoryNumericThreshold {
target: RuntimeTerritoryTarget::AllTerritories,
metric,
comparator,
value,
@ -2481,6 +2483,7 @@ fn decode_real_condition_row(
.filter(|scope| scope.territory_scope_selector_is_0x63)
.map(|_| RuntimeCondition::CompanyTerritoryNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
territory: RuntimeTerritoryTarget::AllTerritories,
metric,
comparator,
value,
@ -2588,19 +2591,25 @@ fn decode_real_grouped_effect_action(
.grouped_target_scope_ordinals_0x7fb
.get(row.group_index)
.copied()?;
let target = match target_scope_ordinal {
0 => RuntimeCompanyTarget::ConditionTrueCompany,
1 => RuntimeCompanyTarget::SelectedCompany,
2 => RuntimeCompanyTarget::HumanCompanies,
3 => RuntimeCompanyTarget::AiCompanies,
_ => return None,
};
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 1
&& row.opcode == 8
&& row.row_shape == "multivalue_scalar"
{
let target = real_grouped_player_target(target_scope_ordinal)?;
return Some(RuntimeEffect::SetPlayerCash {
target,
value: i64::from(row.raw_scalar_value),
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 2
&& row.opcode == 8
&& row.row_shape == "multivalue_scalar"
{
let target = real_grouped_company_target(target_scope_ordinal)?;
return Some(RuntimeEffect::SetCompanyCash {
target,
value: i64::from(row.raw_scalar_value),
@ -2612,6 +2621,7 @@ fn decode_real_grouped_effect_action(
&& row.row_shape == "bool_toggle"
&& row.raw_scalar_value != 0
{
let target = real_grouped_company_target(target_scope_ordinal)?;
return Some(RuntimeEffect::DeactivateCompany { target });
}
@ -2620,6 +2630,7 @@ fn decode_real_grouped_effect_action(
&& row.row_shape == "scalar_assignment"
&& row.raw_scalar_value >= 0
{
let target = real_grouped_company_target(target_scope_ordinal)?;
return Some(RuntimeEffect::SetCompanyTrackLayingCapacity {
target,
value: Some(row.raw_scalar_value as u32),
@ -2629,6 +2640,26 @@ fn decode_real_grouped_effect_action(
None
}
fn real_grouped_company_target(ordinal: u8) -> Option<RuntimeCompanyTarget> {
match ordinal {
0 => Some(RuntimeCompanyTarget::ConditionTrueCompany),
1 => Some(RuntimeCompanyTarget::SelectedCompany),
2 => Some(RuntimeCompanyTarget::HumanCompanies),
3 => Some(RuntimeCompanyTarget::AiCompanies),
_ => None,
}
}
fn real_grouped_player_target(ordinal: u8) -> Option<RuntimePlayerTarget> {
match ordinal {
0 => Some(RuntimePlayerTarget::ConditionTruePlayer),
1 => Some(RuntimePlayerTarget::SelectedPlayer),
2 => Some(RuntimePlayerTarget::HumanPlayers),
3 => Some(RuntimePlayerTarget::AiPlayers),
_ => None,
}
}
fn parse_synthetic_packed_event_action(bytes: &[u8], cursor: &mut usize) -> Option<RuntimeEffect> {
let opcode = read_u8_at(bytes, *cursor)?;
*cursor += 1;
@ -2784,6 +2815,15 @@ fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
| RuntimeEffect::ActivateEventRecord { .. }
| RuntimeEffect::DeactivateEventRecord { .. }
| RuntimeEffect::RemoveEventRecord { .. } => true,
RuntimeEffect::SetPlayerCash { target, .. } => matches!(
target,
RuntimePlayerTarget::AllActive
| RuntimePlayerTarget::Ids { .. }
| RuntimePlayerTarget::HumanPlayers
| RuntimePlayerTarget::AiPlayers
| RuntimePlayerTarget::SelectedPlayer
| RuntimePlayerTarget::ConditionTruePlayer
),
RuntimeEffect::SetCompanyCash { target, .. }
| RuntimeEffect::AdjustCompanyCash { target, .. }
| RuntimeEffect::AdjustCompanyDebt { target, .. } => matches!(