Implement world-scalar packed event conditions

This commit is contained in:
Jan Petykiewicz 2026-04-16 13:48:55 -07:00
commit 3f2632e330
12 changed files with 1541 additions and 8 deletions

View file

@ -58,7 +58,13 @@ rows directly into `RuntimeState.named_locomotive_availability` and
`RuntimeState.named_locomotive_cost` without needing overlay snapshots when the save carries enough `RuntimeState.named_locomotive_cost` without needing overlay snapshots when the save carries enough
catalog context. The remaining recovered scalar world families execute too: cargo-production slots catalog context. The remaining recovered scalar world families execute too: cargo-production slots
`230..240` lower into `cargo_production_overrides`, and descriptor `453` lowers into `230..240` lower into `cargo_production_overrides`, and descriptor `453` lowers into
`world_restore.territory_access_cost`. Explicit unmapped world-condition and world-descriptor `world_restore.territory_access_cost`. Whole-game ordinary-condition breadth now aligns with those
same world-scalar runtime surfaces too: named locomotive availability thresholds, named
locomotive cost thresholds, aggregate cargo-production thresholds, limited-track-building-amount
thresholds, and territory-access-cost thresholds all gate imported runtime records through the
same service path. Families the current checked-in metadata still does not ground, such as `All
Factory Production`, now remain explicitly visible on `blocked_unmapped_world_condition` rather
than collapsing back to generic residue. Explicit unmapped world-condition and world-descriptor
frontier buckets still remain where current checked-in metadata stops, and frontier buckets still remain where current checked-in metadata stops, and
`blocked_missing_locomotive_catalog_context` is now reserved for intentionally incomplete save-side `blocked_missing_locomotive_catalog_context` is now reserved for intentionally incomplete save-side
catalog context instead of the normal save-slice path. Shell purchase-flow, Trainbuy refresh, catalog context instead of the normal save-slice path. Shell purchase-flow, Trainbuy refresh,

View file

@ -4476,6 +4476,13 @@ mod tests {
let world_scalar_executable_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join( let world_scalar_executable_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../fixtures/runtime/packed-event-world-scalar-executable-save-slice-fixture.json", "../../fixtures/runtime/packed-event-world-scalar-executable-save-slice-fixture.json",
); );
let world_scalar_condition_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../fixtures/runtime/packed-event-world-scalar-condition-save-slice-fixture.json",
);
let world_scalar_condition_parity_fixture =
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../fixtures/runtime/packed-event-world-scalar-condition-parity-save-slice-fixture.json",
);
run_runtime_summarize_fixture(&parity_fixture) run_runtime_summarize_fixture(&parity_fixture)
.expect("save-slice-backed parity fixture should summarize"); .expect("save-slice-backed parity fixture should summarize");
@ -4511,6 +4518,10 @@ mod tests {
.expect("save-slice-backed recovered scalar-band parity fixture should summarize"); .expect("save-slice-backed recovered scalar-band parity fixture should summarize");
run_runtime_summarize_fixture(&world_scalar_executable_fixture) run_runtime_summarize_fixture(&world_scalar_executable_fixture)
.expect("save-slice-backed executable world-scalar fixture should summarize"); .expect("save-slice-backed executable world-scalar fixture should summarize");
run_runtime_summarize_fixture(&world_scalar_condition_fixture)
.expect("save-slice-backed executable world-scalar condition fixture should summarize");
run_runtime_summarize_fixture(&world_scalar_condition_parity_fixture)
.expect("save-slice-backed parity world-scalar condition fixture should summarize");
} }
#[test] #[test]

View file

@ -1544,6 +1544,42 @@ fn lower_condition_targets_in_condition(
comparator: *comparator, comparator: *comparator,
value: *value, value: *value,
}, },
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
name,
comparator,
value,
} => RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
name: name.clone(),
comparator: *comparator,
value: *value,
},
RuntimeCondition::NamedLocomotiveCostThreshold {
name,
comparator,
value,
} => RuntimeCondition::NamedLocomotiveCostThreshold {
name: name.clone(),
comparator: *comparator,
value: *value,
},
RuntimeCondition::CargoProductionTotalThreshold { comparator, value } => {
RuntimeCondition::CargoProductionTotalThreshold {
comparator: *comparator,
value: *value,
}
}
RuntimeCondition::LimitedTrackBuildingAmountThreshold { comparator, value } => {
RuntimeCondition::LimitedTrackBuildingAmountThreshold {
comparator: *comparator,
value: *value,
}
}
RuntimeCondition::TerritoryAccessCostThreshold { comparator, value } => {
RuntimeCondition::TerritoryAccessCostThreshold {
comparator: *comparator,
value: *value,
}
}
RuntimeCondition::EconomicStatusCodeThreshold { comparator, value } => { RuntimeCondition::EconomicStatusCodeThreshold { comparator, value } => {
RuntimeCondition::EconomicStatusCodeThreshold { RuntimeCondition::EconomicStatusCodeThreshold {
comparator: *comparator, comparator: *comparator,
@ -1633,6 +1669,11 @@ fn condition_uses_condition_true_company(condition: &RuntimeCondition) -> bool {
RuntimeCondition::TerritoryNumericThreshold { .. } RuntimeCondition::TerritoryNumericThreshold { .. }
| RuntimeCondition::SpecialConditionThreshold { .. } | RuntimeCondition::SpecialConditionThreshold { .. }
| RuntimeCondition::CandidateAvailabilityThreshold { .. } | RuntimeCondition::CandidateAvailabilityThreshold { .. }
| RuntimeCondition::NamedLocomotiveAvailabilityThreshold { .. }
| RuntimeCondition::NamedLocomotiveCostThreshold { .. }
| RuntimeCondition::CargoProductionTotalThreshold { .. }
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
| RuntimeCondition::TerritoryAccessCostThreshold { .. }
| RuntimeCondition::EconomicStatusCodeThreshold { .. } | RuntimeCondition::EconomicStatusCodeThreshold { .. }
| RuntimeCondition::WorldFlagEquals { .. } => false, | RuntimeCondition::WorldFlagEquals { .. } => false,
} }
@ -2251,6 +2292,11 @@ fn runtime_condition_is_world_state(condition: &RuntimeCondition) -> bool {
condition, condition,
RuntimeCondition::SpecialConditionThreshold { .. } RuntimeCondition::SpecialConditionThreshold { .. }
| RuntimeCondition::CandidateAvailabilityThreshold { .. } | RuntimeCondition::CandidateAvailabilityThreshold { .. }
| RuntimeCondition::NamedLocomotiveAvailabilityThreshold { .. }
| RuntimeCondition::NamedLocomotiveCostThreshold { .. }
| RuntimeCondition::CargoProductionTotalThreshold { .. }
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
| RuntimeCondition::TerritoryAccessCostThreshold { .. }
| RuntimeCondition::EconomicStatusCodeThreshold { .. } | RuntimeCondition::EconomicStatusCodeThreshold { .. }
| RuntimeCondition::WorldFlagEquals { .. } | RuntimeCondition::WorldFlagEquals { .. }
) )
@ -2262,12 +2308,18 @@ fn ordinary_condition_row_is_world_state_family(
row.metric.as_deref().is_some_and(|metric| { row.metric.as_deref().is_some_and(|metric| {
metric.contains("Special Condition") metric.contains("Special Condition")
|| metric.contains("Candidate Availability") || metric.contains("Candidate Availability")
|| metric.contains("Named Locomotive")
|| metric.contains("Cargo Production")
|| metric.contains("Limited Track Building Amount")
|| metric.contains("Territory Access Cost")
|| metric.contains("Economic Status") || metric.contains("Economic Status")
|| metric.contains("World Flag") || metric.contains("World Flag")
}) || row }) || row.semantic_family.as_deref().is_some_and(|family| {
.semantic_family matches!(
.as_deref() family,
.is_some_and(|family| family == "world_state_threshold" || family == "world_flag_equals") "world_state_threshold" | "world_scalar_threshold" | "world_flag_equals"
)
})
} }
fn real_grouped_row_is_world_state_family( fn real_grouped_row_is_world_state_family(
@ -2334,6 +2386,11 @@ fn runtime_condition_company_target_import_blocker(
.or_else(|| territory_target_import_blocker(territory, company_context)), .or_else(|| territory_target_import_blocker(territory, company_context)),
RuntimeCondition::SpecialConditionThreshold { .. } RuntimeCondition::SpecialConditionThreshold { .. }
| RuntimeCondition::CandidateAvailabilityThreshold { .. } | RuntimeCondition::CandidateAvailabilityThreshold { .. }
| RuntimeCondition::NamedLocomotiveAvailabilityThreshold { .. }
| RuntimeCondition::NamedLocomotiveCostThreshold { .. }
| RuntimeCondition::CargoProductionTotalThreshold { .. }
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
| RuntimeCondition::TerritoryAccessCostThreshold { .. }
| RuntimeCondition::EconomicStatusCodeThreshold { .. } | RuntimeCondition::EconomicStatusCodeThreshold { .. }
| RuntimeCondition::WorldFlagEquals { .. } => None, | RuntimeCondition::WorldFlagEquals { .. } => None,
} }
@ -2855,7 +2912,10 @@ fn resolve_document_path(base_dir: &Path, path: &str) -> PathBuf {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{RuntimeTrackPieceCounts, RuntimeTrain, StepCommand, execute_step_command}; use crate::{
RuntimeConditionComparator, RuntimeTrackPieceCounts, RuntimeTrain, StepCommand,
execute_step_command,
};
fn state() -> RuntimeState { fn state() -> RuntimeState {
RuntimeState { RuntimeState {
@ -7859,6 +7919,262 @@ mod tests {
); );
} }
#[test]
fn imports_and_executes_world_scalar_conditions_through_runtime_state() {
let save_slice = SmpLoadedSaveSlice {
file_extension_hint: Some("gms".to_string()),
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
trailer_family: None,
bridge_family: None,
profile: None,
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
metadata_tag_offset: 0x7100,
records_tag_offset: 0x7200,
close_tag_offset: 0x7800,
packed_state_version: 0x3e9,
packed_state_version_hex: "0x000003e9".to_string(),
live_id_bound: 45,
live_record_count: 2,
live_entry_ids: vec![41, 45],
decoded_record_count: 2,
imported_runtime_record_count: 2,
records: vec![
crate::SmpLoadedPackedEventRecordSummary {
record_index: 0,
live_entry_id: 41,
payload_offset: Some(0x7200),
payload_len: Some(192),
decode_status: "executable".to_string(),
payload_family: "real_packed_v1".to_string(),
trigger_kind: Some(6),
active: None,
marks_collection_dirty: None,
one_shot: Some(false),
compact_control: Some(real_compact_control()),
text_bands: packed_text_bands(),
standalone_condition_row_count: 0,
standalone_condition_rows: vec![],
negative_sentinel_scope: None,
grouped_effect_row_counts: vec![5, 0, 0, 0],
grouped_effect_rows: vec![
real_locomotive_availability_row(250, 42),
real_locomotive_cost_row(352, 250000),
real_cargo_production_row(230, 125),
real_limited_track_building_amount_row(18),
real_territory_access_cost_row(750000),
],
decoded_conditions: vec![],
decoded_actions: vec![
RuntimeEffect::SetNamedLocomotiveAvailabilityValue {
name: "Big Boy".to_string(),
value: 42,
},
RuntimeEffect::SetNamedLocomotiveCost {
name: "Locomotive 1".to_string(),
value: 250000,
},
RuntimeEffect::SetCargoProductionSlot {
slot: 1,
value: 125,
},
RuntimeEffect::SetLimitedTrackBuildingAmount { value: 18 },
RuntimeEffect::SetTerritoryAccessCost { value: 750000 },
],
executable_import_ready: true,
notes: vec!["world-scalar setup record".to_string()],
},
crate::SmpLoadedPackedEventRecordSummary {
record_index: 1,
live_entry_id: 45,
payload_offset: Some(0x7300),
payload_len: Some(184),
decode_status: "executable".to_string(),
payload_family: "real_packed_v1".to_string(),
trigger_kind: Some(7),
active: None,
marks_collection_dirty: None,
one_shot: Some(false),
compact_control: Some(real_compact_control()),
text_bands: packed_text_bands(),
standalone_condition_row_count: 5,
standalone_condition_rows: vec![
crate::SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: 2422,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&42_i32.to_le_bytes());
bytes
},
candidate_name: Some("Big Boy".to_string()),
comparator: Some("eq".to_string()),
metric: Some("Named Locomotive Availability: Big Boy".to_string()),
semantic_family: Some("world_scalar_threshold".to_string()),
semantic_preview: Some(
"Test Named Locomotive Availability: Big Boy == 42".to_string(),
),
requires_candidate_name_binding: false,
notes: vec![],
},
crate::SmpLoadedPackedEventConditionRowSummary {
row_index: 1,
raw_condition_id: 2423,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&250000_i32.to_le_bytes());
bytes
},
candidate_name: Some("Locomotive 1".to_string()),
comparator: Some("eq".to_string()),
metric: Some("Named Locomotive Cost: Locomotive 1".to_string()),
semantic_family: Some("world_scalar_threshold".to_string()),
semantic_preview: Some(
"Test Named Locomotive Cost: Locomotive 1 == 250000"
.to_string(),
),
requires_candidate_name_binding: false,
notes: vec![],
},
crate::SmpLoadedPackedEventConditionRowSummary {
row_index: 2,
raw_condition_id: 2418,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&125_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Cargo Production Total".to_string()),
semantic_family: Some("world_scalar_threshold".to_string()),
semantic_preview: Some(
"Test Cargo Production Total == 125".to_string(),
),
requires_candidate_name_binding: false,
notes: vec![],
},
crate::SmpLoadedPackedEventConditionRowSummary {
row_index: 3,
raw_condition_id: 2547,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&18_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Limited Track Building Amount".to_string()),
semantic_family: Some("world_scalar_threshold".to_string()),
semantic_preview: Some(
"Test Limited Track Building Amount == 18".to_string(),
),
requires_candidate_name_binding: false,
notes: vec![],
},
crate::SmpLoadedPackedEventConditionRowSummary {
row_index: 4,
raw_condition_id: 1516,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&750000_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Territory Access Cost".to_string()),
semantic_family: Some("world_scalar_threshold".to_string()),
semantic_preview: Some(
"Test Territory Access Cost == 750000".to_string(),
),
requires_candidate_name_binding: false,
notes: vec![],
},
],
negative_sentinel_scope: None,
grouped_effect_row_counts: vec![1, 0, 0, 0],
grouped_effect_rows: vec![real_world_flag_row(
110,
"Disable Stock Buying and Selling",
true,
)],
decoded_conditions: vec![
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
name: "Big Boy".to_string(),
comparator: RuntimeConditionComparator::Eq,
value: 42,
},
RuntimeCondition::NamedLocomotiveCostThreshold {
name: "Locomotive 1".to_string(),
comparator: RuntimeConditionComparator::Eq,
value: 250000,
},
RuntimeCondition::CargoProductionTotalThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 125,
},
RuntimeCondition::LimitedTrackBuildingAmountThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 18,
},
RuntimeCondition::TerritoryAccessCostThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 750000,
},
],
decoded_actions: vec![RuntimeEffect::SetWorldFlag {
key: "world.world_scalar_conditions_passed".to_string(),
value: true,
}],
executable_import_ready: true,
notes: vec!["world-scalar conditions gate a world-side effect".to_string()],
},
],
}),
notes: vec![],
};
let mut import = project_save_slice_to_runtime_state_import(
&save_slice,
"world-scalar-condition-save-slice",
None,
)
.expect("save-slice import should project");
crate::execute_step_command(
&mut import.state,
&crate::StepCommand::ServiceTriggerKind { trigger_kind: 6 },
)
.expect("setup trigger should execute");
crate::execute_step_command(
&mut import.state,
&crate::StepCommand::ServiceTriggerKind { trigger_kind: 7 },
)
.expect("gated trigger should execute");
assert_eq!(
import
.state
.world_flags
.get("world.world_scalar_conditions_passed"),
Some(&true)
);
}
#[test] #[test]
fn overlays_recovered_world_toggle_batch_into_executable_runtime_record() { fn overlays_recovered_world_toggle_batch_into_executable_runtime_record() {
let base_state = state(); let base_state = state();

View file

@ -244,6 +244,28 @@ pub enum RuntimeCondition {
comparator: RuntimeConditionComparator, comparator: RuntimeConditionComparator,
value: i64, value: i64,
}, },
NamedLocomotiveAvailabilityThreshold {
name: String,
comparator: RuntimeConditionComparator,
value: i64,
},
NamedLocomotiveCostThreshold {
name: String,
comparator: RuntimeConditionComparator,
value: i64,
},
CargoProductionTotalThreshold {
comparator: RuntimeConditionComparator,
value: i64,
},
LimitedTrackBuildingAmountThreshold {
comparator: RuntimeConditionComparator,
value: i64,
},
TerritoryAccessCostThreshold {
comparator: RuntimeConditionComparator,
value: i64,
},
EconomicStatusCodeThreshold { EconomicStatusCodeThreshold {
comparator: RuntimeConditionComparator, comparator: RuntimeConditionComparator,
value: i64, value: i64,
@ -1375,6 +1397,17 @@ fn validate_runtime_condition(
Ok(()) Ok(())
} }
} }
RuntimeCondition::NamedLocomotiveAvailabilityThreshold { name, .. }
| RuntimeCondition::NamedLocomotiveCostThreshold { name, .. } => {
if name.trim().is_empty() {
Err("name must not be empty".to_string())
} else {
Ok(())
}
}
RuntimeCondition::CargoProductionTotalThreshold { .. }
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
| RuntimeCondition::TerritoryAccessCostThreshold { .. } => Ok(()),
RuntimeCondition::EconomicStatusCodeThreshold { .. } => Ok(()), RuntimeCondition::EconomicStatusCodeThreshold { .. } => Ok(()),
RuntimeCondition::WorldFlagEquals { key, .. } => { RuntimeCondition::WorldFlagEquals { key, .. } => {
if key.trim().is_empty() { if key.trim().is_empty() {

View file

@ -240,6 +240,11 @@ enum RealOrdinaryConditionMetric {
enum RealWorldConditionKind { enum RealWorldConditionKind {
SpecialCondition { label: &'static str }, SpecialCondition { label: &'static str },
CandidateAvailability, CandidateAvailability,
NamedLocomotiveAvailability,
NamedLocomotiveCost,
CargoProductionTotal,
LimitedTrackBuildingAmount,
TerritoryAccessCost,
EconomicStatus, EconomicStatus,
WorldFlag { key: &'static str }, WorldFlag { key: &'static str },
} }
@ -258,8 +263,13 @@ struct RealOrdinaryConditionMetadata {
} }
const REAL_CANDIDATE_AVAILABILITY_CONDITION_TEMPLATE_ID: i32 = 435; const REAL_CANDIDATE_AVAILABILITY_CONDITION_TEMPLATE_ID: i32 = 435;
const REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID: i32 = 2422;
const REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID: i32 = 2423;
const REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID: i32 = 2418;
const REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID: i32 = 2547;
const REAL_TERRITORY_ACCESS_COST_CONDITION_ID: i32 = 1516;
const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 24] = [ const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 29] = [
RealOrdinaryConditionMetadata { RealOrdinaryConditionMetadata {
raw_condition_id: 1802, raw_condition_id: 1802,
label: "Current Cash", label: "Current Cash",
@ -419,6 +429,35 @@ const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 24] = [
label: "%1 Avail.", label: "%1 Avail.",
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CandidateAvailability), kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CandidateAvailability),
}, },
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID,
label: "Unknown Loco Available",
kind: RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::NamedLocomotiveAvailability,
),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID,
label: "Unknown Loco Cost",
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID,
label: "All Cargo Production",
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID,
label: "Limited Track Building Amount",
kind: RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::LimitedTrackBuildingAmount,
),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_TERRITORY_ACCESS_COST_CONDITION_ID,
label: "Access Rights Cost:",
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost),
},
RealOrdinaryConditionMetadata { RealOrdinaryConditionMetadata {
raw_condition_id: 2350, raw_condition_id: 2350,
label: "Economic Status", label: "Economic Status",
@ -2526,6 +2565,17 @@ fn parse_real_condition_row_summary(
.to_string(), .to_string(),
); );
} }
if ordinary_metadata.is_some_and(|metadata| {
matches!(
metadata.kind,
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::NamedLocomotiveAvailability
| RealWorldConditionKind::NamedLocomotiveCost
)
) && candidate_name.is_none()
}) {
notes.push("named locomotive condition row is missing its side-string binding".to_string());
}
Some(SmpLoadedPackedEventConditionRowSummary { Some(SmpLoadedPackedEventConditionRowSummary {
row_index, row_index,
raw_condition_id, raw_condition_id,
@ -2645,6 +2695,27 @@ fn real_ordinary_condition_metric_label(
None => "Candidate Availability".to_string(), None => "Candidate Availability".to_string(),
} }
} }
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::NamedLocomotiveAvailability,
) => match candidate_name {
Some(name) => format!("Named Locomotive Availability: {name}"),
None => "Named Locomotive Availability".to_string(),
},
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost) => {
match candidate_name {
Some(name) => format!("Named Locomotive Cost: {name}"),
None => "Named Locomotive Cost".to_string(),
}
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal) => {
"Cargo Production Total".to_string()
}
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::LimitedTrackBuildingAmount,
) => "Limited Track Building Amount".to_string(),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost) => {
"Territory Access Cost".to_string()
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => { RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => {
"Economic Status".to_string() "Economic Status".to_string()
} }
@ -2662,6 +2733,13 @@ fn real_ordinary_condition_semantic_family(
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { .. }) => { RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { .. }) => {
"world_flag_equals" "world_flag_equals"
} }
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::NamedLocomotiveAvailability
| RealWorldConditionKind::NamedLocomotiveCost
| RealWorldConditionKind::CargoProductionTotal
| RealWorldConditionKind::LimitedTrackBuildingAmount
| RealWorldConditionKind::TerritoryAccessCost,
) => "world_scalar_threshold",
RealOrdinaryConditionKind::WorldState(_) => "world_state_threshold", RealOrdinaryConditionKind::WorldState(_) => "world_state_threshold",
} }
} }
@ -2868,6 +2946,32 @@ fn decode_real_condition_row(
comparator, comparator,
value, value,
}), }),
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::NamedLocomotiveAvailability,
) => row.candidate_name.as_ref().map(|name| {
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
name: name.clone(),
comparator,
value,
}
}),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost) => row
.candidate_name
.as_ref()
.map(|name| RuntimeCondition::NamedLocomotiveCostThreshold {
name: name.clone(),
comparator,
value,
}),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal) => {
Some(RuntimeCondition::CargoProductionTotalThreshold { comparator, value })
}
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::LimitedTrackBuildingAmount,
) => Some(RuntimeCondition::LimitedTrackBuildingAmountThreshold { comparator, value }),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost) => {
Some(RuntimeCondition::TerritoryAccessCostThreshold { comparator, value })
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => { RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => {
Some(RuntimeCondition::EconomicStatusCodeThreshold { comparator, value }) Some(RuntimeCondition::EconomicStatusCodeThreshold { comparator, value })
} }
@ -3655,6 +3759,11 @@ fn runtime_condition_supported_for_save_import(condition: &RuntimeCondition) ->
| RuntimeCondition::CompanyTerritoryNumericThreshold { .. } | RuntimeCondition::CompanyTerritoryNumericThreshold { .. }
| RuntimeCondition::SpecialConditionThreshold { .. } | RuntimeCondition::SpecialConditionThreshold { .. }
| RuntimeCondition::CandidateAvailabilityThreshold { .. } | RuntimeCondition::CandidateAvailabilityThreshold { .. }
| RuntimeCondition::NamedLocomotiveAvailabilityThreshold { .. }
| RuntimeCondition::NamedLocomotiveCostThreshold { .. }
| RuntimeCondition::CargoProductionTotalThreshold { .. }
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
| RuntimeCondition::TerritoryAccessCostThreshold { .. }
| RuntimeCondition::EconomicStatusCodeThreshold { .. } | RuntimeCondition::EconomicStatusCodeThreshold { .. }
| RuntimeCondition::WorldFlagEquals { .. } => true, | RuntimeCondition::WorldFlagEquals { .. } => true,
} }
@ -9431,6 +9540,224 @@ mod tests {
); );
} }
#[test]
fn decodes_real_named_locomotive_availability_threshold_from_checked_in_metadata() {
let condition_row = build_real_condition_row_with_threshold(
REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID,
4,
42,
Some("Big Boy"),
);
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[condition_row],
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.metric
.as_deref(),
Some("Named Locomotive Availability: Big Boy")
);
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.semantic_family
.as_deref(),
Some("world_scalar_threshold")
);
assert_eq!(
summary.records[0].decoded_conditions,
vec![RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
name: "Big Boy".to_string(),
comparator: RuntimeConditionComparator::Eq,
value: 42,
}]
);
}
#[test]
fn decodes_real_named_locomotive_cost_threshold_from_checked_in_metadata() {
let condition_row = build_real_condition_row_with_threshold(
REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID,
0,
250000,
Some("Locomotive 1"),
);
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[condition_row],
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.metric
.as_deref(),
Some("Named Locomotive Cost: Locomotive 1")
);
assert_eq!(
summary.records[0].decoded_conditions,
vec![RuntimeCondition::NamedLocomotiveCostThreshold {
name: "Locomotive 1".to_string(),
comparator: RuntimeConditionComparator::Ge,
value: 250000,
}]
);
}
#[test]
fn decodes_real_world_scalar_thresholds_from_checked_in_metadata() {
let condition_rows = vec![
build_real_condition_row_with_threshold(
REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID,
0,
200,
None,
),
build_real_condition_row_with_threshold(
REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID,
4,
18,
None,
),
build_real_condition_row_with_threshold(
REAL_TERRITORY_ACCESS_COST_CONDITION_ID,
4,
750000,
None,
),
];
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&condition_rows,
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.metric
.as_deref(),
Some("Cargo Production Total")
);
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.semantic_family
.as_deref(),
Some("world_scalar_threshold")
);
assert_eq!(
summary.records[0].decoded_conditions,
vec![
RuntimeCondition::CargoProductionTotalThreshold {
comparator: RuntimeConditionComparator::Ge,
value: 200,
},
RuntimeCondition::LimitedTrackBuildingAmountThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 18,
},
RuntimeCondition::TerritoryAccessCostThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 750000,
},
]
);
}
#[test] #[test]
fn decodes_real_world_flag_condition_from_checked_in_world_condition_metadata() { fn decodes_real_world_flag_condition_from_checked_in_world_condition_metadata() {
let condition_row = build_real_condition_row_with_threshold(2535, 4, 1, None); let condition_row = build_real_condition_row_with_threshold(2535, 4, 1, None);
@ -9492,6 +9819,31 @@ mod tests {
); );
} }
#[test]
fn looks_up_checked_in_world_scalar_condition_metadata() {
let availability =
real_ordinary_condition_metadata(REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID)
.expect("availability condition metadata should exist");
assert_eq!(availability.label, "Unknown Loco Available");
let cost = real_ordinary_condition_metadata(REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID)
.expect("cost condition metadata should exist");
assert_eq!(cost.label, "Unknown Loco Cost");
let cargo = real_ordinary_condition_metadata(REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID)
.expect("cargo condition metadata should exist");
assert_eq!(cargo.label, "All Cargo Production");
let build_limit =
real_ordinary_condition_metadata(REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID)
.expect("build-limit condition metadata should exist");
assert_eq!(build_limit.label, "Limited Track Building Amount");
let access_cost = real_ordinary_condition_metadata(REAL_TERRITORY_ACCESS_COST_CONDITION_ID)
.expect("territory-access-cost condition metadata should exist");
assert_eq!(access_cost.label, "Access Rights Cost:");
}
#[test] #[test]
fn looks_up_checked_in_world_flag_descriptor_metadata() { fn looks_up_checked_in_world_flag_descriptor_metadata() {
let metadata = let metadata =

View file

@ -722,6 +722,67 @@ fn evaluate_record_conditions(
return Ok(None); return Ok(None);
} }
} }
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
name,
comparator,
value,
} => {
let actual = state
.named_locomotive_availability
.get(name)
.copied()
.map(i64::from)
.unwrap_or(0);
if !compare_condition_value(actual, *comparator, *value) {
return Ok(None);
}
}
RuntimeCondition::NamedLocomotiveCostThreshold {
name,
comparator,
value,
} => {
let actual = state
.named_locomotive_cost
.get(name)
.copied()
.map(i64::from)
.unwrap_or(0);
if !compare_condition_value(actual, *comparator, *value) {
return Ok(None);
}
}
RuntimeCondition::CargoProductionTotalThreshold { comparator, value } => {
let actual = state
.cargo_production_overrides
.values()
.copied()
.map(i64::from)
.sum::<i64>();
if !compare_condition_value(actual, *comparator, *value) {
return Ok(None);
}
}
RuntimeCondition::LimitedTrackBuildingAmountThreshold { comparator, value } => {
let actual = state
.world_restore
.limited_track_building_amount
.map(i64::from)
.unwrap_or(0);
if !compare_condition_value(actual, *comparator, *value) {
return Ok(None);
}
}
RuntimeCondition::TerritoryAccessCostThreshold { comparator, value } => {
let actual = state
.world_restore
.territory_access_cost
.map(i64::from)
.unwrap_or(0);
if !compare_condition_value(actual, *comparator, *value) {
return Ok(None);
}
}
RuntimeCondition::EconomicStatusCodeThreshold { comparator, value } => { RuntimeCondition::EconomicStatusCodeThreshold { comparator, value } => {
let actual = state let actual = state
.world_restore .world_restore
@ -2142,6 +2203,91 @@ mod tests {
assert_eq!(state.world_flags.get("world_condition_failed"), None); assert_eq!(state.world_flags.get("world_condition_failed"), None);
} }
#[test]
fn evaluates_world_scalar_conditions_before_effects_run() {
let mut state = RuntimeState {
world_restore: RuntimeWorldRestoreState {
limited_track_building_amount: Some(18),
territory_access_cost: Some(750000),
..RuntimeWorldRestoreState::default()
},
named_locomotive_availability: BTreeMap::from([(String::from("Big Boy"), 42)]),
named_locomotive_cost: BTreeMap::from([(String::from("GP7"), 175000)]),
cargo_production_overrides: BTreeMap::from([(1, 125), (2, 75)]),
event_runtime_records: vec![
RuntimeEventRecord {
record_id: 25,
trigger_kind: 7,
active: true,
service_count: 0,
marks_collection_dirty: false,
one_shot: false,
has_fired: false,
conditions: vec![
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
name: "Big Boy".to_string(),
comparator: RuntimeConditionComparator::Eq,
value: 42,
},
RuntimeCondition::NamedLocomotiveCostThreshold {
name: "GP7".to_string(),
comparator: RuntimeConditionComparator::Eq,
value: 175000,
},
RuntimeCondition::CargoProductionTotalThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 200,
},
RuntimeCondition::LimitedTrackBuildingAmountThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 18,
},
RuntimeCondition::TerritoryAccessCostThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 750000,
},
],
effects: vec![RuntimeEffect::SetWorldFlag {
key: "world_scalar_condition_passed".to_string(),
value: true,
}],
},
RuntimeEventRecord {
record_id: 26,
trigger_kind: 7,
active: true,
service_count: 0,
marks_collection_dirty: false,
one_shot: false,
has_fired: false,
conditions: vec![RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
name: "Missing Loco".to_string(),
comparator: RuntimeConditionComparator::Gt,
value: 0,
}],
effects: vec![RuntimeEffect::SetWorldFlag {
key: "world_scalar_condition_failed".to_string(),
value: true,
}],
},
],
..state()
};
let result = execute_step_command(
&mut state,
&StepCommand::ServiceTriggerKind { trigger_kind: 7 },
)
.expect("world-scalar conditions should evaluate successfully");
assert_eq!(result.service_events[0].serviced_record_ids, vec![25]);
assert_eq!(
state.world_flags.get("world_scalar_condition_passed"),
Some(&true)
);
assert_eq!(state.world_flags.get("world_scalar_condition_failed"), None);
}
#[test] #[test]
fn one_shot_record_only_fires_once() { fn one_shot_record_only_fires_once() {
let mut state = RuntimeState { let mut state = RuntimeState {

View file

@ -138,6 +138,12 @@ The highest-value next passes are now:
- cargo-production `230..240` and territory-access-cost `453` now execute too through minimal - cargo-production `230..240` and territory-access-cost `453` now execute too through minimal
world-side scalar landing surfaces: slot-indexed `cargo_production_overrides` and world-side scalar landing surfaces: slot-indexed `cargo_production_overrides` and
`world_restore.territory_access_cost` `world_restore.territory_access_cost`
- world-scalar ordinary-condition coverage now matches those runtime surfaces too: checked-in
metadata lowers named locomotive availability, named locomotive cost, aggregate cargo
production, limited-track-building-amount, and territory-access-cost rows into explicit runtime
condition gates
- the remaining world-scalar condition frontier is now narrow and explicit: unsupported families
such as `All Factory Production` stay parity-only on `blocked_unmapped_world_condition`
- keep in mind that the current local `.gms` corpus still exports with no packed event collection, - keep in mind that the current local `.gms` corpus still exports with no packed event collection,
so real descriptor mapping needs to stay plumbing-first until better captures exist so real descriptor mapping needs to stay plumbing-first until better captures exist
- use `rrt-hook` primarily as optional capture or integration tooling, not as the first execution - use `rrt-hook` primarily as optional capture or integration tooling, not as the first execution

View file

@ -97,11 +97,18 @@ Implemented today:
- the remaining recovered scalar world families now execute as well: cargo-production `230..240` - the remaining recovered scalar world families now execute as well: cargo-production `230..240`
rows lower into slot-indexed `cargo_production_overrides`, and territory-access-cost descriptor rows lower into slot-indexed `cargo_production_overrides`, and territory-access-cost descriptor
`453` lowers into `world_restore.territory_access_cost` `453` lowers into `world_restore.territory_access_cost`
- world-scalar ordinary-condition coverage now aligns with those runtime surfaces too: checked-in
metadata lowers named locomotive availability, named locomotive cost, aggregate cargo
production, limited-track-building-amount, and territory-access-cost rows into explicit runtime
condition gates
- the remaining world-side condition frontier is now narrower and more honest: unsupported scalar
families such as `All Factory Production` stay visible on `blocked_unmapped_world_condition`
instead of falling back to generic placeholder ids
That means the next implementation work is breadth, not bootstrap. The recommended next slice is That means the next implementation work is breadth, not bootstrap. The recommended next slice is
broader real grouped-descriptor and ordinary condition-id coverage beyond the current access, broader real grouped-descriptor and ordinary condition-id coverage beyond the current access,
whole-game toggle, train, player, numeric-threshold, named locomotive availability, named whole-game toggle, train, player, numeric-threshold, named locomotive availability, named
locomotive cost, and world scalar override batches. locomotive cost, world scalar override, and world-scalar condition batches.
Richer runtime ownership should still be added only where a later descriptor or condition family Richer runtime ownership should still be added only where a later descriptor or condition family
needs more than the current event-owned roster. needs more than the current event-owned roster.

View file

@ -0,0 +1,43 @@
{
"format_version": 1,
"fixture_id": "packed-event-world-scalar-condition-parity-save-slice-fixture",
"source": {
"kind": "captured-runtime",
"description": "Fixture pinning one remaining unmapped world-scalar ordinary-condition family after the grounded batch."
},
"state_save_slice_path": "packed-event-world-scalar-condition-parity-save-slice.json",
"commands": [
{
"kind": "service_trigger_kind",
"trigger_kind": 7
}
],
"expected_summary": {
"packed_event_collection_present": true,
"packed_event_record_count": 1,
"packed_event_decoded_record_count": 1,
"packed_event_imported_runtime_record_count": 0,
"packed_event_parity_only_record_count": 1,
"packed_event_blocked_unmapped_world_descriptor_count": 1,
"event_runtime_record_count": 0,
"world_flag_count": 7,
"total_event_record_service_count": 0,
"total_trigger_dispatch_count": 1
},
"expected_state_fragment": {
"packed_event_collection": {
"records": [
{
"import_outcome": "blocked_unmapped_world_descriptor",
"standalone_condition_rows": [
{
"raw_condition_id": 2419,
"metric": "All Factory Production",
"semantic_family": "world_scalar_threshold"
}
]
}
]
}
}
}

View file

@ -0,0 +1,125 @@
{
"format_version": 1,
"save_slice_id": "packed-event-world-scalar-condition-parity-save-slice",
"source": {
"description": "Tracked save-slice document pinning one remaining unmapped world-scalar condition family after the grounded batch.",
"original_save_filename": "captured-world-scalar-condition-parity.gms",
"original_save_sha256": "world-scalar-condition-parity-sample-sha256",
"notes": [
"tracked as JSON save-slice document rather than raw .smp",
"keeps the broader all-factory-production family parity-only until a stronger runtime landing surface is grounded"
]
},
"save_slice": {
"file_extension_hint": "gms",
"container_profile_family": "rt3-classic-save-container-v1",
"mechanism_family": "classic-save-rehydrate-v1",
"mechanism_confidence": "grounded",
"trailer_family": null,
"bridge_family": null,
"profile": null,
"candidate_availability_table": null,
"named_locomotive_availability_table": null,
"special_conditions_table": null,
"event_runtime_collection": {
"source_kind": "packed-event-runtime-collection",
"mechanism_family": "classic-save-rehydrate-v1",
"mechanism_confidence": "grounded",
"container_profile_family": "rt3-classic-save-container-v1",
"metadata_tag_offset": 31232,
"records_tag_offset": 31488,
"close_tag_offset": 31872,
"packed_state_version": 1001,
"packed_state_version_hex": "0x000003e9",
"live_id_bound": 33,
"live_record_count": 1,
"live_entry_ids": [33],
"decoded_record_count": 1,
"imported_runtime_record_count": 0,
"records": [
{
"record_index": 0,
"live_entry_id": 33,
"payload_offset": 31520,
"payload_len": 152,
"decode_status": "parity_only",
"payload_family": "real_packed_v1",
"trigger_kind": 7,
"one_shot": false,
"compact_control": {
"mode_byte_0x7ef": 7,
"primary_selector_0x7f0": 0,
"grouped_mode_0x7f4": 2,
"one_shot_header_0x7f5": 0,
"modifier_flag_0x7f9": 0,
"modifier_flag_0x7fa": 0,
"grouped_target_scope_ordinals_0x7fb": [0, 0, 0, 0],
"grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0],
"summary_toggle_0x800": 1,
"grouped_territory_selectors_0x80f": [-1, -1, -1, -1]
},
"text_bands": [],
"standalone_condition_row_count": 1,
"standalone_condition_rows": [
{
"row_index": 0,
"raw_condition_id": 2419,
"subtype": 4,
"flag_bytes": [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"candidate_name": null,
"comparator": null,
"metric": "All Factory Production",
"semantic_family": "world_scalar_threshold",
"semantic_preview": null,
"requires_candidate_name_binding": false,
"notes": [
"checked-in RT3.lng label is known, but this world-scalar condition family is not yet lowered"
]
}
],
"negative_sentinel_scope": null,
"grouped_effect_row_counts": [1, 0, 0, 0],
"grouped_effect_rows": [
{
"group_index": 0,
"row_index": 0,
"descriptor_id": 110,
"descriptor_label": "Disable Stock Buying and Selling",
"target_mask_bits": 8,
"parameter_family": "world_flag_toggle",
"opcode": 0,
"raw_scalar_value": 1,
"value_byte_0x09": 0,
"value_dword_0x0d": 0,
"value_byte_0x11": 0,
"value_byte_0x12": 0,
"value_word_0x14": 0,
"value_word_0x16": 0,
"row_shape": "bool_toggle",
"semantic_family": "bool_toggle",
"semantic_preview": "Set Disable Stock Buying and Selling to TRUE",
"recovered_locomotive_id": null,
"locomotive_name": null,
"notes": []
}
],
"decoded_conditions": [],
"decoded_actions": [
{
"kind": "set_world_flag",
"key": "world.disable_stock_buying_and_selling",
"value": true
}
],
"executable_import_ready": false,
"notes": [
"unmapped world-scalar condition parity sample"
]
}
]
},
"notes": [
"world-scalar condition parity sample"
]
}
}

View file

@ -0,0 +1,102 @@
{
"format_version": 1,
"fixture_id": "packed-event-world-scalar-condition-save-slice-fixture",
"source": {
"kind": "captured-runtime",
"description": "Fixture proving grounded world-scalar ordinary conditions gate an imported whole-game effect."
},
"state_save_slice_path": "packed-event-world-scalar-condition-save-slice.json",
"commands": [
{
"kind": "service_trigger_kind",
"trigger_kind": 6
},
{
"kind": "service_trigger_kind",
"trigger_kind": 7
}
],
"expected_summary": {
"packed_event_collection_present": true,
"packed_event_record_count": 2,
"packed_event_decoded_record_count": 2,
"packed_event_imported_runtime_record_count": 2,
"event_runtime_record_count": 2,
"named_locomotive_availability_count": 1,
"zero_named_locomotive_availability_count": 0,
"named_locomotive_cost_count": 1,
"cargo_production_override_count": 1,
"world_restore_limited_track_building_amount": 18,
"world_restore_territory_access_cost": 750000,
"world_flag_count": 8,
"total_event_record_service_count": 2,
"total_trigger_dispatch_count": 2
},
"expected_state_fragment": {
"world_flags": {
"world.disable_stock_buying_and_selling": true
},
"world_restore": {
"limited_track_building_amount": 18,
"territory_access_cost": 750000
},
"named_locomotive_availability": {
"Big Boy": 42
},
"named_locomotive_cost": {
"Locomotive 1": 250000
},
"cargo_production_overrides": {
"1": 125
},
"packed_event_collection": {
"records": [
{
"import_outcome": "imported"
},
{
"import_outcome": "imported",
"decoded_conditions": [
{
"kind": "named_locomotive_availability_threshold",
"name": "Big Boy",
"comparator": "eq",
"value": 42
},
{
"kind": "named_locomotive_cost_threshold",
"name": "Locomotive 1",
"comparator": "eq",
"value": 250000
},
{
"kind": "cargo_production_total_threshold",
"comparator": "eq",
"value": 125
},
{
"kind": "limited_track_building_amount_threshold",
"comparator": "eq",
"value": 18
},
{
"kind": "territory_access_cost_threshold",
"comparator": "eq",
"value": 750000
}
]
}
]
},
"event_runtime_records": [
{
"record_id": 41,
"service_count": 1
},
{
"record_id": 45,
"service_count": 1
}
]
}
}

View file

@ -0,0 +1,386 @@
{
"format_version": 1,
"save_slice_id": "packed-event-world-scalar-condition-save-slice",
"source": {
"description": "Tracked save-slice document proving grounded world-scalar ordinary conditions gate a whole-game effect.",
"original_save_filename": "captured-world-scalar-condition.gms",
"original_save_sha256": "world-scalar-condition-sample-sha256",
"notes": [
"tracked as JSON save-slice document rather than raw .smp",
"uses checked-in RT3.lng condition ids for named locomotive availability, named locomotive cost, aggregate cargo production, limited track building amount, and access rights cost"
]
},
"save_slice": {
"file_extension_hint": "gms",
"container_profile_family": "rt3-classic-save-container-v1",
"mechanism_family": "classic-save-rehydrate-v1",
"mechanism_confidence": "grounded",
"trailer_family": null,
"bridge_family": null,
"profile": null,
"candidate_availability_table": null,
"named_locomotive_availability_table": null,
"special_conditions_table": null,
"event_runtime_collection": {
"source_kind": "packed-event-runtime-collection",
"mechanism_family": "classic-save-rehydrate-v1",
"mechanism_confidence": "grounded",
"container_profile_family": "rt3-classic-save-container-v1",
"metadata_tag_offset": 31488,
"records_tag_offset": 31744,
"close_tag_offset": 32768,
"packed_state_version": 1001,
"packed_state_version_hex": "0x000003e9",
"live_id_bound": 45,
"live_record_count": 2,
"live_entry_ids": [41, 45],
"decoded_record_count": 2,
"imported_runtime_record_count": 2,
"records": [
{
"record_index": 0,
"live_entry_id": 41,
"payload_offset": 31808,
"payload_len": 272,
"decode_status": "parity_only",
"payload_family": "real_packed_v1",
"trigger_kind": 6,
"one_shot": false,
"compact_control": {
"mode_byte_0x7ef": 6,
"primary_selector_0x7f0": 0,
"grouped_mode_0x7f4": 2,
"one_shot_header_0x7f5": 0,
"modifier_flag_0x7f9": 0,
"modifier_flag_0x7fa": 0,
"grouped_target_scope_ordinals_0x7fb": [0, 0, 0, 0],
"grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0],
"summary_toggle_0x800": 1,
"grouped_territory_selectors_0x80f": [-1, -1, -1, -1]
},
"text_bands": [],
"standalone_condition_row_count": 0,
"standalone_condition_rows": [],
"negative_sentinel_scope": null,
"grouped_effect_row_counts": [5, 0, 0, 0],
"grouped_effect_rows": [
{
"group_index": 0,
"row_index": 0,
"descriptor_id": 250,
"descriptor_label": "Unknown Loco Available",
"target_mask_bits": 8,
"parameter_family": "locomotive_availability_scalar",
"opcode": 3,
"raw_scalar_value": 42,
"value_byte_0x09": 0,
"value_dword_0x0d": 0,
"value_byte_0x11": 0,
"value_byte_0x12": 0,
"value_word_0x14": 0,
"value_word_0x16": 0,
"row_shape": "scalar_assignment",
"semantic_family": "scalar_assignment",
"semantic_preview": "Set Unknown Loco Available to 42",
"recovered_locomotive_id": 10,
"locomotive_name": null,
"notes": [
"locomotive availability descriptor maps to live locomotive id 10"
]
},
{
"group_index": 0,
"row_index": 1,
"descriptor_id": 352,
"descriptor_label": "Locomotive 1 Cost",
"target_mask_bits": 8,
"parameter_family": "locomotive_cost_scalar",
"opcode": 3,
"raw_scalar_value": 250000,
"value_byte_0x09": 0,
"value_dword_0x0d": 0,
"value_byte_0x11": 0,
"value_byte_0x12": 0,
"value_word_0x14": 0,
"value_word_0x16": 0,
"row_shape": "scalar_assignment",
"semantic_family": "scalar_assignment",
"semantic_preview": "Set Locomotive 1 Cost to 250000",
"recovered_locomotive_id": 1,
"locomotive_name": null,
"notes": [
"locomotive cost descriptor maps to live locomotive id 1"
]
},
{
"group_index": 0,
"row_index": 2,
"descriptor_id": 230,
"descriptor_label": "Cargo Production Slot 1",
"target_mask_bits": 8,
"parameter_family": "cargo_production_scalar",
"opcode": 3,
"raw_scalar_value": 125,
"value_byte_0x09": 0,
"value_dword_0x0d": 0,
"value_byte_0x11": 0,
"value_byte_0x12": 0,
"value_word_0x14": 0,
"value_word_0x16": 0,
"row_shape": "scalar_assignment",
"semantic_family": "scalar_assignment",
"semantic_preview": "Set Cargo Production Slot 1 to 125",
"recovered_locomotive_id": null,
"locomotive_name": null,
"notes": []
},
{
"group_index": 0,
"row_index": 3,
"descriptor_id": 122,
"descriptor_label": "Limited Track Building Amount",
"target_mask_bits": 8,
"parameter_family": "world_track_build_limit_scalar",
"opcode": 3,
"raw_scalar_value": 18,
"value_byte_0x09": 0,
"value_dword_0x0d": 0,
"value_byte_0x11": 0,
"value_byte_0x12": 0,
"value_word_0x14": 0,
"value_word_0x16": 0,
"row_shape": "scalar_assignment",
"semantic_family": "scalar_assignment",
"semantic_preview": "Set Limited Track Building Amount to 18",
"recovered_locomotive_id": null,
"locomotive_name": null,
"notes": []
},
{
"group_index": 0,
"row_index": 4,
"descriptor_id": 453,
"descriptor_label": "Territory Access Cost",
"target_mask_bits": 8,
"parameter_family": "territory_access_cost_scalar",
"opcode": 3,
"raw_scalar_value": 750000,
"value_byte_0x09": 0,
"value_dword_0x0d": 0,
"value_byte_0x11": 0,
"value_byte_0x12": 0,
"value_word_0x14": 0,
"value_word_0x16": 0,
"row_shape": "scalar_assignment",
"semantic_family": "scalar_assignment",
"semantic_preview": "Set Territory Access Cost to 750000",
"recovered_locomotive_id": null,
"locomotive_name": null,
"notes": []
}
],
"decoded_conditions": [],
"decoded_actions": [
{
"kind": "set_named_locomotive_availability_value",
"name": "Big Boy",
"value": 42
},
{
"kind": "set_named_locomotive_cost",
"name": "Locomotive 1",
"value": 250000
},
{
"kind": "set_cargo_production_slot",
"slot": 1,
"value": 125
},
{
"kind": "set_limited_track_building_amount",
"value": 18
},
{
"kind": "set_territory_access_cost",
"value": 750000
}
],
"executable_import_ready": true,
"notes": [
"world-scalar setup record"
]
},
{
"record_index": 1,
"live_entry_id": 45,
"payload_offset": 32128,
"payload_len": 224,
"decode_status": "parity_only",
"payload_family": "real_packed_v1",
"trigger_kind": 7,
"one_shot": false,
"compact_control": {
"mode_byte_0x7ef": 7,
"primary_selector_0x7f0": 0,
"grouped_mode_0x7f4": 2,
"one_shot_header_0x7f5": 0,
"modifier_flag_0x7f9": 0,
"modifier_flag_0x7fa": 0,
"grouped_target_scope_ordinals_0x7fb": [0, 0, 0, 0],
"grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0],
"summary_toggle_0x800": 1,
"grouped_territory_selectors_0x80f": [-1, -1, -1, -1]
},
"text_bands": [],
"standalone_condition_row_count": 5,
"standalone_condition_rows": [
{
"row_index": 0,
"raw_condition_id": 2422,
"subtype": 4,
"flag_bytes": [42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"candidate_name": "Big Boy",
"comparator": "eq",
"metric": "Named Locomotive Availability: Big Boy",
"semantic_family": "world_scalar_threshold",
"semantic_preview": "Test Named Locomotive Availability: Big Boy == 42",
"requires_candidate_name_binding": false,
"notes": [
"checked-in world-scalar condition metadata sample"
]
},
{
"row_index": 1,
"raw_condition_id": 2423,
"subtype": 4,
"flag_bytes": [144, 208, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"candidate_name": "Locomotive 1",
"comparator": "eq",
"metric": "Named Locomotive Cost: Locomotive 1",
"semantic_family": "world_scalar_threshold",
"semantic_preview": "Test Named Locomotive Cost: Locomotive 1 == 250000",
"requires_candidate_name_binding": false,
"notes": [
"checked-in world-scalar condition metadata sample"
]
},
{
"row_index": 2,
"raw_condition_id": 2418,
"subtype": 4,
"flag_bytes": [125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"candidate_name": null,
"comparator": "eq",
"metric": "Cargo Production Total",
"semantic_family": "world_scalar_threshold",
"semantic_preview": "Test Cargo Production Total == 125",
"requires_candidate_name_binding": false,
"notes": [
"checked-in world-scalar condition metadata sample"
]
},
{
"row_index": 3,
"raw_condition_id": 2547,
"subtype": 4,
"flag_bytes": [18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"candidate_name": null,
"comparator": "eq",
"metric": "Limited Track Building Amount",
"semantic_family": "world_scalar_threshold",
"semantic_preview": "Test Limited Track Building Amount == 18",
"requires_candidate_name_binding": false,
"notes": [
"checked-in world-scalar condition metadata sample"
]
},
{
"row_index": 4,
"raw_condition_id": 1516,
"subtype": 4,
"flag_bytes": [176, 113, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"candidate_name": null,
"comparator": "eq",
"metric": "Territory Access Cost",
"semantic_family": "world_scalar_threshold",
"semantic_preview": "Test Territory Access Cost == 750000",
"requires_candidate_name_binding": false,
"notes": [
"checked-in world-scalar condition metadata sample"
]
}
],
"negative_sentinel_scope": null,
"grouped_effect_row_counts": [1, 0, 0, 0],
"grouped_effect_rows": [
{
"group_index": 0,
"row_index": 0,
"descriptor_id": 110,
"descriptor_label": "Disable Stock Buying and Selling",
"target_mask_bits": 8,
"parameter_family": "world_flag_toggle",
"opcode": 0,
"raw_scalar_value": 1,
"value_byte_0x09": 0,
"value_dword_0x0d": 0,
"value_byte_0x11": 0,
"value_byte_0x12": 0,
"value_word_0x14": 0,
"value_word_0x16": 0,
"row_shape": "bool_toggle",
"semantic_family": "bool_toggle",
"semantic_preview": "Set Disable Stock Buying and Selling to TRUE",
"recovered_locomotive_id": null,
"locomotive_name": null,
"notes": []
}
],
"decoded_conditions": [
{
"kind": "named_locomotive_availability_threshold",
"name": "Big Boy",
"comparator": "eq",
"value": 42
},
{
"kind": "named_locomotive_cost_threshold",
"name": "Locomotive 1",
"comparator": "eq",
"value": 250000
},
{
"kind": "cargo_production_total_threshold",
"comparator": "eq",
"value": 125
},
{
"kind": "limited_track_building_amount_threshold",
"comparator": "eq",
"value": 18
},
{
"kind": "territory_access_cost_threshold",
"comparator": "eq",
"value": 750000
}
],
"decoded_actions": [
{
"kind": "set_world_flag",
"key": "world.disable_stock_buying_and_selling",
"value": true
}
],
"executable_import_ready": true,
"notes": [
"world-scalar conditions gate a whole-game effect"
]
}
]
},
"notes": [
"world-scalar condition executable sample"
]
}
}