Execute real packed event world and train descriptors

This commit is contained in:
Jan Petykiewicz 2026-04-15 20:20:25 -07:00
commit e481274243
31 changed files with 3287 additions and 206 deletions

View file

@ -5,8 +5,8 @@ use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use crate::{
RuntimeCompanyConditionTestScope, RuntimeCompanyMetric, RuntimeCompanyTarget,
RuntimeCondition, RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecordTemplate,
RuntimeCompanyConditionTestScope, RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCondition,
RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecordTemplate,
RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeTerritoryMetric,
RuntimeTerritoryTarget, RuntimeTrackMetric,
};
@ -154,14 +154,14 @@ const REAL_GROUPED_EFFECT_DESCRIPTOR_METADATA: [RealGroupedEffectDescriptorMetad
label: "Economic Status",
target_mask_bits: 0x08,
parameter_family: "whole_game_state_enum",
executable_in_runtime: false,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 9,
label: "Confiscate All",
target_mask_bits: 0x01,
parameter_family: "company_confiscation_variant",
executable_in_runtime: false,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 13,
@ -175,7 +175,7 @@ const REAL_GROUPED_EFFECT_DESCRIPTOR_METADATA: [RealGroupedEffectDescriptorMetad
label: "Retire Train",
target_mask_bits: 0x0d,
parameter_family: "company_or_territory_asset_toggle",
executable_in_runtime: false,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 16,
@ -269,7 +269,9 @@ const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 22] = [
RealOrdinaryConditionMetadata {
raw_condition_id: 2316,
label: "Territory Transition Track Pieces",
metric: RealOrdinaryConditionMetric::Territory(RuntimeTerritoryMetric::TrackPiecesTransition),
metric: RealOrdinaryConditionMetric::Territory(
RuntimeTerritoryMetric::TrackPiecesTransition,
),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2317,
@ -279,7 +281,9 @@ const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 22] = [
RealOrdinaryConditionMetadata {
raw_condition_id: 2318,
label: "Territory Non-Electric Track Pieces",
metric: RealOrdinaryConditionMetric::Territory(RuntimeTerritoryMetric::TrackPiecesNonElectric),
metric: RealOrdinaryConditionMetric::Territory(
RuntimeTerritoryMetric::TrackPiecesNonElectric,
),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2323,
@ -2096,14 +2100,36 @@ fn parse_real_event_runtime_record_summary(
)?);
}
}
if let Some(control) = compact_control.as_ref() {
for row in &mut grouped_effect_rows {
if row.descriptor_id != 15
|| row.row_shape != "bool_toggle"
|| row.raw_scalar_value == 0
{
continue;
}
let company_target_present = control
.grouped_target_scope_ordinals_0x7fb
.get(row.group_index)
.copied()
.and_then(real_grouped_company_target)
.is_some();
let territory_target_present = control
.grouped_territory_selectors_0x80f
.get(row.group_index)
.is_some_and(|selector| *selector >= 0);
if !company_target_present && !territory_target_present {
row.notes
.push("retire train row is missing company and territory scope".to_string());
}
}
}
let negative_sentinel_scope = compact_control.as_ref().and_then(|control| {
derive_negative_sentinel_scope_summary(&standalone_condition_rows, control)
});
let decoded_conditions = decode_real_condition_rows(
&standalone_condition_rows,
negative_sentinel_scope.as_ref(),
);
let decoded_conditions =
decode_real_condition_rows(&standalone_condition_rows, negative_sentinel_scope.as_ref());
let decoded_actions = compact_control
.as_ref()
.map(|control| decode_real_grouped_effect_actions(&grouped_effect_rows, control))
@ -2253,7 +2279,10 @@ fn parse_real_condition_row_summary(
notes.push("condition row carries candidate-name side string".to_string());
}
if ordinary_metadata.is_none() && raw_condition_id >= 0 {
notes.push("ordinary condition id is not yet recovered in the checked-in condition table".to_string());
notes.push(
"ordinary condition id is not yet recovered in the checked-in condition table"
.to_string(),
);
}
Some(SmpLoadedPackedEventConditionRowSummary {
row_index,
@ -2462,33 +2491,31 @@ fn decode_real_condition_row(
let comparator = decode_real_condition_comparator(row.subtype)?;
let value = decode_real_condition_threshold(&row.flag_bytes)?;
match metadata.metric {
RealOrdinaryConditionMetric::Company(metric) => Some(RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
metric,
comparator,
value,
}),
RealOrdinaryConditionMetric::Territory(metric) => {
negative_sentinel_scope
.filter(|scope| scope.territory_scope_selector_is_0x63)
.map(|_| RuntimeCondition::TerritoryNumericThreshold {
target: RuntimeTerritoryTarget::AllTerritories,
metric,
comparator,
value,
})
}
RealOrdinaryConditionMetric::CompanyTerritory(metric) => {
negative_sentinel_scope
.filter(|scope| scope.territory_scope_selector_is_0x63)
.map(|_| RuntimeCondition::CompanyTerritoryNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
territory: RuntimeTerritoryTarget::AllTerritories,
metric,
comparator,
value,
})
RealOrdinaryConditionMetric::Company(metric) => {
Some(RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
metric,
comparator,
value,
})
}
RealOrdinaryConditionMetric::Territory(metric) => negative_sentinel_scope
.filter(|scope| scope.territory_scope_selector_is_0x63)
.map(|_| RuntimeCondition::TerritoryNumericThreshold {
target: RuntimeTerritoryTarget::AllTerritories,
metric,
comparator,
value,
}),
RealOrdinaryConditionMetric::CompanyTerritory(metric) => negative_sentinel_scope
.filter(|scope| scope.territory_scope_selector_is_0x63)
.map(|_| RuntimeCondition::CompanyTerritoryNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
territory: RuntimeTerritoryTarget::AllTerritories,
metric,
comparator,
value,
}),
}
}
@ -2616,6 +2643,24 @@ fn decode_real_grouped_effect_action(
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 8
&& row.row_shape == "scalar_assignment"
{
return Some(RuntimeEffect::SetEconomicStatusCode {
value: row.raw_scalar_value,
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 9
&& row.row_shape == "bool_toggle"
&& row.raw_scalar_value != 0
{
let target = real_grouped_company_target(target_scope_ordinal)?;
return Some(RuntimeEffect::ConfiscateCompanyAssets { target });
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 13
&& row.row_shape == "bool_toggle"
@ -2637,6 +2682,30 @@ fn decode_real_grouped_effect_action(
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 15
&& row.row_shape == "bool_toggle"
&& row.raw_scalar_value != 0
{
let company_target = real_grouped_company_target(target_scope_ordinal);
let territory_target = compact_control
.grouped_territory_selectors_0x80f
.get(row.group_index)
.copied()
.filter(|selector| *selector >= 0)
.map(|selector| RuntimeTerritoryTarget::Ids {
ids: vec![selector as u32],
});
if company_target.is_none() && territory_target.is_none() {
return None;
}
return Some(RuntimeEffect::RetireTrains {
company_target,
territory_target,
locomotive_name: row.locomotive_name.clone(),
});
}
None
}
@ -2808,10 +2877,13 @@ fn parse_optional_u16_len_prefixed_string(
fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
match effect {
RuntimeEffect::SetWorldFlag { .. }
| RuntimeEffect::SetEconomicStatusCode { .. }
| RuntimeEffect::SetCandidateAvailability { .. }
| RuntimeEffect::SetSpecialCondition { .. }
| RuntimeEffect::ConfiscateCompanyAssets { .. }
| RuntimeEffect::DeactivateCompany { .. }
| RuntimeEffect::SetCompanyTrackLayingCapacity { .. }
| RuntimeEffect::RetireTrains { .. }
| RuntimeEffect::ActivateEventRecord { .. }
| RuntimeEffect::DeactivateEventRecord { .. }
| RuntimeEffect::RemoveEventRecord { .. } => true,