Broaden whole-game packed event coverage
This commit is contained in:
parent
991725dba8
commit
b89463d227
19 changed files with 1874 additions and 27 deletions
18
README.md
18
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:
|
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`
|
special-condition and candidate-availability setters import natively, and descriptor `110`
|
||||||
`Disable Stock Buying and Selling` now lowers into the keyed runtime flag
|
`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
|
`world.disable_stock_buying_and_selling`. The recovered whole-game toggle batch is broader now
|
||||||
frontier buckets still remain where current checked-in metadata stops. Shell purchase-flow and
|
too: descriptors `111..138`, excluding the scalar `Limited Track Building Amount` slot, also lower
|
||||||
selected-profile parity remain out of scope. Mixed supported/unsupported real rows still stay
|
into keyed `world_flags` for finance/trading, construction, and governance restrictions. Explicit
|
||||||
parity-only. The PE32 hook remains useful as capture and integration tooling, but it is no longer
|
the late recovered special-condition toggles now execute too where current evidence is equally
|
||||||
the main execution milestone.
|
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
|
## Project Docs
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1240,6 +1240,10 @@ fn lower_condition_targets_in_condition(
|
||||||
value: *value,
|
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::TerritoryNumericThreshold { .. }
|
||||||
| RuntimeCondition::SpecialConditionThreshold { .. }
|
| RuntimeCondition::SpecialConditionThreshold { .. }
|
||||||
| RuntimeCondition::CandidateAvailabilityThreshold { .. }
|
| 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::SpecialConditionThreshold { .. }
|
||||||
| RuntimeCondition::CandidateAvailabilityThreshold { .. }
|
| RuntimeCondition::CandidateAvailabilityThreshold { .. }
|
||||||
| RuntimeCondition::EconomicStatusCodeThreshold { .. }
|
| RuntimeCondition::EconomicStatusCodeThreshold { .. }
|
||||||
|
| RuntimeCondition::WorldFlagEquals { .. }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1980,7 +1986,8 @@ 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::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 {
|
crate::SmpLoadedPackedEventGroupedEffectRowSummary {
|
||||||
group_index: 0,
|
group_index: 0,
|
||||||
row_index: 0,
|
row_index: 0,
|
||||||
descriptor_id: 110,
|
descriptor_id,
|
||||||
descriptor_label: Some("Disable Stock Buying and Selling".to_string()),
|
descriptor_label: Some(label.to_string()),
|
||||||
target_mask_bits: Some(0x08),
|
target_mask_bits: Some(0x08),
|
||||||
parameter_family: Some("world_flag_toggle".to_string()),
|
parameter_family: Some("world_flag_toggle".to_string()),
|
||||||
opcode: 0,
|
opcode: 0,
|
||||||
|
|
@ -2863,7 +2874,7 @@ mod tests {
|
||||||
row_shape: "bool_toggle".to_string(),
|
row_shape: "bool_toggle".to_string(),
|
||||||
semantic_family: Some("bool_toggle".to_string()),
|
semantic_family: Some("bool_toggle".to_string()),
|
||||||
semantic_preview: Some(format!(
|
semantic_preview: Some(format!(
|
||||||
"Set Disable Stock Buying and Selling to {}",
|
"Set {label} to {}",
|
||||||
if enabled { "TRUE" } else { "FALSE" }
|
if enabled { "TRUE" } else { "FALSE" }
|
||||||
)),
|
)),
|
||||||
locomotive_name: None,
|
locomotive_name: None,
|
||||||
|
|
@ -5658,7 +5669,11 @@ mod tests {
|
||||||
standalone_condition_rows: vec![],
|
standalone_condition_rows: vec![],
|
||||||
negative_sentinel_scope: None,
|
negative_sentinel_scope: None,
|
||||||
grouped_effect_row_counts: vec![1, 0, 0, 0],
|
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_conditions: Vec::new(),
|
||||||
decoded_actions: vec![RuntimeEffect::SetWorldFlag {
|
decoded_actions: vec![RuntimeEffect::SetWorldFlag {
|
||||||
key: "world.disable_stock_buying_and_selling".to_string(),
|
key: "world.disable_stock_buying_and_selling".to_string(),
|
||||||
|
|
@ -5751,7 +5766,11 @@ mod tests {
|
||||||
standalone_condition_rows: vec![],
|
standalone_condition_rows: vec![],
|
||||||
negative_sentinel_scope: None,
|
negative_sentinel_scope: None,
|
||||||
grouped_effect_row_counts: vec![1, 0, 0, 0],
|
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_conditions: Vec::new(),
|
||||||
decoded_actions: vec![RuntimeEffect::SetWorldFlag {
|
decoded_actions: vec![RuntimeEffect::SetWorldFlag {
|
||||||
key: "world.disable_stock_buying_and_selling".to_string(),
|
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]
|
#[test]
|
||||||
fn overlays_real_confiscate_all_descriptor_into_executable_runtime_record() {
|
fn overlays_real_confiscate_all_descriptor_into_executable_runtime_record() {
|
||||||
let base_state = RuntimeState {
|
let base_state = RuntimeState {
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,10 @@ pub enum RuntimeCondition {
|
||||||
comparator: RuntimeConditionComparator,
|
comparator: RuntimeConditionComparator,
|
||||||
value: i64,
|
value: i64,
|
||||||
},
|
},
|
||||||
|
WorldFlagEquals {
|
||||||
|
key: String,
|
||||||
|
value: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
|
@ -1268,6 +1272,13 @@ fn validate_runtime_condition(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RuntimeCondition::EconomicStatusCodeThreshold { .. } => Ok(()),
|
RuntimeCondition::EconomicStatusCodeThreshold { .. } => Ok(()),
|
||||||
|
RuntimeCondition::WorldFlagEquals { key, .. } => {
|
||||||
|
if key.trim().is_empty() {
|
||||||
|
Err("key must not be empty".to_string())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,7 @@ enum RealWorldConditionKind {
|
||||||
SpecialCondition { label: &'static str },
|
SpecialCondition { label: &'static str },
|
||||||
CandidateAvailability,
|
CandidateAvailability,
|
||||||
EconomicStatus,
|
EconomicStatus,
|
||||||
|
WorldFlag { key: &'static str },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
|
@ -2499,14 +2500,26 @@ fn real_ordinary_condition_metadata(
|
||||||
.find(|metadata| metadata.raw_condition_id == raw_condition_id)
|
.find(|metadata| metadata.raw_condition_id == raw_condition_id)
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
known_special_condition_definition_for_label_id(raw_condition_id as u32).map(
|
known_special_condition_definition_for_label_id(raw_condition_id as u32).map(
|
||||||
|definition| RealOrdinaryConditionMetadata {
|
|definition| {
|
||||||
raw_condition_id,
|
let kind = if let Some(world_toggle) =
|
||||||
label: definition.label,
|
real_grouped_effect_descriptor_metadata(110 + definition.slot_index as u32)
|
||||||
kind: RealOrdinaryConditionKind::WorldState(
|
.filter(|metadata| metadata.parameter_family == "world_flag_toggle")
|
||||||
RealWorldConditionKind::SpecialCondition {
|
{
|
||||||
label: definition.label,
|
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) => {
|
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => {
|
||||||
"Economic Status".to_string()
|
"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 {
|
) -> &'static str {
|
||||||
match metadata.kind {
|
match metadata.kind {
|
||||||
RealOrdinaryConditionKind::Numeric(_) => "numeric_threshold",
|
RealOrdinaryConditionKind::Numeric(_) => "numeric_threshold",
|
||||||
|
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { .. }) => {
|
||||||
|
"world_flag_equals"
|
||||||
|
}
|
||||||
RealOrdinaryConditionKind::WorldState(_) => "world_state_threshold",
|
RealOrdinaryConditionKind::WorldState(_) => "world_state_threshold",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2737,9 +2756,28 @@ fn decode_real_condition_row(
|
||||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => {
|
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => {
|
||||||
Some(RuntimeCondition::EconomicStatusCodeThreshold { comparator, value })
|
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<RuntimeCondition> {
|
||||||
|
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(
|
fn real_grouped_effect_descriptor_metadata(
|
||||||
descriptor_id: u32,
|
descriptor_id: u32,
|
||||||
) -> Option<RealGroupedEffectDescriptorMetadata> {
|
) -> Option<RealGroupedEffectDescriptorMetadata> {
|
||||||
|
|
@ -2747,6 +2785,28 @@ fn real_grouped_effect_descriptor_metadata(
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
.find(|metadata| metadata.descriptor_id == descriptor_id)
|
.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<RealGroupedEffectDescriptorMetadata> {
|
||||||
|
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(
|
fn classify_real_grouped_effect_semantic_family(
|
||||||
|
|
@ -2830,7 +2890,32 @@ fn runtime_candidate_availability_name(label: &str) -> String {
|
||||||
fn runtime_world_flag_key(
|
fn runtime_world_flag_key(
|
||||||
descriptor_metadata: RealGroupedEffectDescriptorMetadata,
|
descriptor_metadata: RealGroupedEffectDescriptorMetadata,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
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(
|
fn decode_real_grouped_effect_actions(
|
||||||
|
|
@ -2928,7 +3013,7 @@ fn decode_real_grouped_effect_action(
|
||||||
}
|
}
|
||||||
|
|
||||||
if descriptor_metadata.executable_in_runtime
|
if descriptor_metadata.executable_in_runtime
|
||||||
&& descriptor_metadata.descriptor_id == 110
|
&& descriptor_metadata.parameter_family == "world_flag_toggle"
|
||||||
&& row.row_shape == "bool_toggle"
|
&& row.row_shape == "bool_toggle"
|
||||||
{
|
{
|
||||||
return Some(RuntimeEffect::SetWorldFlag {
|
return Some(RuntimeEffect::SetWorldFlag {
|
||||||
|
|
@ -3232,7 +3317,8 @@ fn runtime_condition_supported_for_save_import(condition: &RuntimeCondition) ->
|
||||||
| RuntimeCondition::CompanyTerritoryNumericThreshold { .. }
|
| RuntimeCondition::CompanyTerritoryNumericThreshold { .. }
|
||||||
| RuntimeCondition::SpecialConditionThreshold { .. }
|
| RuntimeCondition::SpecialConditionThreshold { .. }
|
||||||
| RuntimeCondition::CandidateAvailabilityThreshold { .. }
|
| 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]
|
#[test]
|
||||||
fn looks_up_checked_in_world_flag_descriptor_metadata() {
|
fn looks_up_checked_in_world_flag_descriptor_metadata() {
|
||||||
let metadata =
|
let metadata =
|
||||||
|
|
@ -8869,6 +9016,34 @@ mod tests {
|
||||||
assert!(metadata.executable_in_runtime);
|
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]
|
#[test]
|
||||||
fn looks_up_checked_in_deactivate_player_descriptor_metadata() {
|
fn looks_up_checked_in_deactivate_player_descriptor_metadata() {
|
||||||
let metadata =
|
let metadata =
|
||||||
|
|
@ -9027,6 +9202,154 @@ mod tests {
|
||||||
assert!(summary.records[0].executable_import_ready);
|
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]
|
#[test]
|
||||||
fn decodes_negative_sentinel_scope_modifiers_and_territory_marker() {
|
fn decodes_negative_sentinel_scope_modifiers_and_territory_marker() {
|
||||||
for (value, expected) in [
|
for (value, expected) in [
|
||||||
|
|
|
||||||
|
|
@ -710,6 +710,12 @@ fn evaluate_record_conditions(
|
||||||
return Ok(None);
|
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),
|
economic_status_code: Some(3),
|
||||||
..RuntimeWorldRestoreState::default()
|
..RuntimeWorldRestoreState::default()
|
||||||
},
|
},
|
||||||
|
world_flags: BTreeMap::from([(
|
||||||
|
String::from("world.disable_stock_buying_and_selling"),
|
||||||
|
true,
|
||||||
|
)]),
|
||||||
candidate_availability: BTreeMap::from([(String::from("Mogul"), 2)]),
|
candidate_availability: BTreeMap::from([(String::from("Mogul"), 2)]),
|
||||||
special_conditions: BTreeMap::from([(String::from("Use Wartime Cargos"), 1)]),
|
special_conditions: BTreeMap::from([(String::from("Use Wartime Cargos"), 1)]),
|
||||||
event_runtime_records: vec![
|
event_runtime_records: vec![
|
||||||
|
|
@ -1915,6 +1925,10 @@ mod tests {
|
||||||
comparator: RuntimeConditionComparator::Eq,
|
comparator: RuntimeConditionComparator::Eq,
|
||||||
value: 3,
|
value: 3,
|
||||||
},
|
},
|
||||||
|
RuntimeCondition::WorldFlagEquals {
|
||||||
|
key: "world.disable_stock_buying_and_selling".to_string(),
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
effects: vec![RuntimeEffect::SetWorldFlag {
|
effects: vec![RuntimeEffect::SetWorldFlag {
|
||||||
key: "world_condition_passed".to_string(),
|
key: "world_condition_passed".to_string(),
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,15 @@ The highest-value next passes are now:
|
||||||
descriptor metadata covers special-condition and candidate-availability setters, and descriptor
|
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
|
`110` `Disable Stock Buying and Selling` now executes too through the checked-in keyed runtime
|
||||||
flag `world.disable_stock_buying_and_selling`
|
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,
|
- 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
|
||||||
|
|
|
||||||
|
|
@ -63,12 +63,23 @@ Implemented today:
|
||||||
through the ordinary runtime path, and the first real world-flag family now executes too:
|
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
|
descriptor `110` `Disable Stock Buying and Selling` lowers through checked-in keyed runtime
|
||||||
metadata into `world.disable_stock_buying_and_selling`
|
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
|
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, train, player, and numeric-threshold batches. Richer runtime ownership should still be
|
whole-game toggle, train, player, and numeric-threshold batches. Richer runtime ownership should
|
||||||
added only where a later descriptor or condition family needs more than the current event-owned
|
still be added only where a later descriptor or condition family needs more than the current
|
||||||
roster.
|
event-owned roster.
|
||||||
|
|
||||||
## Why This Boundary
|
## Why This Boundary
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
211
fixtures/runtime/packed-event-world-toggle-late-save-slice.json
Normal file
211
fixtures/runtime/packed-event-world-toggle-late-save-slice.json
Normal file
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue