Execute world track build limit descriptor

This commit is contained in:
Jan Petykiewicz 2026-04-16 09:20:49 -07:00
commit 43c76adbf0
11 changed files with 439 additions and 9 deletions

View file

@ -36,9 +36,11 @@ whole-game descriptor metadata now drives the first real world-side effect batch
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`. The recovered whole-game toggle batch is broader now `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 too: descriptors `111..138`, with descriptor `122` `Limited Track Building Amount` now landing in
into keyed `world_flags` for finance/trading, construction, and governance restrictions. Explicit the bounded `world_restore.limited_track_building_amount` scalar and the remaining boolean lanes
the late recovered special-condition toggles now execute too where current evidence is equally lowering into keyed `world_flags`, cover 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 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 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 is broader now too: checked-in world-flag condition ids can lower into `world_flag_equals` gates

View file

@ -54,6 +54,8 @@ pub struct ExpectedRuntimeSummary {
#[serde(default)] #[serde(default)]
pub world_restore_ai_ignore_territories_at_startup_enabled: Option<bool>, pub world_restore_ai_ignore_territories_at_startup_enabled: Option<bool>,
#[serde(default)] #[serde(default)]
pub world_restore_limited_track_building_amount: Option<i32>,
#[serde(default)]
pub world_restore_economic_status_code: Option<i32>, pub world_restore_economic_status_code: Option<i32>,
#[serde(default)] #[serde(default)]
pub world_restore_absolute_counter_restore_kind: Option<String>, pub world_restore_absolute_counter_restore_kind: Option<String>,
@ -345,6 +347,14 @@ impl ExpectedRuntimeSummary {
)); ));
} }
} }
if let Some(value) = self.world_restore_limited_track_building_amount {
if actual.world_restore_limited_track_building_amount != Some(value) {
mismatches.push(format!(
"world_restore_limited_track_building_amount mismatch: expected {value}, got {:?}",
actual.world_restore_limited_track_building_amount
));
}
}
if let Some(code) = self.world_restore_economic_status_code { if let Some(code) = self.world_restore_economic_status_code {
if actual.world_restore_economic_status_code != Some(code) { if actual.world_restore_economic_status_code != Some(code) {
mismatches.push(format!( mismatches.push(format!(

View file

@ -532,6 +532,7 @@ fn project_save_slice_components(
disable_train_crashes_enabled: special_condition_enabled(32), disable_train_crashes_enabled: special_condition_enabled(32),
disable_train_crashes_and_breakdowns_enabled: special_condition_enabled(33), disable_train_crashes_and_breakdowns_enabled: special_condition_enabled(33),
ai_ignore_territories_at_startup_enabled: special_condition_enabled(34), ai_ignore_territories_at_startup_enabled: special_condition_enabled(34),
limited_track_building_amount: None,
economic_status_code: None, economic_status_code: None,
absolute_counter_restore_kind: Some( absolute_counter_restore_kind: Some(
"mode-adjusted-selected-year-lane".to_string(), "mode-adjusted-selected-year-lane".to_string(),
@ -1034,6 +1035,9 @@ fn lower_condition_targets_in_effect(
key: key.clone(), key: key.clone(),
value: *value, value: *value,
}, },
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
RuntimeEffect::SetLimitedTrackBuildingAmount { value: *value }
}
RuntimeEffect::SetEconomicStatusCode { value } => { RuntimeEffect::SetEconomicStatusCode { value } => {
RuntimeEffect::SetEconomicStatusCode { value: *value } RuntimeEffect::SetEconomicStatusCode { value: *value }
} }
@ -1358,6 +1362,9 @@ fn smp_runtime_effect_to_runtime_effect(
key: key.clone(), key: key.clone(),
value: *value, value: *value,
}), }),
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
Ok(RuntimeEffect::SetLimitedTrackBuildingAmount { value: *value })
}
RuntimeEffect::SetEconomicStatusCode { value } => { RuntimeEffect::SetEconomicStatusCode { value } => {
Ok(RuntimeEffect::SetEconomicStatusCode { value: *value }) Ok(RuntimeEffect::SetEconomicStatusCode { value: *value })
} }
@ -2099,6 +2106,7 @@ fn runtime_effect_uses_condition_true_company(effect: &RuntimeEffect) -> bool {
.iter() .iter()
.any(runtime_effect_uses_condition_true_company), .any(runtime_effect_uses_condition_true_company),
RuntimeEffect::SetWorldFlag { .. } RuntimeEffect::SetWorldFlag { .. }
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
| RuntimeEffect::SetEconomicStatusCode { .. } | RuntimeEffect::SetEconomicStatusCode { .. }
| RuntimeEffect::SetPlayerCash { .. } | RuntimeEffect::SetPlayerCash { .. }
| RuntimeEffect::DeactivatePlayer { .. } | RuntimeEffect::DeactivatePlayer { .. }
@ -2177,6 +2185,7 @@ fn runtime_effect_company_target_import_blocker(
runtime_effect_company_target_import_blocker(nested, company_context) runtime_effect_company_target_import_blocker(nested, company_context)
}), }),
RuntimeEffect::SetWorldFlag { .. } RuntimeEffect::SetWorldFlag { .. }
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
| RuntimeEffect::SetEconomicStatusCode { .. } | RuntimeEffect::SetEconomicStatusCode { .. }
| RuntimeEffect::SetCandidateAvailability { .. } | RuntimeEffect::SetCandidateAvailability { .. }
| RuntimeEffect::SetSpecialCondition { .. } | RuntimeEffect::SetSpecialCondition { .. }
@ -2799,6 +2808,32 @@ mod tests {
} }
} }
fn real_limited_track_building_amount_row(
value: i32,
) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary {
crate::SmpLoadedPackedEventGroupedEffectRowSummary {
group_index: 0,
row_index: 0,
descriptor_id: 122,
descriptor_label: Some("Limited Track Building Amount".to_string()),
target_mask_bits: Some(0x08),
parameter_family: Some("world_track_build_limit_scalar".to_string()),
opcode: 3,
raw_scalar_value: value,
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(format!("Set Limited Track Building Amount to {value}")),
locomotive_name: None,
notes: vec![],
}
}
fn real_special_condition_row( fn real_special_condition_row(
value: i32, value: i32,
) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary { ) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary {
@ -5462,6 +5497,81 @@ mod tests {
assert_eq!(import.state.world_restore.economic_status_code, Some(2)); assert_eq!(import.state.world_restore.economic_status_code, Some(2));
} }
#[test]
fn imports_real_limited_track_building_amount_descriptor_into_executable_runtime_record() {
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: 52,
live_record_count: 1,
live_entry_ids: vec![52],
decoded_record_count: 1,
imported_runtime_record_count: 0,
records: vec![crate::SmpLoadedPackedEventRecordSummary {
record_index: 0,
live_entry_id: 52,
payload_offset: Some(0x7202),
payload_len: Some(120),
decode_status: "parity_only".to_string(),
payload_family: "real_packed_v1".to_string(),
trigger_kind: Some(6),
active: None,
marks_collection_dirty: None,
one_shot: Some(false),
compact_control: Some(real_compact_control()),
text_bands: packed_text_bands(),
standalone_condition_row_count: 0,
standalone_condition_rows: vec![],
negative_sentinel_scope: None,
grouped_effect_row_counts: vec![1, 0, 0, 0],
grouped_effect_rows: vec![real_limited_track_building_amount_row(18)],
decoded_conditions: Vec::new(),
decoded_actions: vec![RuntimeEffect::SetLimitedTrackBuildingAmount {
value: 18,
}],
executable_import_ready: true,
notes: vec!["decoded from grounded real 0x4e9a row framing".to_string()],
}],
}),
notes: vec![],
};
let mut import = project_save_slice_to_runtime_state_import(
&save_slice,
"real-limited-track-building-amount-save-slice",
None,
)
.expect("save-slice import should project");
execute_step_command(
&mut import.state,
&StepCommand::ServiceTriggerKind { trigger_kind: 6 },
)
.expect("real limited-track-building-amount descriptor should execute");
assert_eq!(
import.state.world_restore.limited_track_building_amount,
Some(18)
);
}
#[test] #[test]
fn overlays_real_special_condition_descriptor_into_executable_runtime_record() { fn overlays_real_special_condition_descriptor_into_executable_runtime_record() {
let base_state = state(); let base_state = state();

View file

@ -255,6 +255,9 @@ pub enum RuntimeEffect {
key: String, key: String,
value: bool, value: bool,
}, },
SetLimitedTrackBuildingAmount {
value: i32,
},
SetEconomicStatusCode { SetEconomicStatusCode {
value: i32, value: i32,
}, },
@ -591,6 +594,8 @@ pub struct RuntimeWorldRestoreState {
#[serde(default)] #[serde(default)]
pub ai_ignore_territories_at_startup_enabled: Option<bool>, pub ai_ignore_territories_at_startup_enabled: Option<bool>,
#[serde(default)] #[serde(default)]
pub limited_track_building_amount: Option<i32>,
#[serde(default)]
pub economic_status_code: Option<i32>, pub economic_status_code: Option<i32>,
#[serde(default)] #[serde(default)]
pub absolute_counter_restore_kind: Option<String>, pub absolute_counter_restore_kind: Option<String>,
@ -1136,7 +1141,8 @@ fn validate_runtime_effect(
return Err("key must not be empty".to_string()); return Err("key must not be empty".to_string());
} }
} }
RuntimeEffect::SetEconomicStatusCode { .. } => {} RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
| RuntimeEffect::SetEconomicStatusCode { .. } => {}
RuntimeEffect::SetCompanyCash { target, .. } RuntimeEffect::SetCompanyCash { target, .. }
| RuntimeEffect::ConfiscateCompanyAssets { target } | RuntimeEffect::ConfiscateCompanyAssets { target }
| RuntimeEffect::DeactivateCompany { target } | RuntimeEffect::DeactivateCompany { target }
@ -1437,6 +1443,7 @@ mod tests {
disable_train_crashes_enabled: Some(false), disable_train_crashes_enabled: Some(false),
disable_train_crashes_and_breakdowns_enabled: Some(false), disable_train_crashes_and_breakdowns_enabled: Some(false),
ai_ignore_territories_at_startup_enabled: Some(false), ai_ignore_territories_at_startup_enabled: Some(false),
limited_track_building_amount: None,
economic_status_code: None, economic_status_code: None,
absolute_counter_restore_kind: Some( absolute_counter_restore_kind: Some(
"mode-adjusted-selected-year-lane".to_string(), "mode-adjusted-selected-year-lane".to_string(),

View file

@ -2785,9 +2785,31 @@ 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_scalar_descriptor_metadata(descriptor_id))
.or_else(|| special_condition_world_toggle_descriptor_metadata(descriptor_id)) .or_else(|| special_condition_world_toggle_descriptor_metadata(descriptor_id))
} }
fn special_condition_world_scalar_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
let slot_index = descriptor_id.checked_sub(110)? as usize;
if slot_index != 12 {
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_track_build_limit_scalar",
runtime_key: None,
executable_in_runtime: true,
})
}
fn special_condition_world_toggle_descriptor_metadata( fn special_condition_world_toggle_descriptor_metadata(
descriptor_id: u32, descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> { ) -> Option<RealGroupedEffectDescriptorMetadata> {
@ -3012,6 +3034,15 @@ fn decode_real_grouped_effect_action(
}); });
} }
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 122
&& row.row_shape == "scalar_assignment"
{
return Some(RuntimeEffect::SetLimitedTrackBuildingAmount {
value: row.raw_scalar_value,
});
}
if descriptor_metadata.executable_in_runtime if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "world_flag_toggle" && descriptor_metadata.parameter_family == "world_flag_toggle"
&& row.row_shape == "bool_toggle" && row.row_shape == "bool_toggle"
@ -3256,6 +3287,7 @@ fn parse_optional_u16_len_prefixed_string(
fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool { fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
match effect { match effect {
RuntimeEffect::SetWorldFlag { .. } RuntimeEffect::SetWorldFlag { .. }
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
| RuntimeEffect::SetEconomicStatusCode { .. } | RuntimeEffect::SetEconomicStatusCode { .. }
| RuntimeEffect::SetCandidateAvailability { .. } | RuntimeEffect::SetCandidateAvailability { .. }
| RuntimeEffect::SetSpecialCondition { .. } | RuntimeEffect::SetSpecialCondition { .. }
@ -9030,6 +9062,17 @@ mod tests {
assert!(metadata.executable_in_runtime); assert!(metadata.executable_in_runtime);
} }
#[test]
fn looks_up_limited_track_building_amount_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(122).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Limited Track Building Amount");
assert_eq!(metadata.parameter_family, "world_track_build_limit_scalar");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test] #[test]
fn looks_up_recovered_late_world_toggle_descriptor_metadata() { fn looks_up_recovered_late_world_toggle_descriptor_metadata() {
let metadata = let metadata =
@ -9276,6 +9319,77 @@ mod tests {
assert!(summary.records[0].executable_import_ready); assert!(summary.records[0].executable_import_ready);
} }
#[test]
fn decodes_limited_track_building_amount_descriptor_family() {
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 122,
opcode: 3,
raw_scalar_value: 18,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
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: 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],
}),
&[],
[&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("Limited Track Building Amount")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.parameter_family
.as_deref(),
Some("world_track_build_limit_scalar")
);
assert_eq!(
summary.records[0].decoded_actions,
vec![RuntimeEffect::SetLimitedTrackBuildingAmount { value: 18 }]
);
assert!(summary.records[0].executable_import_ready);
}
#[test] #[test]
fn decodes_recovered_late_world_toggle_descriptor_family() { fn decodes_recovered_late_world_toggle_descriptor_family() {
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec { let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {

View file

@ -311,6 +311,9 @@ fn apply_runtime_effects(
RuntimeEffect::SetWorldFlag { key, value } => { RuntimeEffect::SetWorldFlag { key, value } => {
state.world_flags.insert(key.clone(), *value); state.world_flags.insert(key.clone(), *value);
} }
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
state.world_restore.limited_track_building_amount = Some(*value);
}
RuntimeEffect::SetEconomicStatusCode { value } => { RuntimeEffect::SetEconomicStatusCode { value } => {
state.world_restore.economic_status_code = Some(*value); state.world_restore.economic_status_code = Some(*value);
} }
@ -2375,6 +2378,32 @@ mod tests {
assert_eq!(state.world_restore.economic_status_code, Some(3)); assert_eq!(state.world_restore.economic_status_code, Some(3));
} }
#[test]
fn applies_limited_track_building_amount_effect() {
let mut state = RuntimeState {
event_runtime_records: vec![RuntimeEventRecord {
record_id: 91,
trigger_kind: 6,
active: true,
service_count: 0,
marks_collection_dirty: false,
one_shot: false,
has_fired: false,
conditions: Vec::new(),
effects: vec![RuntimeEffect::SetLimitedTrackBuildingAmount { value: 18 }],
}],
..state()
};
execute_step_command(
&mut state,
&StepCommand::ServiceTriggerKind { trigger_kind: 6 },
)
.expect("limited-track-building-amount effect should succeed");
assert_eq!(state.world_restore.limited_track_building_amount, Some(18));
}
#[test] #[test]
fn confiscate_company_assets_zeros_company_and_retires_owned_trains() { fn confiscate_company_assets_zeros_company_and_retires_owned_trains() {
let mut state = RuntimeState { let mut state = RuntimeState {

View file

@ -24,6 +24,7 @@ pub struct RuntimeSummary {
pub world_restore_disable_train_crashes_enabled: Option<bool>, pub world_restore_disable_train_crashes_enabled: Option<bool>,
pub world_restore_disable_train_crashes_and_breakdowns_enabled: Option<bool>, pub world_restore_disable_train_crashes_and_breakdowns_enabled: Option<bool>,
pub world_restore_ai_ignore_territories_at_startup_enabled: Option<bool>, pub world_restore_ai_ignore_territories_at_startup_enabled: Option<bool>,
pub world_restore_limited_track_building_amount: Option<i32>,
pub world_restore_economic_status_code: Option<i32>, pub world_restore_economic_status_code: Option<i32>,
pub world_restore_absolute_counter_restore_kind: Option<String>, pub world_restore_absolute_counter_restore_kind: Option<String>,
pub world_restore_absolute_counter_adjustment_context: Option<String>, pub world_restore_absolute_counter_adjustment_context: Option<String>,
@ -139,6 +140,9 @@ impl RuntimeSummary {
world_restore_ai_ignore_territories_at_startup_enabled: state world_restore_ai_ignore_territories_at_startup_enabled: state
.world_restore .world_restore
.ai_ignore_territories_at_startup_enabled, .ai_ignore_territories_at_startup_enabled,
world_restore_limited_track_building_amount: state
.world_restore
.limited_track_building_amount,
world_restore_economic_status_code: state.world_restore.economic_status_code, world_restore_economic_status_code: state.world_restore.economic_status_code,
world_restore_absolute_counter_restore_kind: state world_restore_absolute_counter_restore_kind: state
.world_restore .world_restore

View file

@ -110,8 +110,9 @@ The highest-value next passes are now:
`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: - 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 descriptors `111..138` now decode through checked-in metadata into either keyed `world_flags`
into keyed `world_flags` for finance/trading, construction, and governance restrictions or the bounded `world_restore.limited_track_building_amount` scalar for finance/trading,
construction, and governance restrictions
- the late recovered world-toggle band now executes too where current evidence is equally strong: - 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`, `Use Bio-Accelerator Cars`, `Disable Cargo Economy`, `Disable Train Crashes`,
`Disable Train Crashes AND Breakdowns`, and `AI Ignore Territories At Startup` `Disable Train Crashes AND Breakdowns`, and `AI Ignore Territories At Startup`

View file

@ -64,9 +64,9 @@ Implemented today:
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: - 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 descriptors `111..138` now lower through checked-in metadata into either keyed `world_flags` or
through checked-in metadata into keyed `world_flags` for finance/trading, construction, and the bounded `world_restore.limited_track_building_amount` scalar for finance/trading,
governance/company-formation restrictions construction, and governance/company-formation restrictions
- the same keyed world-toggle path now also covers the late special-condition band where current - 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`, static evidence stays equally strong: `Use Bio-Accelerator Cars`, `Disable Cargo Economy`,
`Disable Train Crashes`, `Disable Train Crashes AND Breakdowns`, and `Disable Train Crashes`, `Disable Train Crashes AND Breakdowns`, and

View file

@ -0,0 +1,44 @@
{
"format_version": 1,
"fixture_id": "packed-event-world-track-build-limit-save-slice-fixture",
"source": {
"kind": "captured-runtime",
"description": "Fixture proving the recovered Limited Track Building Amount descriptor imports and executes through the ordinary runtime path."
},
"state_save_slice_path": "packed-event-world-track-build-limit-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,
"world_restore_limited_track_building_amount": 18,
"total_event_record_service_count": 1,
"total_trigger_dispatch_count": 1
},
"expected_state_fragment": {
"world_restore": {
"limited_track_building_amount": 18
},
"packed_event_collection": {
"records": [
{
"import_outcome": "imported",
"decoded_actions": [
{
"kind": "set_limited_track_building_amount",
"value": 18
}
]
}
]
}
}
}

View file

@ -0,0 +1,109 @@
{
"format_version": 1,
"save_slice_id": "packed-event-world-track-build-limit-save-slice",
"source": {
"description": "Tracked save-slice document proving the recovered Limited Track Building Amount descriptor imports and executes.",
"original_save_filename": "captured-world-track-build-limit.gms",
"original_save_sha256": "world-track-build-limit-sample-sha256",
"notes": [
"tracked as JSON save-slice document rather than raw .smp",
"descriptor 122 now lowers into the bounded world-restore scalar lane",
"whole-game scalar descriptor sample for Limited Track Building Amount"
]
},
"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": 32000,
"records_tag_offset": 32256,
"close_tag_offset": 33024,
"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": 32320,
"payload_len": 112,
"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": [1, 0, 0, 0],
"grouped_effect_rows": [
{
"group_index": 0,
"row_index": 0,
"descriptor_id": 122,
"descriptor_label": "Limited Track Building Amount",
"target_mask_bits": 8,
"parameter_family": "world_track_build_limit_scalar",
"opcode": 3,
"raw_scalar_value": 18,
"value_byte_0x09": 0,
"value_dword_0x0d": 0,
"value_byte_0x11": 0,
"value_byte_0x12": 0,
"value_word_0x14": 0,
"value_word_0x16": 0,
"row_shape": "scalar_assignment",
"semantic_family": "scalar_assignment",
"semantic_preview": "Set Limited Track Building Amount to 18",
"locomotive_name": null,
"notes": [
"checked-in whole-game scalar descriptor family"
]
}
],
"decoded_conditions": [],
"decoded_actions": [
{
"kind": "set_limited_track_building_amount",
"value": 18
}
],
"executable_import_ready": true,
"notes": [
"checked-in whole-game scalar grouped-effect import sample"
]
}
]
},
"notes": [
"whole-game limited-track-building-amount effect sample"
]
}
}