From b89463d2279172fd1895f6b9b32e2faa30f4704a Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Thu, 16 Apr 2026 08:28:50 -0700 Subject: [PATCH] Broaden whole-game packed event coverage --- README.md | 18 +- crates/rrt-runtime/src/import.rs | 395 +++++++++++++++++- crates/rrt-runtime/src/runtime.rs | 11 + crates/rrt-runtime/src/smp.rs | 345 ++++++++++++++- crates/rrt-runtime/src/step.rs | 14 + docs/README.md | 9 + docs/runtime-rehost-plan.md | 17 +- ...-flag-condition-overlay-base-snapshot.json | 30 ++ ...-world-flag-condition-overlay-fixture.json | 56 +++ ...ed-event-world-flag-condition-overlay.json | 9 + ...event-world-flag-condition-save-slice.json | 179 ++++++++ ...oggle-construction-save-slice-fixture.json | 32 ++ ...-world-toggle-construction-save-slice.json | 159 +++++++ ...rld-toggle-finance-save-slice-fixture.json | 32 ++ ...event-world-toggle-finance-save-slice.json | 159 +++++++ ...-toggle-governance-save-slice-fixture.json | 32 ++ ...nt-world-toggle-governance-save-slice.json | 159 +++++++ ...-world-toggle-late-save-slice-fixture.json | 34 ++ ...ed-event-world-toggle-late-save-slice.json | 211 ++++++++++ 19 files changed, 1874 insertions(+), 27 deletions(-) create mode 100644 fixtures/runtime/packed-event-world-flag-condition-overlay-base-snapshot.json create mode 100644 fixtures/runtime/packed-event-world-flag-condition-overlay-fixture.json create mode 100644 fixtures/runtime/packed-event-world-flag-condition-overlay.json create mode 100644 fixtures/runtime/packed-event-world-flag-condition-save-slice.json create mode 100644 fixtures/runtime/packed-event-world-toggle-construction-save-slice-fixture.json create mode 100644 fixtures/runtime/packed-event-world-toggle-construction-save-slice.json create mode 100644 fixtures/runtime/packed-event-world-toggle-finance-save-slice-fixture.json create mode 100644 fixtures/runtime/packed-event-world-toggle-finance-save-slice.json create mode 100644 fixtures/runtime/packed-event-world-toggle-governance-save-slice-fixture.json create mode 100644 fixtures/runtime/packed-event-world-toggle-governance-save-slice.json create mode 100644 fixtures/runtime/packed-event-world-toggle-late-save-slice-fixture.json create mode 100644 fixtures/runtime/packed-event-world-toggle-late-save-slice.json diff --git a/README.md b/README.md index 948746e..7173b15 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,19 @@ template plus candidate-name side strings all lower into the runtime condition m whole-game descriptor metadata now drives the first real world-side effect batch too: special-condition and candidate-availability setters import natively, and descriptor `110` `Disable Stock Buying and Selling` now lowers into the keyed runtime flag -`world.disable_stock_buying_and_selling`. Explicit unmapped world-condition and world-descriptor -frontier buckets still remain where current checked-in metadata stops. Shell purchase-flow and -selected-profile parity remain out of scope. Mixed supported/unsupported real rows still stay -parity-only. The PE32 hook remains useful as capture and integration tooling, but it is no longer -the main execution milestone. +`world.disable_stock_buying_and_selling`. The recovered whole-game toggle batch is broader now +too: descriptors `111..138`, excluding the scalar `Limited Track Building Amount` slot, also lower +into keyed `world_flags` for finance/trading, construction, and governance restrictions. Explicit +the late recovered special-condition toggles now execute too where current evidence is equally +strong: `Use Bio-Accelerator Cars`, `Disable Cargo Economy`, `Disable Train Crashes`, `Disable +Train Crashes AND Breakdowns`, and `AI Ignore Territories At Startup`. Whole-game condition decode +is broader now too: checked-in world-flag condition ids can lower into `world_flag_equals` gates +for boolean equality/inequality forms, so real packed records can gate whole-game effects on +existing `world_flags` without fixture-authored placeholder ids. Explicit unmapped world-condition +and world-descriptor frontier buckets still remain where current checked-in metadata stops. Shell +purchase-flow and selected-profile parity remain out of scope. Mixed supported/unsupported real +rows still stay parity-only. The PE32 hook remains useful as capture and integration tooling, but +it is no longer the main execution milestone. ## Project Docs diff --git a/crates/rrt-runtime/src/import.rs b/crates/rrt-runtime/src/import.rs index 0d31d32..3fb0132 100644 --- a/crates/rrt-runtime/src/import.rs +++ b/crates/rrt-runtime/src/import.rs @@ -1240,6 +1240,10 @@ fn lower_condition_targets_in_condition( value: *value, } } + RuntimeCondition::WorldFlagEquals { key, value } => RuntimeCondition::WorldFlagEquals { + key: key.clone(), + value: *value, + }, }) } @@ -1319,7 +1323,8 @@ fn condition_uses_condition_true_company(condition: &RuntimeCondition) -> bool { RuntimeCondition::TerritoryNumericThreshold { .. } | RuntimeCondition::SpecialConditionThreshold { .. } | RuntimeCondition::CandidateAvailabilityThreshold { .. } - | RuntimeCondition::EconomicStatusCodeThreshold { .. } => false, + | RuntimeCondition::EconomicStatusCodeThreshold { .. } + | RuntimeCondition::WorldFlagEquals { .. } => false, } } @@ -1899,6 +1904,7 @@ fn runtime_condition_is_world_state(condition: &RuntimeCondition) -> bool { RuntimeCondition::SpecialConditionThreshold { .. } | RuntimeCondition::CandidateAvailabilityThreshold { .. } | RuntimeCondition::EconomicStatusCodeThreshold { .. } + | RuntimeCondition::WorldFlagEquals { .. } ) } @@ -1980,7 +1986,8 @@ fn runtime_condition_company_target_import_blocker( .or_else(|| territory_target_import_blocker(territory, company_context)), RuntimeCondition::SpecialConditionThreshold { .. } | RuntimeCondition::CandidateAvailabilityThreshold { .. } - | RuntimeCondition::EconomicStatusCodeThreshold { .. } => None, + | RuntimeCondition::EconomicStatusCodeThreshold { .. } + | RuntimeCondition::WorldFlagEquals { .. } => None, } } @@ -2844,12 +2851,16 @@ mod tests { } } - fn real_world_flag_row(enabled: bool) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary { + fn real_world_flag_row( + descriptor_id: u32, + label: &str, + enabled: bool, + ) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary { crate::SmpLoadedPackedEventGroupedEffectRowSummary { group_index: 0, row_index: 0, - descriptor_id: 110, - descriptor_label: Some("Disable Stock Buying and Selling".to_string()), + descriptor_id, + descriptor_label: Some(label.to_string()), target_mask_bits: Some(0x08), parameter_family: Some("world_flag_toggle".to_string()), opcode: 0, @@ -2863,7 +2874,7 @@ mod tests { row_shape: "bool_toggle".to_string(), semantic_family: Some("bool_toggle".to_string()), semantic_preview: Some(format!( - "Set Disable Stock Buying and Selling to {}", + "Set {label} to {}", if enabled { "TRUE" } else { "FALSE" } )), locomotive_name: None, @@ -5658,7 +5669,11 @@ mod tests { standalone_condition_rows: vec![], negative_sentinel_scope: None, grouped_effect_row_counts: vec![1, 0, 0, 0], - grouped_effect_rows: vec![real_world_flag_row(true)], + grouped_effect_rows: vec![real_world_flag_row( + 110, + "Disable Stock Buying and Selling", + true, + )], decoded_conditions: Vec::new(), decoded_actions: vec![RuntimeEffect::SetWorldFlag { key: "world.disable_stock_buying_and_selling".to_string(), @@ -5751,7 +5766,11 @@ mod tests { standalone_condition_rows: vec![], negative_sentinel_scope: None, grouped_effect_row_counts: vec![1, 0, 0, 0], - grouped_effect_rows: vec![real_world_flag_row(false)], + grouped_effect_rows: vec![real_world_flag_row( + 110, + "Disable Stock Buying and Selling", + false, + )], decoded_conditions: Vec::new(), decoded_actions: vec![RuntimeEffect::SetWorldFlag { key: "world.disable_stock_buying_and_selling".to_string(), @@ -5790,6 +5809,366 @@ mod tests { ); } + #[test] + fn overlays_real_world_flag_condition_into_executable_runtime_record() { + let mut base_state = state(); + base_state + .world_flags + .insert("world.disable_stock_buying_and_selling".to_string(), true); + 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, + 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: 0x7600, + packed_state_version: 0x3e9, + packed_state_version_hex: "0x000003e9".to_string(), + live_id_bound: 27, + live_record_count: 1, + live_entry_ids: vec![27], + decoded_record_count: 1, + imported_runtime_record_count: 1, + records: vec![crate::SmpLoadedPackedEventRecordSummary { + record_index: 0, + live_entry_id: 27, + payload_offset: Some(0x7200), + payload_len: Some(152), + 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: 1, + standalone_condition_rows: vec![ + crate::SmpLoadedPackedEventConditionRowSummary { + row_index: 0, + raw_condition_id: 2535, + subtype: 0, + flag_bytes: vec![ + 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: None, + comparator: Some("eq".to_string()), + metric: Some( + "World Flag: Disable Stock Buying and Selling".to_string(), + ), + semantic_family: Some("world_flag_equals".to_string()), + semantic_preview: Some( + "Test Disable Stock Buying and Selling == TRUE".to_string(), + ), + requires_candidate_name_binding: false, + notes: vec![ + "checked-in whole-game condition metadata sample".to_string(), + ], + }, + ], + negative_sentinel_scope: None, + grouped_effect_row_counts: vec![1, 0, 0, 0], + grouped_effect_rows: vec![crate::SmpLoadedPackedEventGroupedEffectRowSummary { + group_index: 0, + row_index: 0, + descriptor_id: 109, + descriptor_label: Some("Turbo Diesel Availability".to_string()), + target_mask_bits: Some(0x08), + parameter_family: Some("candidate_availability_scalar".to_string()), + opcode: 3, + 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: "scalar_assignment".to_string(), + semantic_family: Some("scalar_assignment".to_string()), + semantic_preview: Some("Set Turbo Diesel Availability to 1".to_string()), + locomotive_name: None, + notes: vec!["checked-in whole-game grouped-effect sample".to_string()], + }], + decoded_conditions: vec![RuntimeCondition::WorldFlagEquals { + key: "world.disable_stock_buying_and_selling".to_string(), + value: true, + }], + decoded_actions: vec![RuntimeEffect::SetCandidateAvailability { + name: "Turbo Diesel".to_string(), + value: 1, + }], + executable_import_ready: true, + notes: vec!["world-flag condition gates a world-side effect".to_string()], + }], + }), + notes: vec![], + }; + + let mut import = project_save_slice_overlay_to_runtime_state_import( + &base_state, + &save_slice, + "real-world-flag-condition-overlay", + None, + ) + .expect("overlay import should project"); + + crate::execute_step_command( + &mut import.state, + &crate::StepCommand::ServiceTriggerKind { trigger_kind: 7 }, + ) + .expect("trigger service should execute"); + assert_eq!( + import.state.candidate_availability.get("Turbo Diesel"), + Some(&1) + ); + } + + #[test] + fn overlays_recovered_world_toggle_batch_into_executable_runtime_record() { + let base_state = 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, + 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: 0x7600, + packed_state_version: 0x3e9, + packed_state_version_hex: "0x000003e9".to_string(), + live_id_bound: 25, + live_record_count: 1, + live_entry_ids: vec![25], + decoded_record_count: 1, + imported_runtime_record_count: 1, + records: vec![crate::SmpLoadedPackedEventRecordSummary { + record_index: 0, + live_entry_id: 25, + payload_offset: Some(0x7200), + payload_len: Some(168), + 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: 0, + standalone_condition_rows: vec![], + negative_sentinel_scope: None, + grouped_effect_row_counts: vec![3, 0, 0, 0], + grouped_effect_rows: vec![ + real_world_flag_row(111, "Disable Margin Buying/Short Selling Stock", true), + real_world_flag_row(120, "Disable All Track Building", true), + real_world_flag_row(131, "Disable Starting Any Companies", false), + ], + decoded_conditions: Vec::new(), + decoded_actions: vec![ + RuntimeEffect::SetWorldFlag { + key: "world.disable_margin_buying_short_selling_stock".to_string(), + value: true, + }, + RuntimeEffect::SetWorldFlag { + key: "world.disable_all_track_building".to_string(), + value: true, + }, + RuntimeEffect::SetWorldFlag { + key: "world.disable_starting_any_companies".to_string(), + value: false, + }, + ], + executable_import_ready: true, + notes: vec!["decoded from grounded real 0x4e9a row framing".to_string()], + }], + }), + notes: vec![], + }; + + let mut import = project_save_slice_overlay_to_runtime_state_import( + &base_state, + &save_slice, + "real-world-toggle-batch-overlay", + None, + ) + .expect("overlay import should project"); + + crate::execute_step_command( + &mut import.state, + &crate::StepCommand::ServiceTriggerKind { trigger_kind: 7 }, + ) + .expect("trigger service should execute"); + assert_eq!( + import + .state + .world_flags + .get("world.disable_margin_buying_short_selling_stock"), + Some(&true) + ); + assert_eq!( + import + .state + .world_flags + .get("world.disable_all_track_building"), + Some(&true) + ); + assert_eq!( + import + .state + .world_flags + .get("world.disable_starting_any_companies"), + Some(&false) + ); + } + + #[test] + fn overlays_recovered_late_world_toggle_batch_into_executable_runtime_record() { + let base_state = 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, + 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: 0x7600, + packed_state_version: 0x3e9, + packed_state_version_hex: "0x000003e9".to_string(), + live_id_bound: 26, + live_record_count: 1, + live_entry_ids: vec![26], + decoded_record_count: 1, + imported_runtime_record_count: 1, + records: vec![crate::SmpLoadedPackedEventRecordSummary { + record_index: 0, + live_entry_id: 26, + payload_offset: Some(0x7200), + 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: 0, + standalone_condition_rows: vec![], + negative_sentinel_scope: None, + grouped_effect_row_counts: vec![5, 0, 0, 0], + grouped_effect_rows: vec![ + real_world_flag_row(139, "Use Bio-Accelerator Cars", true), + real_world_flag_row(140, "Disable Cargo Economy", true), + real_world_flag_row(142, "Disable Train Crashes", false), + real_world_flag_row(143, "Disable Train Crashes AND Breakdowns", true), + real_world_flag_row(144, "AI Ignore Territories At Startup", true), + ], + decoded_conditions: Vec::new(), + decoded_actions: vec![ + RuntimeEffect::SetWorldFlag { + key: "world.use_bio_accelerator_cars".to_string(), + value: true, + }, + RuntimeEffect::SetWorldFlag { + key: "world.disable_cargo_economy".to_string(), + value: true, + }, + RuntimeEffect::SetWorldFlag { + key: "world.disable_train_crashes".to_string(), + value: false, + }, + RuntimeEffect::SetWorldFlag { + key: "world.disable_train_crashes_and_breakdowns".to_string(), + value: true, + }, + RuntimeEffect::SetWorldFlag { + key: "world.ai_ignore_territories_at_startup".to_string(), + value: true, + }, + ], + executable_import_ready: true, + notes: vec!["decoded from grounded real 0x4e9a row framing".to_string()], + }], + }), + notes: vec![], + }; + + let mut import = project_save_slice_overlay_to_runtime_state_import( + &base_state, + &save_slice, + "real-late-world-toggle-batch-overlay", + None, + ) + .expect("overlay import should project"); + + crate::execute_step_command( + &mut import.state, + &crate::StepCommand::ServiceTriggerKind { trigger_kind: 7 }, + ) + .expect("trigger service should execute"); + assert_eq!( + import + .state + .world_flags + .get("world.use_bio_accelerator_cars"), + Some(&true) + ); + assert_eq!( + import.state.world_flags.get("world.disable_cargo_economy"), + Some(&true) + ); + assert_eq!( + import.state.world_flags.get("world.disable_train_crashes"), + Some(&false) + ); + assert_eq!( + import + .state + .world_flags + .get("world.disable_train_crashes_and_breakdowns"), + Some(&true) + ); + assert_eq!( + import + .state + .world_flags + .get("world.ai_ignore_territories_at_startup"), + Some(&true) + ); + } + #[test] fn overlays_real_confiscate_all_descriptor_into_executable_runtime_record() { let base_state = RuntimeState { diff --git a/crates/rrt-runtime/src/runtime.rs b/crates/rrt-runtime/src/runtime.rs index d8d398e..69d5cc0 100644 --- a/crates/rrt-runtime/src/runtime.rs +++ b/crates/rrt-runtime/src/runtime.rs @@ -242,6 +242,10 @@ pub enum RuntimeCondition { comparator: RuntimeConditionComparator, value: i64, }, + WorldFlagEquals { + key: String, + value: bool, + }, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -1268,6 +1272,13 @@ fn validate_runtime_condition( } } RuntimeCondition::EconomicStatusCodeThreshold { .. } => Ok(()), + RuntimeCondition::WorldFlagEquals { key, .. } => { + if key.trim().is_empty() { + Err("key must not be empty".to_string()) + } else { + Ok(()) + } + } } } diff --git a/crates/rrt-runtime/src/smp.rs b/crates/rrt-runtime/src/smp.rs index a0b3ec6..1eb84e4 100644 --- a/crates/rrt-runtime/src/smp.rs +++ b/crates/rrt-runtime/src/smp.rs @@ -239,6 +239,7 @@ enum RealWorldConditionKind { SpecialCondition { label: &'static str }, CandidateAvailability, EconomicStatus, + WorldFlag { key: &'static str }, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -2499,14 +2500,26 @@ fn real_ordinary_condition_metadata( .find(|metadata| metadata.raw_condition_id == raw_condition_id) .or_else(|| { known_special_condition_definition_for_label_id(raw_condition_id as u32).map( - |definition| RealOrdinaryConditionMetadata { - raw_condition_id, - label: definition.label, - kind: RealOrdinaryConditionKind::WorldState( - RealWorldConditionKind::SpecialCondition { - label: definition.label, - }, - ), + |definition| { + let kind = if let Some(world_toggle) = + real_grouped_effect_descriptor_metadata(110 + definition.slot_index as u32) + .filter(|metadata| metadata.parameter_family == "world_flag_toggle") + { + RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { + key: world_toggle.runtime_key.unwrap_or(world_toggle.label), + }) + } else { + RealOrdinaryConditionKind::WorldState( + RealWorldConditionKind::SpecialCondition { + label: definition.label, + }, + ) + }; + RealOrdinaryConditionMetadata { + raw_condition_id, + label: definition.label, + kind, + } }, ) }) @@ -2532,6 +2545,9 @@ fn real_ordinary_condition_metric_label( RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => { "Economic Status".to_string() } + RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { .. }) => { + format!("World Flag: {}", metadata.label) + } } } @@ -2540,6 +2556,9 @@ fn real_ordinary_condition_semantic_family( ) -> &'static str { match metadata.kind { RealOrdinaryConditionKind::Numeric(_) => "numeric_threshold", + RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { .. }) => { + "world_flag_equals" + } RealOrdinaryConditionKind::WorldState(_) => "world_state_threshold", } } @@ -2737,9 +2756,28 @@ fn decode_real_condition_row( RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => { Some(RuntimeCondition::EconomicStatusCodeThreshold { comparator, value }) } + RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { key }) => { + decode_world_flag_condition(comparator, value, key) + } } } +fn decode_world_flag_condition( + comparator: RuntimeConditionComparator, + value: i64, + key: &'static str, +) -> Option { + let bool_value = match (comparator, value) { + (RuntimeConditionComparator::Eq, 0) | (RuntimeConditionComparator::Ne, 1) => false, + (RuntimeConditionComparator::Eq, 1) | (RuntimeConditionComparator::Ne, 0) => true, + _ => return None, + }; + Some(RuntimeCondition::WorldFlagEquals { + key: key.to_string(), + value: bool_value, + }) +} + fn real_grouped_effect_descriptor_metadata( descriptor_id: u32, ) -> Option { @@ -2747,6 +2785,28 @@ fn real_grouped_effect_descriptor_metadata( .iter() .copied() .find(|metadata| metadata.descriptor_id == descriptor_id) + .or_else(|| special_condition_world_toggle_descriptor_metadata(descriptor_id)) +} + +fn special_condition_world_toggle_descriptor_metadata( + descriptor_id: u32, +) -> Option { + let slot_index = descriptor_id.checked_sub(110)? as usize; + if !(1..=34).contains(&slot_index) || matches!(slot_index, 12 | 31) { + return None; + } + let definition = KNOWN_SPECIAL_CONDITION_DEFINITIONS.get(slot_index)?; + if definition.hidden { + return None; + } + Some(RealGroupedEffectDescriptorMetadata { + descriptor_id, + label: definition.label, + target_mask_bits: 0x08, + parameter_family: "world_flag_toggle", + runtime_key: None, + executable_in_runtime: true, + }) } fn classify_real_grouped_effect_semantic_family( @@ -2830,7 +2890,32 @@ fn runtime_candidate_availability_name(label: &str) -> String { fn runtime_world_flag_key( descriptor_metadata: RealGroupedEffectDescriptorMetadata, ) -> Option { - descriptor_metadata.runtime_key.map(str::to_string) + descriptor_metadata + .runtime_key + .map(str::to_string) + .or_else(|| { + (descriptor_metadata.parameter_family == "world_flag_toggle") + .then(|| runtime_world_flag_key_from_label(descriptor_metadata.label)) + }) +} + +fn runtime_world_flag_key_from_label(label: &str) -> String { + let mut key = String::with_capacity(label.len() + 6); + key.push_str("world."); + let mut last_was_underscore = false; + for ch in label.chars() { + if ch.is_ascii_alphanumeric() { + key.push(ch.to_ascii_lowercase()); + last_was_underscore = false; + } else if !last_was_underscore { + key.push('_'); + last_was_underscore = true; + } + } + while key.ends_with('_') { + key.pop(); + } + key } fn decode_real_grouped_effect_actions( @@ -2928,7 +3013,7 @@ fn decode_real_grouped_effect_action( } if descriptor_metadata.executable_in_runtime - && descriptor_metadata.descriptor_id == 110 + && descriptor_metadata.parameter_family == "world_flag_toggle" && row.row_shape == "bool_toggle" { return Some(RuntimeEffect::SetWorldFlag { @@ -3232,7 +3317,8 @@ fn runtime_condition_supported_for_save_import(condition: &RuntimeCondition) -> | RuntimeCondition::CompanyTerritoryNumericThreshold { .. } | RuntimeCondition::SpecialConditionThreshold { .. } | RuntimeCondition::CandidateAvailabilityThreshold { .. } - | RuntimeCondition::EconomicStatusCodeThreshold { .. } => true, + | RuntimeCondition::EconomicStatusCodeThreshold { .. } + | RuntimeCondition::WorldFlagEquals { .. } => true, } } @@ -8855,6 +8941,67 @@ mod tests { ); } + #[test] + 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 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("World Flag: Disable Stock Buying and Selling") + ); + assert_eq!( + summary.records[0].standalone_condition_rows[0] + .semantic_family + .as_deref(), + Some("world_flag_equals") + ); + assert_eq!( + summary.records[0].decoded_conditions, + vec![RuntimeCondition::WorldFlagEquals { + key: "world.disable_stock_buying_and_selling".to_string(), + value: true, + }] + ); + } + #[test] fn looks_up_checked_in_world_flag_descriptor_metadata() { let metadata = @@ -8869,6 +9016,34 @@ mod tests { assert!(metadata.executable_in_runtime); } + #[test] + fn looks_up_recovered_world_toggle_descriptor_metadata() { + let metadata = + real_grouped_effect_descriptor_metadata(111).expect("descriptor metadata should exist"); + + assert_eq!(metadata.label, "Disable Margin Buying/Short Selling Stock"); + assert_eq!(metadata.parameter_family, "world_flag_toggle"); + assert_eq!( + runtime_world_flag_key(metadata), + Some("world.disable_margin_buying_short_selling_stock".to_string()) + ); + assert!(metadata.executable_in_runtime); + } + + #[test] + fn looks_up_recovered_late_world_toggle_descriptor_metadata() { + let metadata = + real_grouped_effect_descriptor_metadata(143).expect("descriptor metadata should exist"); + + assert_eq!(metadata.label, "Disable Train Crashes AND Breakdowns"); + assert_eq!(metadata.parameter_family, "world_flag_toggle"); + assert_eq!( + runtime_world_flag_key(metadata), + Some("world.disable_train_crashes_and_breakdowns".to_string()) + ); + assert!(metadata.executable_in_runtime); + } + #[test] fn looks_up_checked_in_deactivate_player_descriptor_metadata() { let metadata = @@ -9027,6 +9202,154 @@ mod tests { assert!(summary.records[0].executable_import_ready); } + #[test] + fn decodes_recovered_world_toggle_descriptor_family() { + let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec { + descriptor_id: 131, + 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, + locomotive_name: None, + }); + let group0_rows = vec![grouped_row]; + 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: [1, 0, 0, 0], + summary_toggle_0x800: 1, + grouped_territory_selectors_0x80f: [-1, -1, -1, -1], + }), + &[], + [&group0_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].grouped_effect_rows[0] + .descriptor_label + .as_deref(), + Some("Disable Starting Any Companies") + ); + assert_eq!( + summary.records[0].grouped_effect_rows[0] + .parameter_family + .as_deref(), + Some("world_flag_toggle") + ); + assert_eq!( + summary.records[0].decoded_actions, + vec![RuntimeEffect::SetWorldFlag { + key: "world.disable_starting_any_companies".to_string(), + value: true, + }] + ); + assert!(summary.records[0].executable_import_ready); + } + + #[test] + fn decodes_recovered_late_world_toggle_descriptor_family() { + let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec { + descriptor_id: 144, + 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, + locomotive_name: None, + }); + let group0_rows = vec![grouped_row]; + 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: [1, 0, 0, 0], + summary_toggle_0x800: 1, + grouped_territory_selectors_0x80f: [-1, -1, -1, -1], + }), + &[], + [&group0_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].grouped_effect_rows[0] + .descriptor_label + .as_deref(), + Some("AI Ignore Territories At Startup") + ); + assert_eq!( + summary.records[0].grouped_effect_rows[0] + .parameter_family + .as_deref(), + Some("world_flag_toggle") + ); + assert_eq!( + summary.records[0].decoded_actions, + vec![RuntimeEffect::SetWorldFlag { + key: "world.ai_ignore_territories_at_startup".to_string(), + value: true, + }] + ); + assert!(summary.records[0].executable_import_ready); + } + #[test] fn decodes_negative_sentinel_scope_modifiers_and_territory_marker() { for (value, expected) in [ diff --git a/crates/rrt-runtime/src/step.rs b/crates/rrt-runtime/src/step.rs index 0e85fd9..440c14c 100644 --- a/crates/rrt-runtime/src/step.rs +++ b/crates/rrt-runtime/src/step.rs @@ -710,6 +710,12 @@ fn evaluate_record_conditions( return Ok(None); } } + RuntimeCondition::WorldFlagEquals { key, value } => { + let actual = state.world_flags.get(key).copied().unwrap_or(false); + if actual != *value { + return Ok(None); + } + } } } @@ -1889,6 +1895,10 @@ mod tests { economic_status_code: Some(3), ..RuntimeWorldRestoreState::default() }, + world_flags: BTreeMap::from([( + String::from("world.disable_stock_buying_and_selling"), + true, + )]), candidate_availability: BTreeMap::from([(String::from("Mogul"), 2)]), special_conditions: BTreeMap::from([(String::from("Use Wartime Cargos"), 1)]), event_runtime_records: vec![ @@ -1915,6 +1925,10 @@ mod tests { comparator: RuntimeConditionComparator::Eq, value: 3, }, + RuntimeCondition::WorldFlagEquals { + key: "world.disable_stock_buying_and_selling".to_string(), + value: true, + }, ], effects: vec![RuntimeEffect::SetWorldFlag { key: "world_condition_passed".to_string(), diff --git a/docs/README.md b/docs/README.md index 82444d8..fd97004 100644 --- a/docs/README.md +++ b/docs/README.md @@ -109,6 +109,15 @@ The highest-value next passes are now: descriptor metadata covers special-condition and candidate-availability setters, and descriptor `110` `Disable Stock Buying and Selling` now executes too through the checked-in keyed runtime flag `world.disable_stock_buying_and_selling` +- that world-toggle path now covers a broader recovered boolean scenario-rule band too: + descriptors `111..138`, excluding the scalar `Limited Track Building Amount` slot, now decode + into keyed `world_flags` for finance/trading, construction, and governance restrictions +- the late recovered world-toggle band now executes too where current evidence is equally strong: + `Use Bio-Accelerator Cars`, `Disable Cargo Economy`, `Disable Train Crashes`, + `Disable Train Crashes AND Breakdowns`, and `AI Ignore Territories At Startup` +- whole-game ordinary-condition coverage is broader now too: checked-in world-flag condition ids + can lower into `world_flag_equals` gates for boolean equality/inequality forms, so real packed + rows can gate whole-game effects on existing `world_flags` - 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 - use `rrt-hook` primarily as optional capture or integration tooling, not as the first execution diff --git a/docs/runtime-rehost-plan.md b/docs/runtime-rehost-plan.md index edc6daa..948cfa3 100644 --- a/docs/runtime-rehost-plan.md +++ b/docs/runtime-rehost-plan.md @@ -63,12 +63,23 @@ Implemented today: through the ordinary runtime path, and the first real world-flag family now executes too: descriptor `110` `Disable Stock Buying and Selling` lowers through checked-in keyed runtime metadata into `world.disable_stock_buying_and_selling` +- that world-side effect batch now covers a broader recovered boolean scenario-rule family too: + descriptors `111..138`, excluding the scalar `Limited Track Building Amount` slot, now lower + through checked-in metadata into keyed `world_flags` for finance/trading, construction, and + governance/company-formation restrictions +- the same keyed world-toggle path now also covers the late special-condition band where current + static evidence stays equally strong: `Use Bio-Accelerator Cars`, `Disable Cargo Economy`, + `Disable Train Crashes`, `Disable Train Crashes AND Breakdowns`, and + `AI Ignore Territories At Startup` now import and execute as keyed `world_flags` +- whole-game ordinary-condition decode now covers checked-in world-flag condition ids too for + boolean equality/inequality forms, so real packed rows can gate whole-game effects on existing + `world_flags` through `world_flag_equals` without fixture-authored placeholder ids 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, -whole-game, train, player, and numeric-threshold batches. Richer runtime ownership should still be -added only where a later descriptor or condition family needs more than the current event-owned -roster. +whole-game toggle, train, player, and numeric-threshold batches. Richer runtime ownership should +still be added only where a later descriptor or condition family needs more than the current +event-owned roster. ## Why This Boundary diff --git a/fixtures/runtime/packed-event-world-flag-condition-overlay-base-snapshot.json b/fixtures/runtime/packed-event-world-flag-condition-overlay-base-snapshot.json new file mode 100644 index 0000000..65f4b65 --- /dev/null +++ b/fixtures/runtime/packed-event-world-flag-condition-overlay-base-snapshot.json @@ -0,0 +1,30 @@ +{ + "format_version": 1, + "snapshot_id": "packed-event-world-flag-condition-overlay-base-snapshot", + "source": { + "description": "Base runtime snapshot supplying the pre-existing world flag required by the real world-flag condition sample." + }, + "state": { + "calendar": { + "year": 1845, + "month_slot": 2, + "phase_slot": 1, + "tick_slot": 3 + }, + "world_flags": { + "world.disable_stock_buying_and_selling": true + }, + "metadata": { + "base.note": "world-flag condition overlay context" + }, + "event_runtime_records": [], + "candidate_availability": {}, + "special_conditions": {}, + "service_state": { + "periodic_boundary_calls": 0, + "trigger_dispatch_counts": {}, + "total_event_record_services": 0, + "dirty_rerun_count": 0 + } + } +} diff --git a/fixtures/runtime/packed-event-world-flag-condition-overlay-fixture.json b/fixtures/runtime/packed-event-world-flag-condition-overlay-fixture.json new file mode 100644 index 0000000..525f050 --- /dev/null +++ b/fixtures/runtime/packed-event-world-flag-condition-overlay-fixture.json @@ -0,0 +1,56 @@ +{ + "format_version": 1, + "fixture_id": "packed-event-world-flag-condition-overlay-fixture", + "source": { + "kind": "captured-runtime", + "description": "Fixture proving a checked-in world-flag condition gates a whole-game effect through the ordinary runtime path." + }, + "state_import_path": "packed-event-world-flag-condition-overlay.json", + "commands": [ + { + "kind": "service_trigger_kind", + "trigger_kind": 7 + } + ], + "expected_summary": { + "calendar_projection_source": "base-snapshot-preserved", + "calendar_projection_is_placeholder": false, + "packed_event_collection_present": true, + "packed_event_record_count": 1, + "packed_event_decoded_record_count": 1, + "packed_event_imported_runtime_record_count": 1, + "event_runtime_record_count": 1, + "candidate_availability_count": 1, + "zero_candidate_availability_count": 0, + "total_event_record_service_count": 1, + "total_trigger_dispatch_count": 1 + }, + "expected_state_fragment": { + "world_flags": { + "world.disable_stock_buying_and_selling": true + }, + "candidate_availability": { + "Turbo Diesel": 1 + }, + "packed_event_collection": { + "records": [ + { + "import_outcome": "imported", + "decoded_conditions": [ + { + "kind": "world_flag_equals", + "key": "world.disable_stock_buying_and_selling", + "value": true + } + ] + } + ] + }, + "event_runtime_records": [ + { + "record_id": 47, + "service_count": 1 + } + ] + } +} diff --git a/fixtures/runtime/packed-event-world-flag-condition-overlay.json b/fixtures/runtime/packed-event-world-flag-condition-overlay.json new file mode 100644 index 0000000..f6ba444 --- /dev/null +++ b/fixtures/runtime/packed-event-world-flag-condition-overlay.json @@ -0,0 +1,9 @@ +{ + "format_version": 1, + "import_id": "packed-event-world-flag-condition-overlay", + "source": { + "description": "Overlay import combining base world-flag context with a real world-flag ordinary-condition record." + }, + "base_snapshot_path": "packed-event-world-flag-condition-overlay-base-snapshot.json", + "save_slice_path": "packed-event-world-flag-condition-save-slice.json" +} diff --git a/fixtures/runtime/packed-event-world-flag-condition-save-slice.json b/fixtures/runtime/packed-event-world-flag-condition-save-slice.json new file mode 100644 index 0000000..f6b7976 --- /dev/null +++ b/fixtures/runtime/packed-event-world-flag-condition-save-slice.json @@ -0,0 +1,179 @@ +{ + "format_version": 1, + "save_slice_id": "packed-event-world-flag-condition-save-slice", + "source": { + "description": "Tracked save-slice document with a real world-flag condition gating a whole-game effect.", + "original_save_filename": "captured-world-flag-condition.gms", + "original_save_sha256": "world-flag-condition-sample-sha256", + "notes": [ + "tracked as JSON save-slice document rather than raw .smp", + "proves checked-in world-flag condition metadata lowers into the runtime condition model" + ] + }, + "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, + "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": 30528, + "records_tag_offset": 30784, + "close_tag_offset": 31104, + "packed_state_version": 1001, + "packed_state_version_hex": "0x000003e9", + "live_id_bound": 47, + "live_record_count": 1, + "live_entry_ids": [ + 47 + ], + "decoded_record_count": 1, + "imported_runtime_record_count": 1, + "records": [ + { + "record_index": 0, + "live_entry_id": 47, + "payload_offset": 30848, + "payload_len": 152, + "decode_status": "executable", + "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": 2535, + "subtype": 0, + "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": "eq", + "metric": "World Flag: Disable Stock Buying and Selling", + "semantic_family": "world_flag_equals", + "semantic_preview": "Test Disable Stock Buying and Selling == TRUE", + "requires_candidate_name_binding": false, + "notes": [ + "checked-in whole-game 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": 109, + "descriptor_label": "Turbo Diesel Availability", + "target_mask_bits": 8, + "parameter_family": "candidate_availability_scalar", + "opcode": 3, + "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": "scalar_assignment", + "semantic_family": "scalar_assignment", + "semantic_preview": "Set Turbo Diesel Availability to 1", + "locomotive_name": null, + "notes": [ + "checked-in whole-game grouped-effect sample" + ] + } + ], + "decoded_conditions": [ + { + "kind": "world_flag_equals", + "key": "world.disable_stock_buying_and_selling", + "value": true + } + ], + "decoded_actions": [ + { + "kind": "set_candidate_availability", + "name": "Turbo Diesel", + "value": 1 + } + ], + "executable_import_ready": true, + "notes": [ + "world-flag condition gates a whole-game effect" + ] + } + ] + }, + "notes": [ + "whole-game world-flag condition sample" + ] + } +} diff --git a/fixtures/runtime/packed-event-world-toggle-construction-save-slice-fixture.json b/fixtures/runtime/packed-event-world-toggle-construction-save-slice-fixture.json new file mode 100644 index 0000000..b863c36 --- /dev/null +++ b/fixtures/runtime/packed-event-world-toggle-construction-save-slice-fixture.json @@ -0,0 +1,32 @@ +{ + "format_version": 1, + "fixture_id": "packed-event-world-toggle-construction-save-slice-fixture", + "source": { + "kind": "captured-runtime", + "description": "Fixture proving recovered construction world-toggle descriptors import and execute." + }, + "state_save_slice_path": "packed-event-world-toggle-construction-save-slice.json", + "commands": [ + { + "kind": "service_trigger_kind", + "trigger_kind": 6 + } + ], + "expected_summary": { + "packed_event_collection_present": true, + "packed_event_record_count": 1, + "packed_event_decoded_record_count": 1, + "packed_event_imported_runtime_record_count": 1, + "event_runtime_record_count": 1, + "packed_event_blocked_unmapped_world_descriptor_count": 0, + "total_event_record_service_count": 1, + "total_trigger_dispatch_count": 1 + }, + "expected_state_fragment": { + "world_flags": { + "world.disable_all_track_building": true, + "world.disable_building_stations": true, + "world.disable_building_hotel_restaurant_tavern_post_office": false + } + } +} diff --git a/fixtures/runtime/packed-event-world-toggle-construction-save-slice.json b/fixtures/runtime/packed-event-world-toggle-construction-save-slice.json new file mode 100644 index 0000000..91c6387 --- /dev/null +++ b/fixtures/runtime/packed-event-world-toggle-construction-save-slice.json @@ -0,0 +1,159 @@ +{ + "format_version": 1, + "save_slice_id": "packed-event-world-toggle-construction-save-slice", + "source": { + "description": "Tracked save-slice document proving recovered construction world-toggle descriptors import and execute.", + "original_save_filename": "captured-world-toggle-construction.gms", + "original_save_sha256": "world-toggle-construction-sample-sha256", + "notes": [ + "tracked as JSON save-slice document rather than raw .smp", + "recovered whole-game toggle batch for construction and placement restrictions" + ] + }, + "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, + "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": 32200, + "records_tag_offset": 32456, + "close_tag_offset": 33224, + "packed_state_version": 1001, + "packed_state_version_hex": "0x000003e9", + "live_id_bound": 51, + "live_record_count": 1, + "live_entry_ids": [51], + "decoded_record_count": 1, + "imported_runtime_record_count": 1, + "records": [ + { + "record_index": 0, + "live_entry_id": 51, + "payload_offset": 32520, + "payload_len": 168, + "decode_status": "executable", + "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": [3, 0, 0, 0], + "grouped_effect_rows": [ + { + "group_index": 0, + "row_index": 0, + "descriptor_id": 120, + "descriptor_label": "Disable All Track Building", + "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 All Track Building to TRUE", + "locomotive_name": null, + "notes": [] + }, + { + "group_index": 0, + "row_index": 1, + "descriptor_id": 123, + "descriptor_label": "Disable Building Stations", + "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 Building Stations to TRUE", + "locomotive_name": null, + "notes": [] + }, + { + "group_index": 0, + "row_index": 2, + "descriptor_id": 124, + "descriptor_label": "Disable Building Hotel/Restaurant/Tavern/Post Office", + "target_mask_bits": 8, + "parameter_family": "world_flag_toggle", + "opcode": 0, + "raw_scalar_value": 0, + "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 Building Hotel/Restaurant/Tavern/Post Office to FALSE", + "locomotive_name": null, + "notes": [] + } + ], + "decoded_conditions": [], + "decoded_actions": [ + { + "kind": "set_world_flag", + "key": "world.disable_all_track_building", + "value": true + }, + { + "kind": "set_world_flag", + "key": "world.disable_building_stations", + "value": true + }, + { + "kind": "set_world_flag", + "key": "world.disable_building_hotel_restaurant_tavern_post_office", + "value": false + } + ], + "executable_import_ready": true, + "notes": [ + "recovered whole-game construction-toggle descriptor batch" + ] + } + ] + }, + "notes": [ + "whole-game construction toggle effect sample" + ] + } +} diff --git a/fixtures/runtime/packed-event-world-toggle-finance-save-slice-fixture.json b/fixtures/runtime/packed-event-world-toggle-finance-save-slice-fixture.json new file mode 100644 index 0000000..68c1b70 --- /dev/null +++ b/fixtures/runtime/packed-event-world-toggle-finance-save-slice-fixture.json @@ -0,0 +1,32 @@ +{ + "format_version": 1, + "fixture_id": "packed-event-world-toggle-finance-save-slice-fixture", + "source": { + "kind": "captured-runtime", + "description": "Fixture proving recovered finance/trading world-toggle descriptors import and execute." + }, + "state_save_slice_path": "packed-event-world-toggle-finance-save-slice.json", + "commands": [ + { + "kind": "service_trigger_kind", + "trigger_kind": 6 + } + ], + "expected_summary": { + "packed_event_collection_present": true, + "packed_event_record_count": 1, + "packed_event_decoded_record_count": 1, + "packed_event_imported_runtime_record_count": 1, + "event_runtime_record_count": 1, + "packed_event_blocked_unmapped_world_descriptor_count": 0, + "total_event_record_service_count": 1, + "total_trigger_dispatch_count": 1 + }, + "expected_state_fragment": { + "world_flags": { + "world.disable_margin_buying_short_selling_stock": true, + "world.disable_company_issue_buy_back_stock": true, + "world.disable_issuing_repaying_bonds": false + } + } +} diff --git a/fixtures/runtime/packed-event-world-toggle-finance-save-slice.json b/fixtures/runtime/packed-event-world-toggle-finance-save-slice.json new file mode 100644 index 0000000..b1c46de --- /dev/null +++ b/fixtures/runtime/packed-event-world-toggle-finance-save-slice.json @@ -0,0 +1,159 @@ +{ + "format_version": 1, + "save_slice_id": "packed-event-world-toggle-finance-save-slice", + "source": { + "description": "Tracked save-slice document proving recovered finance/trading world-toggle descriptors import and execute.", + "original_save_filename": "captured-world-toggle-finance.gms", + "original_save_sha256": "world-toggle-finance-sample-sha256", + "notes": [ + "tracked as JSON save-slice document rather than raw .smp", + "recovered whole-game toggle batch for finance and trading restrictions" + ] + }, + "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, + "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": 32100, + "records_tag_offset": 32356, + "close_tag_offset": 33124, + "packed_state_version": 1001, + "packed_state_version_hex": "0x000003e9", + "live_id_bound": 50, + "live_record_count": 1, + "live_entry_ids": [50], + "decoded_record_count": 1, + "imported_runtime_record_count": 1, + "records": [ + { + "record_index": 0, + "live_entry_id": 50, + "payload_offset": 32420, + "payload_len": 168, + "decode_status": "executable", + "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": [3, 0, 0, 0], + "grouped_effect_rows": [ + { + "group_index": 0, + "row_index": 0, + "descriptor_id": 111, + "descriptor_label": "Disable Margin Buying/Short Selling Stock", + "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 Margin Buying/Short Selling Stock to TRUE", + "locomotive_name": null, + "notes": [] + }, + { + "group_index": 0, + "row_index": 1, + "descriptor_id": 112, + "descriptor_label": "Disable Company Issue/Buy Back Stock", + "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 Company Issue/Buy Back Stock to TRUE", + "locomotive_name": null, + "notes": [] + }, + { + "group_index": 0, + "row_index": 2, + "descriptor_id": 113, + "descriptor_label": "Disable Issuing/Repaying Bonds", + "target_mask_bits": 8, + "parameter_family": "world_flag_toggle", + "opcode": 0, + "raw_scalar_value": 0, + "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 Issuing/Repaying Bonds to FALSE", + "locomotive_name": null, + "notes": [] + } + ], + "decoded_conditions": [], + "decoded_actions": [ + { + "kind": "set_world_flag", + "key": "world.disable_margin_buying_short_selling_stock", + "value": true + }, + { + "kind": "set_world_flag", + "key": "world.disable_company_issue_buy_back_stock", + "value": true + }, + { + "kind": "set_world_flag", + "key": "world.disable_issuing_repaying_bonds", + "value": false + } + ], + "executable_import_ready": true, + "notes": [ + "recovered whole-game finance-toggle descriptor batch" + ] + } + ] + }, + "notes": [ + "whole-game finance toggle effect sample" + ] + } +} diff --git a/fixtures/runtime/packed-event-world-toggle-governance-save-slice-fixture.json b/fixtures/runtime/packed-event-world-toggle-governance-save-slice-fixture.json new file mode 100644 index 0000000..9b9784d --- /dev/null +++ b/fixtures/runtime/packed-event-world-toggle-governance-save-slice-fixture.json @@ -0,0 +1,32 @@ +{ + "format_version": 1, + "fixture_id": "packed-event-world-toggle-governance-save-slice-fixture", + "source": { + "kind": "captured-runtime", + "description": "Fixture proving recovered governance/company-formation world-toggle descriptors import and execute." + }, + "state_save_slice_path": "packed-event-world-toggle-governance-save-slice.json", + "commands": [ + { + "kind": "service_trigger_kind", + "trigger_kind": 6 + } + ], + "expected_summary": { + "packed_event_collection_present": true, + "packed_event_record_count": 1, + "packed_event_decoded_record_count": 1, + "packed_event_imported_runtime_record_count": 1, + "event_runtime_record_count": 1, + "packed_event_blocked_unmapped_world_descriptor_count": 0, + "total_event_record_service_count": 1, + "total_trigger_dispatch_count": 1 + }, + "expected_state_fragment": { + "world_flags": { + "world.disable_starting_any_companies": true, + "world.disable_starting_multiple_companies": false, + "world.disable_merging_companies": true + } + } +} diff --git a/fixtures/runtime/packed-event-world-toggle-governance-save-slice.json b/fixtures/runtime/packed-event-world-toggle-governance-save-slice.json new file mode 100644 index 0000000..365d367 --- /dev/null +++ b/fixtures/runtime/packed-event-world-toggle-governance-save-slice.json @@ -0,0 +1,159 @@ +{ + "format_version": 1, + "save_slice_id": "packed-event-world-toggle-governance-save-slice", + "source": { + "description": "Tracked save-slice document proving recovered governance/company-formation world-toggle descriptors import and execute.", + "original_save_filename": "captured-world-toggle-governance.gms", + "original_save_sha256": "world-toggle-governance-sample-sha256", + "notes": [ + "tracked as JSON save-slice document rather than raw .smp", + "recovered whole-game toggle batch for governance and company-formation restrictions" + ] + }, + "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, + "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": 32300, + "records_tag_offset": 32556, + "close_tag_offset": 33324, + "packed_state_version": 1001, + "packed_state_version_hex": "0x000003e9", + "live_id_bound": 52, + "live_record_count": 1, + "live_entry_ids": [52], + "decoded_record_count": 1, + "imported_runtime_record_count": 1, + "records": [ + { + "record_index": 0, + "live_entry_id": 52, + "payload_offset": 32620, + "payload_len": 168, + "decode_status": "executable", + "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": [3, 0, 0, 0], + "grouped_effect_rows": [ + { + "group_index": 0, + "row_index": 0, + "descriptor_id": 131, + "descriptor_label": "Disable Starting Any Companies", + "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 Starting Any Companies to TRUE", + "locomotive_name": null, + "notes": [] + }, + { + "group_index": 0, + "row_index": 1, + "descriptor_id": 132, + "descriptor_label": "Disable Starting Multiple Companies", + "target_mask_bits": 8, + "parameter_family": "world_flag_toggle", + "opcode": 0, + "raw_scalar_value": 0, + "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 Starting Multiple Companies to FALSE", + "locomotive_name": null, + "notes": [] + }, + { + "group_index": 0, + "row_index": 2, + "descriptor_id": 133, + "descriptor_label": "Disable Merging Companies", + "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 Merging Companies to TRUE", + "locomotive_name": null, + "notes": [] + } + ], + "decoded_conditions": [], + "decoded_actions": [ + { + "kind": "set_world_flag", + "key": "world.disable_starting_any_companies", + "value": true + }, + { + "kind": "set_world_flag", + "key": "world.disable_starting_multiple_companies", + "value": false + }, + { + "kind": "set_world_flag", + "key": "world.disable_merging_companies", + "value": true + } + ], + "executable_import_ready": true, + "notes": [ + "recovered whole-game governance-toggle descriptor batch" + ] + } + ] + }, + "notes": [ + "whole-game governance toggle effect sample" + ] + } +} diff --git a/fixtures/runtime/packed-event-world-toggle-late-save-slice-fixture.json b/fixtures/runtime/packed-event-world-toggle-late-save-slice-fixture.json new file mode 100644 index 0000000..3faa278 --- /dev/null +++ b/fixtures/runtime/packed-event-world-toggle-late-save-slice-fixture.json @@ -0,0 +1,34 @@ +{ + "format_version": 1, + "fixture_id": "packed-event-world-toggle-late-save-slice-fixture", + "source": { + "kind": "captured-runtime", + "description": "Fixture proving recovered late whole-game toggle descriptors import and execute." + }, + "state_save_slice_path": "packed-event-world-toggle-late-save-slice.json", + "commands": [ + { + "kind": "service_trigger_kind", + "trigger_kind": 6 + } + ], + "expected_summary": { + "packed_event_collection_present": true, + "packed_event_record_count": 1, + "packed_event_decoded_record_count": 1, + "packed_event_imported_runtime_record_count": 1, + "event_runtime_record_count": 1, + "packed_event_blocked_unmapped_world_descriptor_count": 0, + "total_event_record_service_count": 1, + "total_trigger_dispatch_count": 1 + }, + "expected_state_fragment": { + "world_flags": { + "world.use_bio_accelerator_cars": true, + "world.disable_cargo_economy": true, + "world.disable_train_crashes": false, + "world.disable_train_crashes_and_breakdowns": true, + "world.ai_ignore_territories_at_startup": true + } + } +} diff --git a/fixtures/runtime/packed-event-world-toggle-late-save-slice.json b/fixtures/runtime/packed-event-world-toggle-late-save-slice.json new file mode 100644 index 0000000..6d9f4c3 --- /dev/null +++ b/fixtures/runtime/packed-event-world-toggle-late-save-slice.json @@ -0,0 +1,211 @@ +{ + "format_version": 1, + "save_slice_id": "packed-event-world-toggle-late-save-slice", + "source": { + "description": "Tracked save-slice document proving recovered late whole-game toggle descriptors import and execute.", + "original_save_filename": "captured-world-toggle-late.gms", + "original_save_sha256": "world-toggle-late-sample-sha256", + "notes": [ + "tracked as JSON save-slice document rather than raw .smp", + "recovered whole-game toggle batch for bio-accelerator, cargo economy, crash, and AI startup restrictions" + ] + }, + "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, + "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": 32400, + "records_tag_offset": 32656, + "close_tag_offset": 33424, + "packed_state_version": 1001, + "packed_state_version_hex": "0x000003e9", + "live_id_bound": 53, + "live_record_count": 1, + "live_entry_ids": [53], + "decoded_record_count": 1, + "imported_runtime_record_count": 1, + "records": [ + { + "record_index": 0, + "live_entry_id": 53, + "payload_offset": 32720, + "payload_len": 216, + "decode_status": "executable", + "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": 139, + "descriptor_label": "Use Bio-Accelerator Cars", + "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 Use Bio-Accelerator Cars to TRUE", + "locomotive_name": null, + "notes": [] + }, + { + "group_index": 0, + "row_index": 1, + "descriptor_id": 140, + "descriptor_label": "Disable Cargo Economy", + "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 Cargo Economy to TRUE", + "locomotive_name": null, + "notes": [] + }, + { + "group_index": 0, + "row_index": 2, + "descriptor_id": 142, + "descriptor_label": "Disable Train Crashes", + "target_mask_bits": 8, + "parameter_family": "world_flag_toggle", + "opcode": 0, + "raw_scalar_value": 0, + "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 Train Crashes to FALSE", + "locomotive_name": null, + "notes": [] + }, + { + "group_index": 0, + "row_index": 3, + "descriptor_id": 143, + "descriptor_label": "Disable Train Crashes AND Breakdowns", + "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 Train Crashes AND Breakdowns to TRUE", + "locomotive_name": null, + "notes": [] + }, + { + "group_index": 0, + "row_index": 4, + "descriptor_id": 144, + "descriptor_label": "AI Ignore Territories At Startup", + "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 AI Ignore Territories At Startup to TRUE", + "locomotive_name": null, + "notes": [] + } + ], + "decoded_conditions": [], + "decoded_actions": [ + { + "kind": "set_world_flag", + "key": "world.use_bio_accelerator_cars", + "value": true + }, + { + "kind": "set_world_flag", + "key": "world.disable_cargo_economy", + "value": true + }, + { + "kind": "set_world_flag", + "key": "world.disable_train_crashes", + "value": false + }, + { + "kind": "set_world_flag", + "key": "world.disable_train_crashes_and_breakdowns", + "value": true + }, + { + "kind": "set_world_flag", + "key": "world.ai_ignore_territories_at_startup", + "value": true + } + ], + "executable_import_ready": true, + "notes": [ + "recovered late whole-game toggle descriptor batch" + ] + } + ] + }, + "notes": [ + "whole-game late toggle effect sample" + ] + } +}