Execute aggregate cargo economics descriptors

This commit is contained in:
Jan Petykiewicz 2026-04-16 21:42:20 -07:00
commit f623c6dcc9
18 changed files with 1599 additions and 63 deletions

View file

@ -45,7 +45,12 @@ descriptor residue. The recovered whole-game scalar economy/performance strip `5
bounded runtime landing surface too: representative descriptors import into bounded runtime landing surface too: representative descriptors import into
`RuntimeState.world_scalar_overrides` through stable normalized keys such as `RuntimeState.world_scalar_overrides` through stable normalized keys such as
`world.build_stations_cost`, `world.track_maintenance_cost`, `world.all_engine_speeds`, and `world.build_stations_cost`, `world.track_maintenance_cost`, `world.all_engine_speeds`, and
`world.hotel_revenue`. The first grounded `world.hotel_revenue`. The grounded aggregate cargo-economics descriptors now have bounded
runtime landing surfaces too: descriptor `105` `All Cargo Prices` plus descriptors `177..179`
`All Cargo Production` / `All Factory Production` / `All Farm/Mine Production` import into
event-owned cargo override state, while the named cargo-price and named cargo-production strips
remain explicit `blocked_evidence_blocked_descriptor` parity until descriptor ordering is pinned
more strongly. The first grounded
condition-side unlock now exists for negative-sentinel `raw_condition_id = -1` company scopes, and condition-side unlock now exists for negative-sentinel `raw_condition_id = -1` company scopes, and
the first ordinary nonnegative condition batch now executes too: numeric-threshold company the first ordinary nonnegative condition batch now executes too: numeric-threshold company
finance, company track, aggregate territory track, and company-territory track rows can import finance, company track, aggregate territory track, and company-territory track rows can import

View file

@ -954,8 +954,8 @@
"target_mask_bits": 8, "target_mask_bits": 8,
"parameter_family": "cargo_price_scalar", "parameter_family": "cargo_price_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 106, "descriptor_id": 106,
@ -1602,8 +1602,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 178, "descriptor_id": 178,
@ -1611,8 +1611,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 179, "descriptor_id": 179,
@ -1620,8 +1620,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 180, "descriptor_id": 180,
@ -2079,8 +2079,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 231, "descriptor_id": 231,
@ -2088,8 +2088,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 232, "descriptor_id": 232,
@ -2097,8 +2097,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 233, "descriptor_id": 233,
@ -2106,8 +2106,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 234, "descriptor_id": 234,
@ -2115,8 +2115,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 235, "descriptor_id": 235,
@ -2124,8 +2124,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 236, "descriptor_id": 236,
@ -2133,8 +2133,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 237, "descriptor_id": 237,
@ -2142,8 +2142,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 238, "descriptor_id": 238,
@ -2151,8 +2151,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 239, "descriptor_id": 239,
@ -2160,8 +2160,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 240, "descriptor_id": 240,
@ -2169,8 +2169,8 @@
"target_mask_bits": 15, "target_mask_bits": 15,
"parameter_family": "cargo_production_scalar", "parameter_family": "cargo_production_scalar",
"runtime_key": null, "runtime_key": null,
"runtime_status": "evidence_blocked", "runtime_status": "executable",
"executable_in_runtime": false "executable_in_runtime": true
}, },
{ {
"descriptor_id": 241, "descriptor_id": 241,

View file

@ -4479,6 +4479,11 @@ mod tests {
let world_scalar_override_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join( let world_scalar_override_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../fixtures/runtime/packed-event-world-scalar-override-save-slice-fixture.json", "../../fixtures/runtime/packed-event-world-scalar-override-save-slice-fixture.json",
); );
let cargo_economics_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../fixtures/runtime/packed-event-cargo-economics-save-slice-fixture.json");
let cargo_economics_parity_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../fixtures/runtime/packed-event-cargo-economics-parity-save-slice-fixture.json",
);
let world_scalar_condition_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join( let world_scalar_condition_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../fixtures/runtime/packed-event-world-scalar-condition-save-slice-fixture.json", "../../fixtures/runtime/packed-event-world-scalar-condition-save-slice-fixture.json",
); );
@ -4590,6 +4595,10 @@ mod tests {
.expect("save-slice-backed executable world-scalar fixture should summarize"); .expect("save-slice-backed executable world-scalar fixture should summarize");
run_runtime_summarize_fixture(&world_scalar_override_fixture) run_runtime_summarize_fixture(&world_scalar_override_fixture)
.expect("save-slice-backed world-scalar override fixture should summarize"); .expect("save-slice-backed world-scalar override fixture should summarize");
run_runtime_summarize_fixture(&cargo_economics_fixture)
.expect("save-slice-backed cargo-economics fixture should summarize");
run_runtime_summarize_fixture(&cargo_economics_parity_fixture)
.expect("save-slice-backed cargo-economics parity fixture should summarize");
run_runtime_summarize_fixture(&world_scalar_condition_fixture) run_runtime_summarize_fixture(&world_scalar_condition_fixture)
.expect("save-slice-backed executable world-scalar condition fixture should summarize"); .expect("save-slice-backed executable world-scalar condition fixture should summarize");
run_runtime_summarize_fixture(&world_scalar_condition_parity_fixture) run_runtime_summarize_fixture(&world_scalar_condition_parity_fixture)

View file

@ -189,6 +189,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -377,6 +383,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),

View file

@ -5,10 +5,11 @@ use serde::{Deserialize, Serialize};
use crate::persistence::{load_runtime_snapshot_document, validate_runtime_snapshot_document}; use crate::persistence::{load_runtime_snapshot_document, validate_runtime_snapshot_document};
use crate::{ use crate::{
CalendarPoint, RuntimeCargoCatalogEntry, RuntimeChairmanProfile, RuntimeChairmanTarget, CalendarPoint, RuntimeCargoCatalogEntry, RuntimeCargoPriceTarget, RuntimeCargoProductionTarget,
RuntimeCompany, RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind, RuntimeChairmanProfile, RuntimeChairmanTarget, RuntimeCompany,
RuntimeCompanyTarget, RuntimeCondition, RuntimeEffect, RuntimeEventRecord, RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind, RuntimeCompanyTarget,
RuntimeEventRecordTemplate, RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary, RuntimeCondition, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate,
RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary,
RuntimePackedEventCompactControlSummary, RuntimePackedEventConditionRowSummary, RuntimePackedEventCompactControlSummary, RuntimePackedEventConditionRowSummary,
RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventNegativeSentinelScopeSummary, RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventNegativeSentinelScopeSummary,
RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary, RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary,
@ -105,6 +106,12 @@ struct SaveSliceProjection {
locomotive_catalog: Option<Vec<RuntimeLocomotiveCatalogEntry>>, locomotive_catalog: Option<Vec<RuntimeLocomotiveCatalogEntry>>,
cargo_catalog: Option<Vec<RuntimeCargoCatalogEntry>>, cargo_catalog: Option<Vec<RuntimeCargoCatalogEntry>>,
named_locomotive_cost: BTreeMap<String, u32>, named_locomotive_cost: BTreeMap<String, u32>,
all_cargo_price_override: Option<u32>,
named_cargo_price_overrides: BTreeMap<String, u32>,
all_cargo_production_override: Option<u32>,
factory_cargo_production_override: Option<u32>,
farm_mine_cargo_production_override: Option<u32>,
named_cargo_production_overrides: BTreeMap<String, u32>,
cargo_production_overrides: BTreeMap<u32, u32>, cargo_production_overrides: BTreeMap<u32, u32>,
world_scalar_overrides: BTreeMap<String, i64>, world_scalar_overrides: BTreeMap<String, i64>,
special_conditions: BTreeMap<String, u32>, special_conditions: BTreeMap<String, u32>,
@ -277,6 +284,12 @@ pub fn project_save_slice_to_runtime_state_import(
candidate_availability: projection.candidate_availability, candidate_availability: projection.candidate_availability,
named_locomotive_availability: projection.named_locomotive_availability, named_locomotive_availability: projection.named_locomotive_availability,
named_locomotive_cost: projection.named_locomotive_cost, named_locomotive_cost: projection.named_locomotive_cost,
all_cargo_price_override: projection.all_cargo_price_override,
named_cargo_price_overrides: projection.named_cargo_price_overrides,
all_cargo_production_override: projection.all_cargo_production_override,
factory_cargo_production_override: projection.factory_cargo_production_override,
farm_mine_cargo_production_override: projection.farm_mine_cargo_production_override,
named_cargo_production_overrides: projection.named_cargo_production_overrides,
cargo_production_overrides: projection.cargo_production_overrides, cargo_production_overrides: projection.cargo_production_overrides,
world_scalar_overrides: projection.world_scalar_overrides, world_scalar_overrides: projection.world_scalar_overrides,
special_conditions: projection.special_conditions, special_conditions: projection.special_conditions,
@ -365,6 +378,12 @@ pub fn project_save_slice_overlay_to_runtime_state_import(
candidate_availability: projection.candidate_availability, candidate_availability: projection.candidate_availability,
named_locomotive_availability: projection.named_locomotive_availability, named_locomotive_availability: projection.named_locomotive_availability,
named_locomotive_cost: base_state.named_locomotive_cost.clone(), named_locomotive_cost: base_state.named_locomotive_cost.clone(),
all_cargo_price_override: base_state.all_cargo_price_override,
named_cargo_price_overrides: base_state.named_cargo_price_overrides.clone(),
all_cargo_production_override: base_state.all_cargo_production_override,
factory_cargo_production_override: base_state.factory_cargo_production_override,
farm_mine_cargo_production_override: base_state.farm_mine_cargo_production_override,
named_cargo_production_overrides: base_state.named_cargo_production_overrides.clone(),
cargo_production_overrides: base_state.cargo_production_overrides.clone(), cargo_production_overrides: base_state.cargo_production_overrides.clone(),
world_scalar_overrides: base_state.world_scalar_overrides.clone(), world_scalar_overrides: base_state.world_scalar_overrides.clone(),
special_conditions: projection.special_conditions, special_conditions: projection.special_conditions,
@ -874,6 +893,12 @@ fn project_save_slice_components(
}; };
let named_locomotive_cost = BTreeMap::new(); let named_locomotive_cost = BTreeMap::new();
let all_cargo_price_override = None;
let named_cargo_price_overrides = BTreeMap::new();
let all_cargo_production_override = None;
let factory_cargo_production_override = None;
let farm_mine_cargo_production_override = None;
let named_cargo_production_overrides = BTreeMap::new();
let cargo_production_overrides = BTreeMap::new(); let cargo_production_overrides = BTreeMap::new();
let world_scalar_overrides = BTreeMap::new(); let world_scalar_overrides = BTreeMap::new();
@ -951,6 +976,12 @@ fn project_save_slice_components(
locomotive_catalog, locomotive_catalog,
cargo_catalog, cargo_catalog,
named_locomotive_cost, named_locomotive_cost,
all_cargo_price_override,
named_cargo_price_overrides,
all_cargo_production_override,
factory_cargo_production_override,
farm_mine_cargo_production_override,
named_cargo_production_overrides,
cargo_production_overrides, cargo_production_overrides,
world_scalar_overrides, world_scalar_overrides,
special_conditions, special_conditions,
@ -1321,6 +1352,10 @@ fn lower_contextual_real_grouped_effects(
if real_grouped_row_is_unsupported_chairman_target_scope(row) { if real_grouped_row_is_unsupported_chairman_target_scope(row) {
return Err(ImportBlocker::ChairmanTargetScope); return Err(ImportBlocker::ChairmanTargetScope);
} }
if let Some(effect) = lower_contextual_cargo_price_effect(row)? {
effects.push(effect);
continue;
}
if let Some(effect) = lower_contextual_world_scalar_override_effect(row)? { if let Some(effect) = lower_contextual_world_scalar_override_effect(row)? {
effects.push(effect); effects.push(effect);
continue; continue;
@ -1356,6 +1391,27 @@ fn lower_contextual_real_grouped_effects(
Ok(effects) Ok(effects)
} }
fn lower_contextual_cargo_price_effect(
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
) -> Result<Option<RuntimeEffect>, ImportBlocker> {
if row.parameter_family.as_deref() != Some("cargo_price_scalar") {
return Ok(None);
}
if row.row_shape != "scalar_assignment" {
return Ok(None);
}
let Some(value) = u32::try_from(row.raw_scalar_value).ok() else {
return Ok(None);
};
if row.descriptor_id != 105 {
return Ok(None);
}
Ok(Some(RuntimeEffect::SetCargoPriceOverride {
target: RuntimeCargoPriceTarget::All,
value,
}))
}
fn lower_contextual_world_scalar_override_effect( fn lower_contextual_world_scalar_override_effect(
row: &SmpLoadedPackedEventGroupedEffectRowSummary, row: &SmpLoadedPackedEventGroupedEffectRowSummary,
) -> Result<Option<RuntimeEffect>, ImportBlocker> { ) -> Result<Option<RuntimeEffect>, ImportBlocker> {
@ -1419,13 +1475,27 @@ fn lower_contextual_cargo_production_effect(
let Some(value) = u32::try_from(row.raw_scalar_value).ok() else { let Some(value) = u32::try_from(row.raw_scalar_value).ok() else {
return Ok(None); return Ok(None);
}; };
let Some(slot) = row.descriptor_id.checked_sub(229) else { match row.descriptor_id {
return Ok(None); 177 => Ok(Some(RuntimeEffect::SetCargoProductionOverride {
}; target: RuntimeCargoProductionTarget::All,
if !(1..=11).contains(&slot) { value,
return Ok(None); })),
178 => Ok(Some(RuntimeEffect::SetCargoProductionOverride {
target: RuntimeCargoProductionTarget::Factory,
value,
})),
179 => Ok(Some(RuntimeEffect::SetCargoProductionOverride {
target: RuntimeCargoProductionTarget::FarmMine,
value,
})),
230..=240 => {
let Some(slot) = row.descriptor_id.checked_sub(229) else {
return Ok(None);
};
Ok(Some(RuntimeEffect::SetCargoProductionSlot { slot, value }))
}
_ => Ok(None),
} }
Ok(Some(RuntimeEffect::SetCargoProductionSlot { slot, value }))
} }
fn lower_contextual_territory_access_cost_effect( fn lower_contextual_territory_access_cost_effect(
@ -1736,6 +1806,18 @@ fn lower_condition_targets_in_effect(
value: *value, value: *value,
} }
} }
RuntimeEffect::SetCargoPriceOverride { target, value } => {
RuntimeEffect::SetCargoPriceOverride {
target: target.clone(),
value: *value,
}
}
RuntimeEffect::SetCargoProductionOverride { target, value } => {
RuntimeEffect::SetCargoProductionOverride {
target: target.clone(),
value: *value,
}
}
RuntimeEffect::SetCargoProductionSlot { slot, value } => { RuntimeEffect::SetCargoProductionSlot { slot, value } => {
RuntimeEffect::SetCargoProductionSlot { RuntimeEffect::SetCargoProductionSlot {
slot: *slot, slot: *slot,
@ -2383,6 +2465,18 @@ fn smp_runtime_effect_to_runtime_effect(
value: *value, value: *value,
}) })
} }
RuntimeEffect::SetCargoPriceOverride { target, value } => {
Ok(RuntimeEffect::SetCargoPriceOverride {
target: target.clone(),
value: *value,
})
}
RuntimeEffect::SetCargoProductionOverride { target, value } => {
Ok(RuntimeEffect::SetCargoProductionOverride {
target: target.clone(),
value: *value,
})
}
RuntimeEffect::SetWorldScalarOverride { key, value } => { RuntimeEffect::SetWorldScalarOverride { key, value } => {
Ok(RuntimeEffect::SetWorldScalarOverride { Ok(RuntimeEffect::SetWorldScalarOverride {
key: key.clone(), key: key.clone(),
@ -2888,10 +2982,21 @@ fn real_grouped_row_is_unsupported_executable_descriptor_variant(
8 | 108 | 109 | 122 => row.row_shape != "scalar_assignment", 8 | 108 | 109 | 122 => row.row_shape != "scalar_assignment",
13 | 14 => !(row.row_shape == "bool_toggle" && row.raw_scalar_value != 0), 13 | 14 => !(row.row_shape == "bool_toggle" && row.raw_scalar_value != 0),
56 | 57 => row.row_shape != "scalar_assignment", 56 | 57 => row.row_shape != "scalar_assignment",
_ => { _ => match row.parameter_family.as_deref() {
row.parameter_family.as_deref() == Some("world_scalar_override") Some("world_scalar_override") => row.row_shape != "scalar_assignment",
&& row.row_shape != "scalar_assignment" Some("cargo_price_scalar") => {
} row.descriptor_id == 105
&& !(row.row_shape == "scalar_assignment" && row.raw_scalar_value >= 0)
}
Some("cargo_production_scalar") => {
matches!(row.descriptor_id, 177 | 178 | 179 | 230..=240)
&& !(row.row_shape == "scalar_assignment" && row.raw_scalar_value >= 0)
}
Some("territory_access_cost_scalar") => {
!(row.row_shape == "scalar_assignment" && row.raw_scalar_value >= 0)
}
_ => false,
},
} }
} }
@ -3093,6 +3198,8 @@ fn runtime_effect_uses_condition_true_company(effect: &RuntimeEffect) -> bool {
| RuntimeEffect::SetNamedLocomotiveAvailability { .. } | RuntimeEffect::SetNamedLocomotiveAvailability { .. }
| RuntimeEffect::SetNamedLocomotiveAvailabilityValue { .. } | RuntimeEffect::SetNamedLocomotiveAvailabilityValue { .. }
| RuntimeEffect::SetNamedLocomotiveCost { .. } | RuntimeEffect::SetNamedLocomotiveCost { .. }
| RuntimeEffect::SetCargoPriceOverride { .. }
| RuntimeEffect::SetCargoProductionOverride { .. }
| RuntimeEffect::SetCargoProductionSlot { .. } | RuntimeEffect::SetCargoProductionSlot { .. }
| RuntimeEffect::SetTerritoryAccessCost { .. } | RuntimeEffect::SetTerritoryAccessCost { .. }
| RuntimeEffect::SetSpecialCondition { .. } | RuntimeEffect::SetSpecialCondition { .. }
@ -3203,6 +3310,8 @@ fn runtime_effect_company_target_import_blocker(
| RuntimeEffect::SetNamedLocomotiveAvailability { .. } | RuntimeEffect::SetNamedLocomotiveAvailability { .. }
| RuntimeEffect::SetNamedLocomotiveAvailabilityValue { .. } | RuntimeEffect::SetNamedLocomotiveAvailabilityValue { .. }
| RuntimeEffect::SetNamedLocomotiveCost { .. } | RuntimeEffect::SetNamedLocomotiveCost { .. }
| RuntimeEffect::SetCargoPriceOverride { .. }
| RuntimeEffect::SetCargoProductionOverride { .. }
| RuntimeEffect::SetCargoProductionSlot { .. } | RuntimeEffect::SetCargoProductionSlot { .. }
| RuntimeEffect::SetTerritoryAccessCost { .. } | RuntimeEffect::SetTerritoryAccessCost { .. }
| RuntimeEffect::SetSpecialCondition { .. } | RuntimeEffect::SetSpecialCondition { .. }
@ -3552,6 +3661,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -4299,6 +4414,145 @@ mod tests {
} }
} }
fn real_all_cargo_price_row(value: i32) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary {
crate::SmpLoadedPackedEventGroupedEffectRowSummary {
group_index: 0,
row_index: 0,
descriptor_id: 105,
descriptor_label: Some("All Cargo Prices".to_string()),
target_mask_bits: Some(0x08),
parameter_family: Some("cargo_price_scalar".to_string()),
grouped_target_subject: None,
grouped_target_scope: None,
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 All Cargo Prices to {value}")),
recovered_cargo_slot: None,
recovered_cargo_class: None,
recovered_locomotive_id: None,
locomotive_name: None,
notes: vec![
"descriptor recovered from checked-in EventEffects semantic catalog".to_string(),
],
}
}
fn real_named_cargo_price_row(
descriptor_id: u32,
value: i32,
) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary {
crate::SmpLoadedPackedEventGroupedEffectRowSummary {
group_index: 0,
row_index: 0,
descriptor_id,
descriptor_label: Some("Unknown Cargo Price".to_string()),
target_mask_bits: Some(0x08),
parameter_family: Some("cargo_price_scalar".to_string()),
grouped_target_subject: None,
grouped_target_scope: None,
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 Unknown Cargo Price to {value}")),
recovered_cargo_slot: None,
recovered_cargo_class: None,
recovered_locomotive_id: None,
locomotive_name: None,
notes: vec![
"descriptor recovered from checked-in EventEffects semantic catalog".to_string(),
],
}
}
fn real_aggregate_cargo_production_row(
descriptor_id: u32,
value: i32,
) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary {
let (label, recovered_cargo_class) = match descriptor_id {
177 => ("All Cargo Production", None),
178 => ("All Factory Production", Some("factory".to_string())),
179 => ("All Farm/Mine Production", Some("farm_mine".to_string())),
_ => ("Unknown Cargo Production", None),
};
crate::SmpLoadedPackedEventGroupedEffectRowSummary {
group_index: 0,
row_index: 0,
descriptor_id,
descriptor_label: Some(label.to_string()),
target_mask_bits: Some(0x08),
parameter_family: Some("cargo_production_scalar".to_string()),
grouped_target_subject: None,
grouped_target_scope: None,
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 {label} to {value}")),
recovered_cargo_slot: None,
recovered_cargo_class,
recovered_locomotive_id: None,
locomotive_name: None,
notes: vec![
"descriptor recovered from checked-in EventEffects semantic catalog".to_string(),
],
}
}
fn real_named_cargo_production_row(
descriptor_id: u32,
value: i32,
) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary {
crate::SmpLoadedPackedEventGroupedEffectRowSummary {
group_index: 0,
row_index: 0,
descriptor_id,
descriptor_label: Some("Unknown Cargo Production".to_string()),
target_mask_bits: Some(0x08),
parameter_family: Some("cargo_production_scalar".to_string()),
grouped_target_subject: None,
grouped_target_scope: None,
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 Unknown Cargo Production to {value}")),
recovered_cargo_slot: None,
recovered_cargo_class: None,
recovered_locomotive_id: None,
locomotive_name: None,
notes: vec![
"descriptor recovered from checked-in EventEffects semantic catalog".to_string(),
],
}
}
fn real_territory_access_cost_row( fn real_territory_access_cost_row(
value: i32, value: i32,
) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary { ) -> crate::SmpLoadedPackedEventGroupedEffectRowSummary {
@ -6738,6 +6992,12 @@ mod tests {
("Locomotive 112".to_string(), 1), ("Locomotive 112".to_string(), 1),
]), ]),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -7144,6 +7404,12 @@ mod tests {
("Locomotive 1".to_string(), 100000), ("Locomotive 1".to_string(), 100000),
("Locomotive 101".to_string(), 200000), ("Locomotive 101".to_string(), 200000),
]), ]),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -7409,6 +7675,337 @@ mod tests {
assert_eq!(import.state.cargo_production_overrides.get(&1), Some(&125)); assert_eq!(import.state.cargo_production_overrides.get(&1), Some(&125));
} }
#[test]
fn imports_aggregate_cargo_economics_rows_into_runtime_records() {
let save_slice = SmpLoadedSaveSlice {
file_extension_hint: Some("gms".to_string()),
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
trailer_family: None,
bridge_family: None,
profile: None,
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
company_roster: None,
chairman_profile_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: 38,
live_record_count: 1,
live_entry_ids: vec![38],
decoded_record_count: 1,
imported_runtime_record_count: 0,
records: vec![crate::SmpLoadedPackedEventRecordSummary {
record_index: 0,
live_entry_id: 38,
payload_offset: Some(0x7202),
payload_len: Some(144),
decode_status: "parity_only".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: vec![],
standalone_condition_row_count: 0,
standalone_condition_rows: vec![],
negative_sentinel_scope: None,
grouped_effect_row_counts: vec![4, 0, 0, 0],
grouped_effect_rows: vec![
real_all_cargo_price_row(180),
real_aggregate_cargo_production_row(177, 210),
real_aggregate_cargo_production_row(178, 225),
real_aggregate_cargo_production_row(179, 175),
],
decoded_conditions: Vec::new(),
decoded_actions: vec![],
executable_import_ready: false,
notes: vec![
"grounded aggregate cargo economics descriptors import through bounded override surfaces"
.to_string(),
],
}],
}),
notes: vec![],
};
let mut import = project_save_slice_to_runtime_state_import(
&save_slice,
"packed-events-aggregate-cargo-economics",
None,
)
.expect("save slice should project");
assert_eq!(import.state.event_runtime_records.len(), 1);
assert_eq!(
import
.state
.packed_event_collection
.as_ref()
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
Some("imported")
);
execute_step_command(
&mut import.state,
&StepCommand::ServiceTriggerKind { trigger_kind: 7 },
)
.expect("aggregate cargo economics runtime record should run");
assert_eq!(import.state.all_cargo_price_override, Some(180));
assert_eq!(import.state.all_cargo_production_override, Some(210));
assert_eq!(import.state.factory_cargo_production_override, Some(225));
assert_eq!(import.state.farm_mine_cargo_production_override, Some(175));
}
#[test]
fn keeps_named_cargo_price_rows_evidence_blocked() {
let save_slice = SmpLoadedSaveSlice {
file_extension_hint: Some("gms".to_string()),
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
trailer_family: None,
bridge_family: None,
profile: None,
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
company_roster: None,
chairman_profile_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: 39,
live_record_count: 1,
live_entry_ids: vec![39],
decoded_record_count: 1,
imported_runtime_record_count: 0,
records: vec![crate::SmpLoadedPackedEventRecordSummary {
record_index: 0,
live_entry_id: 39,
payload_offset: Some(0x7202),
payload_len: Some(96),
decode_status: "parity_only".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: vec![],
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_named_cargo_price_row(106, 140)],
decoded_conditions: Vec::new(),
decoded_actions: vec![],
executable_import_ready: false,
notes: vec!["named cargo price descriptors remain evidence-blocked until cargo ordering is pinned"
.to_string()],
}],
}),
notes: vec![],
};
let import = project_save_slice_to_runtime_state_import(
&save_slice,
"packed-events-named-cargo-price-parity",
None,
)
.expect("save slice should project");
assert!(import.state.event_runtime_records.is_empty());
assert_eq!(
import
.state
.packed_event_collection
.as_ref()
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
Some("blocked_evidence_blocked_descriptor")
);
}
#[test]
fn keeps_named_cargo_production_rows_evidence_blocked() {
let save_slice = SmpLoadedSaveSlice {
file_extension_hint: Some("gms".to_string()),
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
trailer_family: None,
bridge_family: None,
profile: None,
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
company_roster: None,
chairman_profile_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: 40,
live_record_count: 1,
live_entry_ids: vec![40],
decoded_record_count: 1,
imported_runtime_record_count: 0,
records: vec![crate::SmpLoadedPackedEventRecordSummary {
record_index: 0,
live_entry_id: 40,
payload_offset: Some(0x7202),
payload_len: Some(96),
decode_status: "parity_only".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: vec![],
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_named_cargo_production_row(180, 160)],
decoded_conditions: Vec::new(),
decoded_actions: vec![],
executable_import_ready: false,
notes: vec!["named cargo production descriptors remain evidence-blocked until cargo ordering is pinned"
.to_string()],
}],
}),
notes: vec![],
};
let import = project_save_slice_to_runtime_state_import(
&save_slice,
"packed-events-named-cargo-production-parity",
None,
)
.expect("save slice should project");
assert!(import.state.event_runtime_records.is_empty());
assert_eq!(
import
.state
.packed_event_collection
.as_ref()
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
Some("blocked_evidence_blocked_descriptor")
);
}
#[test]
fn keeps_negative_all_cargo_price_rows_variant_blocked() {
let save_slice = SmpLoadedSaveSlice {
file_extension_hint: Some("gms".to_string()),
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
trailer_family: None,
bridge_family: None,
profile: None,
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
company_roster: None,
chairman_profile_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: 41,
live_record_count: 1,
live_entry_ids: vec![41],
decoded_record_count: 1,
imported_runtime_record_count: 0,
records: vec![crate::SmpLoadedPackedEventRecordSummary {
record_index: 0,
live_entry_id: 41,
payload_offset: Some(0x7202),
payload_len: Some(96),
decode_status: "parity_only".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: vec![],
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_all_cargo_price_row(-1)],
decoded_conditions: Vec::new(),
decoded_actions: vec![],
executable_import_ready: false,
notes: vec![
"negative aggregate cargo price variants remain parity-only".to_string(),
],
}],
}),
notes: vec![],
};
let import = project_save_slice_to_runtime_state_import(
&save_slice,
"packed-events-negative-all-cargo-price",
None,
)
.expect("save slice should project");
assert!(import.state.event_runtime_records.is_empty());
assert_eq!(
import
.state
.packed_event_collection
.as_ref()
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
Some("blocked_variant_or_scope_blocked_descriptor")
);
}
#[test] #[test]
fn imports_recovered_territory_access_cost_rows_into_runtime_records() { fn imports_recovered_territory_access_cost_rows_into_runtime_records() {
let save_slice = SmpLoadedSaveSlice { let save_slice = SmpLoadedSaveSlice {
@ -7545,6 +8142,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -9820,6 +10423,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -9994,6 +10603,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -11683,6 +12298,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -11868,6 +12489,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),

View file

@ -35,7 +35,8 @@ pub use pk4::{
extract_pk4_entry_bytes, extract_pk4_entry_file, inspect_pk4_bytes, inspect_pk4_file, extract_pk4_entry_bytes, extract_pk4_entry_file, inspect_pk4_bytes, inspect_pk4_file,
}; };
pub use runtime::{ pub use runtime::{
RuntimeCargoCatalogEntry, RuntimeCargoClass, RuntimeChairmanMetric, RuntimeChairmanProfile, RuntimeCargoCatalogEntry, RuntimeCargoClass, RuntimeCargoPriceTarget,
RuntimeCargoProductionTarget, RuntimeChairmanMetric, RuntimeChairmanProfile,
RuntimeChairmanTarget, RuntimeCompany, RuntimeCompanyConditionTestScope, RuntimeChairmanTarget, RuntimeCompany, RuntimeCompanyConditionTestScope,
RuntimeCompanyControllerKind, RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCompanyControllerKind, RuntimeCompanyMetric, RuntimeCompanyTarget,
RuntimeCompanyTerritoryAccess, RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition, RuntimeCompanyTerritoryAccess, RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition,

View file

@ -109,6 +109,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),

View file

@ -203,6 +203,22 @@ pub enum RuntimeChairmanTarget {
Ids { ids: Vec<u32> }, Ids { ids: Vec<u32> },
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum RuntimeCargoPriceTarget {
All,
Named { name: String },
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum RuntimeCargoProductionTarget {
All,
Factory,
FarmMine,
Named { name: String },
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")] #[serde(tag = "kind", rename_all = "snake_case")]
pub enum RuntimeTerritoryTarget { pub enum RuntimeTerritoryTarget {
@ -463,6 +479,14 @@ pub enum RuntimeEffect {
name: String, name: String,
value: u32, value: u32,
}, },
SetCargoPriceOverride {
target: RuntimeCargoPriceTarget,
value: u32,
},
SetCargoProductionOverride {
target: RuntimeCargoProductionTarget,
value: u32,
},
SetCargoProductionSlot { SetCargoProductionSlot {
slot: u32, slot: u32,
value: u32, value: u32,
@ -844,6 +868,18 @@ pub struct RuntimeState {
#[serde(default)] #[serde(default)]
pub named_locomotive_cost: BTreeMap<String, u32>, pub named_locomotive_cost: BTreeMap<String, u32>,
#[serde(default)] #[serde(default)]
pub all_cargo_price_override: Option<u32>,
#[serde(default)]
pub named_cargo_price_overrides: BTreeMap<String, u32>,
#[serde(default)]
pub all_cargo_production_override: Option<u32>,
#[serde(default)]
pub factory_cargo_production_override: Option<u32>,
#[serde(default)]
pub farm_mine_cargo_production_override: Option<u32>,
#[serde(default)]
pub named_cargo_production_overrides: BTreeMap<String, u32>,
#[serde(default)]
pub cargo_production_overrides: BTreeMap<u32, u32>, pub cargo_production_overrides: BTreeMap<u32, u32>,
#[serde(default)] #[serde(default)]
pub world_scalar_overrides: BTreeMap<String, i64>, pub world_scalar_overrides: BTreeMap<String, i64>,
@ -1487,6 +1523,16 @@ impl RuntimeState {
return Err("named_locomotive_cost contains an empty key".to_string()); return Err("named_locomotive_cost contains an empty key".to_string());
} }
} }
for key in self.named_cargo_price_overrides.keys() {
if key.trim().is_empty() {
return Err("named_cargo_price_overrides contains an empty key".to_string());
}
}
for key in self.named_cargo_production_overrides.keys() {
if key.trim().is_empty() {
return Err("named_cargo_production_overrides contains an empty key".to_string());
}
}
for slot in self.cargo_production_overrides.keys() { for slot in self.cargo_production_overrides.keys() {
if !(1..=11).contains(slot) { if !(1..=11).contains(slot) {
return Err(format!( return Err(format!(
@ -1600,6 +1646,24 @@ fn validate_runtime_effect(
return Err("name must not be empty".to_string()); return Err("name must not be empty".to_string());
} }
} }
RuntimeEffect::SetCargoPriceOverride { target, .. } => match target {
RuntimeCargoPriceTarget::All => {}
RuntimeCargoPriceTarget::Named { name } => {
if name.trim().is_empty() {
return Err("name must not be empty".to_string());
}
}
},
RuntimeEffect::SetCargoProductionOverride { target, .. } => match target {
RuntimeCargoProductionTarget::All
| RuntimeCargoProductionTarget::Factory
| RuntimeCargoProductionTarget::FarmMine => {}
RuntimeCargoProductionTarget::Named { name } => {
if name.trim().is_empty() {
return Err("name must not be empty".to_string());
}
}
},
RuntimeEffect::SetCargoProductionSlot { slot, .. } => { RuntimeEffect::SetCargoProductionSlot { slot, .. } => {
if !(1..=11).contains(slot) { if !(1..=11).contains(slot) {
return Err("slot must be in 1..=11".to_string()); return Err("slot must be in 1..=11".to_string());
@ -1916,6 +1980,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -1979,7 +2049,13 @@ mod tests {
event_runtime_records: Vec::new(), event_runtime_records: Vec::new(),
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2048,6 +2124,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2126,6 +2208,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2229,6 +2317,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2284,6 +2378,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2339,6 +2439,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2411,6 +2517,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2473,6 +2585,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2539,6 +2657,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2601,6 +2725,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2669,6 +2799,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2731,6 +2867,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2793,6 +2935,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2848,6 +2996,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -2913,6 +3067,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),

View file

@ -7,11 +7,12 @@ use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use crate::{ use crate::{
RuntimeCargoClass, RuntimeChairmanMetric, RuntimeChairmanTarget, RuntimeCargoClass, RuntimeCargoPriceTarget, RuntimeCargoProductionTarget,
RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind, RuntimeCompanyMetric, RuntimeChairmanMetric, RuntimeChairmanTarget, RuntimeCompanyConditionTestScope,
RuntimeCompanyTarget, RuntimeCondition, RuntimeConditionComparator, RuntimeEffect, RuntimeCompanyControllerKind, RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCondition,
RuntimeEventRecordTemplate, RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecordTemplate,
RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts, RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeTerritoryMetric,
RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts,
}; };
pub const SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION: u32 = 0x03ec; pub const SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION: u32 = 0x03ec;
@ -3656,7 +3657,9 @@ fn real_condition_chairman_target(
fn real_grouped_effect_descriptor_metadata( fn real_grouped_effect_descriptor_metadata(
descriptor_id: u32, descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> { ) -> Option<RealGroupedEffectDescriptorMetadata> {
recovered_cargo_production_descriptor_metadata(descriptor_id) recovered_cargo_price_descriptor_metadata(descriptor_id)
.or_else(|| recovered_cargo_economics_descriptor_metadata(descriptor_id))
.or_else(|| recovered_cargo_production_descriptor_metadata(descriptor_id))
.or_else(|| recovered_locomotive_availability_descriptor_metadata(descriptor_id)) .or_else(|| recovered_locomotive_availability_descriptor_metadata(descriptor_id))
.or_else(|| recovered_locomotive_cost_descriptor_metadata(descriptor_id)) .or_else(|| recovered_locomotive_cost_descriptor_metadata(descriptor_id))
.or_else(|| recovered_territory_access_cost_descriptor_metadata(descriptor_id)) .or_else(|| recovered_territory_access_cost_descriptor_metadata(descriptor_id))
@ -3676,6 +3679,55 @@ fn real_grouped_effect_descriptor_metadata(
}) })
} }
fn recovered_cargo_price_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
(descriptor_id == 105).then_some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "All Cargo Prices",
target_mask_bits: 0x08,
parameter_family: "cargo_price_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
})
}
fn recovered_cargo_economics_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
match descriptor_id {
177 => Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "All Cargo Production",
target_mask_bits: 0x08,
parameter_family: "cargo_production_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
}),
178 => Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "All Factory Production",
target_mask_bits: 0x08,
parameter_family: "cargo_production_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
}),
179 => Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "All Farm/Mine Production",
target_mask_bits: 0x08,
parameter_family: "cargo_production_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
}),
_ => None,
}
}
fn recovered_cargo_production_descriptor_metadata( fn recovered_cargo_production_descriptor_metadata(
descriptor_id: u32, descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> { ) -> Option<RealGroupedEffectDescriptorMetadata> {
@ -4260,16 +4312,45 @@ fn decode_real_grouped_effect_action(
}); });
} }
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "cargo_price_scalar"
&& row.row_shape == "scalar_assignment"
&& row.raw_scalar_value >= 0
&& row.descriptor_id == 105
{
return Some(RuntimeEffect::SetCargoPriceOverride {
target: RuntimeCargoPriceTarget::All,
value: row.raw_scalar_value as u32,
});
}
if descriptor_metadata.executable_in_runtime if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "cargo_production_scalar" && descriptor_metadata.parameter_family == "cargo_production_scalar"
&& row.row_shape == "scalar_assignment" && row.row_shape == "scalar_assignment"
&& row.raw_scalar_value >= 0 && row.raw_scalar_value >= 0
{ {
let slot = descriptor_metadata.descriptor_id.checked_sub(229)?; return match descriptor_metadata.descriptor_id {
return Some(RuntimeEffect::SetCargoProductionSlot { 177 => Some(RuntimeEffect::SetCargoProductionOverride {
slot, target: RuntimeCargoProductionTarget::All,
value: row.raw_scalar_value as u32, value: row.raw_scalar_value as u32,
}); }),
178 => Some(RuntimeEffect::SetCargoProductionOverride {
target: RuntimeCargoProductionTarget::Factory,
value: row.raw_scalar_value as u32,
}),
179 => Some(RuntimeEffect::SetCargoProductionOverride {
target: RuntimeCargoProductionTarget::FarmMine,
value: row.raw_scalar_value as u32,
}),
230..=240 => {
let slot = descriptor_metadata.descriptor_id.checked_sub(229)?;
Some(RuntimeEffect::SetCargoProductionSlot {
slot,
value: row.raw_scalar_value as u32,
})
}
_ => None,
};
} }
if descriptor_metadata.executable_in_runtime if descriptor_metadata.executable_in_runtime
@ -4563,6 +4644,8 @@ fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
| RuntimeEffect::SetNamedLocomotiveAvailability { .. } | RuntimeEffect::SetNamedLocomotiveAvailability { .. }
| RuntimeEffect::SetNamedLocomotiveAvailabilityValue { .. } | RuntimeEffect::SetNamedLocomotiveAvailabilityValue { .. }
| RuntimeEffect::SetNamedLocomotiveCost { .. } | RuntimeEffect::SetNamedLocomotiveCost { .. }
| RuntimeEffect::SetCargoPriceOverride { .. }
| RuntimeEffect::SetCargoProductionOverride { .. }
| RuntimeEffect::SetCargoProductionSlot { .. } | RuntimeEffect::SetCargoProductionSlot { .. }
| RuntimeEffect::SetWorldScalarOverride { .. } | RuntimeEffect::SetWorldScalarOverride { .. }
| RuntimeEffect::SetTerritoryAccessCost { .. } | RuntimeEffect::SetTerritoryAccessCost { .. }
@ -11248,6 +11331,30 @@ mod tests {
assert!(metadata.executable_in_runtime); assert!(metadata.executable_in_runtime);
} }
#[test]
fn looks_up_recovered_all_cargo_price_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(105).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "All Cargo Prices");
assert_eq!(metadata.target_mask_bits, 0x08);
assert_eq!(metadata.parameter_family, "cargo_price_scalar");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_recovered_aggregate_cargo_production_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(177).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "All Cargo Production");
assert_eq!(metadata.target_mask_bits, 0x08);
assert_eq!(metadata.parameter_family, "cargo_production_scalar");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test] #[test]
fn looks_up_recovered_lower_band_locomotive_cost_descriptor_metadata() { fn looks_up_recovered_lower_band_locomotive_cost_descriptor_metadata() {
let metadata = let metadata =

View file

@ -3,7 +3,8 @@ use std::collections::BTreeSet;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
RuntimeCargoClass, RuntimeChairmanMetric, RuntimeChairmanTarget, RuntimeCompanyControllerKind, RuntimeCargoClass, RuntimeCargoPriceTarget, RuntimeCargoProductionTarget,
RuntimeChairmanMetric, RuntimeChairmanTarget, RuntimeCompanyControllerKind,
RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCondition, RuntimeConditionComparator, RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCondition, RuntimeConditionComparator,
RuntimeEffect, RuntimeEventRecordTemplate, RuntimePlayerTarget, RuntimeState, RuntimeSummary, RuntimeEffect, RuntimeEventRecordTemplate, RuntimePlayerTarget, RuntimeState, RuntimeSummary,
RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts, RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts,
@ -606,6 +607,32 @@ fn apply_runtime_effects(
RuntimeEffect::SetNamedLocomotiveCost { name, value } => { RuntimeEffect::SetNamedLocomotiveCost { name, value } => {
state.named_locomotive_cost.insert(name.clone(), *value); state.named_locomotive_cost.insert(name.clone(), *value);
} }
RuntimeEffect::SetCargoPriceOverride { target, value } => match target {
RuntimeCargoPriceTarget::All => {
state.all_cargo_price_override = Some(*value);
}
RuntimeCargoPriceTarget::Named { name } => {
state
.named_cargo_price_overrides
.insert(name.clone(), *value);
}
},
RuntimeEffect::SetCargoProductionOverride { target, value } => match target {
RuntimeCargoProductionTarget::All => {
state.all_cargo_production_override = Some(*value);
}
RuntimeCargoProductionTarget::Factory => {
state.factory_cargo_production_override = Some(*value);
}
RuntimeCargoProductionTarget::FarmMine => {
state.farm_mine_cargo_production_override = Some(*value);
}
RuntimeCargoProductionTarget::Named { name } => {
state
.named_cargo_production_overrides
.insert(name.clone(), *value);
}
},
RuntimeEffect::SetCargoProductionSlot { slot, value } => { RuntimeEffect::SetCargoProductionSlot { slot, value } => {
state.cargo_production_overrides.insert(*slot, *value); state.cargo_production_overrides.insert(*slot, *value);
} }
@ -1509,8 +1536,9 @@ mod tests {
use super::*; use super::*;
use crate::{ use crate::{
CalendarPoint, RuntimeChairmanMetric, RuntimeChairmanProfile, RuntimeChairmanTarget, CalendarPoint, RuntimeCargoPriceTarget, RuntimeCargoProductionTarget,
RuntimeCompany, RuntimeCompanyControllerKind, RuntimeCompanyTarget, RuntimeCondition, RuntimeChairmanMetric, RuntimeChairmanProfile, RuntimeChairmanTarget, RuntimeCompany,
RuntimeCompanyControllerKind, RuntimeCompanyTarget, RuntimeCondition,
RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate, RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate,
RuntimePlayer, RuntimeSaveProfileState, RuntimeServiceState, RuntimeTerritory, RuntimePlayer, RuntimeSaveProfileState, RuntimeServiceState, RuntimeTerritory,
RuntimeTerritoryTarget, RuntimeTrackPieceCounts, RuntimeTrain, RuntimeWorldRestoreState, RuntimeTerritoryTarget, RuntimeTrackPieceCounts, RuntimeTrain, RuntimeWorldRestoreState,
@ -1561,6 +1589,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -1920,6 +1954,26 @@ mod tests {
key: "world.build_stations_cost".to_string(), key: "world.build_stations_cost".to_string(),
value: 350000, value: 350000,
}, },
RuntimeEffect::SetCargoPriceOverride {
target: RuntimeCargoPriceTarget::All,
value: 180,
},
RuntimeEffect::SetCargoPriceOverride {
target: RuntimeCargoPriceTarget::Named {
name: "Coal".to_string(),
},
value: 95,
},
RuntimeEffect::SetCargoProductionOverride {
target: RuntimeCargoProductionTarget::Factory,
value: 225,
},
RuntimeEffect::SetCargoProductionOverride {
target: RuntimeCargoProductionTarget::Named {
name: "Corn".to_string(),
},
value: 140,
},
RuntimeEffect::SetCargoProductionSlot { RuntimeEffect::SetCargoProductionSlot {
slot: 1, slot: 1,
value: 125, value: 125,
@ -1942,9 +1996,16 @@ mod tests {
.get("world.build_stations_cost"), .get("world.build_stations_cost"),
Some(&350000) Some(&350000)
); );
assert_eq!(state.all_cargo_price_override, Some(180));
assert_eq!(state.named_cargo_price_overrides.get("Coal"), Some(&95));
assert_eq!(state.factory_cargo_production_override, Some(225));
assert_eq!(
state.named_cargo_production_overrides.get("Corn"),
Some(&140)
);
assert_eq!(state.cargo_production_overrides.get(&1), Some(&125)); assert_eq!(state.cargo_production_overrides.get(&1), Some(&125));
assert_eq!(state.world_restore.territory_access_cost, Some(750000)); assert_eq!(state.world_restore.territory_access_cost, Some(750000));
assert_eq!(result.service_events[0].applied_effect_count, 3); assert_eq!(result.service_events[0].applied_effect_count, 7);
} }
#[test] #[test]

View file

@ -934,6 +934,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -1051,6 +1057,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -1105,6 +1117,12 @@ mod tests {
("Mikado".to_string(), 0), ("Mikado".to_string(), 0),
]), ]),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -1151,6 +1169,12 @@ mod tests {
("Big Boy".to_string(), 250000), ("Big Boy".to_string(), 250000),
("GP7".to_string(), 175000), ("GP7".to_string(), 175000),
]), ]),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -1195,6 +1219,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::from([(1, 125), (2, 250)]), cargo_production_overrides: BTreeMap::from([(1, 125), (2, 250)]),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -1301,6 +1331,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -1385,6 +1421,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),
@ -1465,6 +1507,12 @@ mod tests {
candidate_availability: BTreeMap::new(), candidate_availability: BTreeMap::new(),
named_locomotive_availability: BTreeMap::new(), named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(), named_locomotive_cost: BTreeMap::new(),
all_cargo_price_override: None,
named_cargo_price_overrides: BTreeMap::new(),
all_cargo_production_override: None,
factory_cargo_production_override: None,
farm_mine_cargo_production_override: None,
named_cargo_production_overrides: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(), cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(), world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(), special_conditions: BTreeMap::new(),

View file

@ -113,6 +113,11 @@ The highest-value next passes are now:
landing surface too: representative rows execute into `RuntimeState.world_scalar_overrides` landing surface too: representative rows execute into `RuntimeState.world_scalar_overrides`
through stable normalized keys such as `world.build_stations_cost` and through stable normalized keys such as `world.build_stations_cost` and
`world.track_maintenance_cost` `world.track_maintenance_cost`
- the grounded aggregate cargo-economics descriptors now execute too: descriptor `105`
`All Cargo Prices` and descriptors `177..179` `All Cargo Production` / `All Factory Production`
/ `All Farm/Mine Production` land on bounded event-owned cargo override state, while the named
cargo-price and named cargo-production strips remain explicit
`blocked_evidence_blocked_descriptor` parity until descriptor ordering is pinned more strongly
- widen real packed-event executable coverage descriptor by descriptor after identity, target mask, - widen real packed-event executable coverage descriptor by descriptor after identity, target mask,
and normalized effect semantics are all grounded, not just after row framing is parsed and normalized effect semantics are all grounded, not just after row framing is parsed
- the first grounded condition-side unlock now exists for negative-sentinel `raw_condition_id = -1` - the first grounded condition-side unlock now exists for negative-sentinel `raw_condition_id = -1`

View file

@ -75,6 +75,11 @@ Implemented today:
- the recovered whole-game scalar economy/performance strip `59..104` now has a bounded runtime - the recovered whole-game scalar economy/performance strip `59..104` now has a bounded runtime
landing surface too: representative descriptors import as `SetWorldScalarOverride` and land in landing surface too: representative descriptors import as `SetWorldScalarOverride` and land in
`RuntimeState.world_scalar_overrides` `RuntimeState.world_scalar_overrides`
- the grounded aggregate cargo-economics descriptors now execute too: descriptor `105`
`All Cargo Prices` and descriptors `177..179` `All Cargo Production` / `All Factory Production`
/ `All Farm/Mine Production` import through bounded cargo override surfaces, while the named
cargo-price and named cargo-production strips now sit on explicit
`blocked_evidence_blocked_descriptor` parity instead of generic unmapped-descriptor frontier
- a minimal event-owned train surface and an opaque economic-status lane now exist in runtime - a minimal event-owned train surface and an opaque economic-status lane now exist in runtime
state, and real descriptors `8` = `Economic Status`, `9` = `Confiscate All`, and `15` = state, and real descriptors `8` = `Economic Status`, `9` = `Confiscate All`, and `15` =
`Retire Train` now import and execute through the ordinary runtime path when overlay context `Retire Train` now import and execute through the ordinary runtime path when overlay context

View file

@ -0,0 +1,50 @@
{
"format_version": 1,
"fixture_id": "packed-event-cargo-economics-parity-save-slice-fixture",
"source": {
"kind": "captured-runtime",
"description": "Fixture pinning the remaining named cargo-economics descriptor strips on explicit evidence-blocked parity."
},
"state_save_slice_path": "packed-event-cargo-economics-parity-save-slice.json",
"commands": [
{
"kind": "step_count",
"steps": 1
}
],
"expected_summary": {
"calendar_projection_is_placeholder": true,
"packed_event_collection_present": true,
"packed_event_record_count": 1,
"packed_event_decoded_record_count": 1,
"packed_event_imported_runtime_record_count": 0,
"packed_event_blocked_evidence_blocked_descriptor_count": 1,
"packed_event_blocked_unmapped_real_descriptor_count": 0,
"packed_event_blocked_unmapped_world_descriptor_count": 0,
"event_runtime_record_count": 0
},
"expected_state_fragment": {
"packed_event_collection": {
"records": [
{
"import_outcome": "blocked_evidence_blocked_descriptor",
"grouped_effect_rows": [
{
"descriptor_id": 106,
"descriptor_label": "Unknown Cargo Price",
"parameter_family": "cargo_price_scalar",
"semantic_family": "scalar_assignment"
},
{
"descriptor_id": 180,
"descriptor_label": "Unknown Cargo Production",
"parameter_family": "cargo_production_scalar",
"semantic_family": "scalar_assignment"
}
]
}
]
},
"event_runtime_records": []
}
}

View file

@ -0,0 +1,137 @@
{
"format_version": 1,
"save_slice_id": "packed-event-cargo-economics-parity-save-slice",
"source": {
"description": "Tracked save-slice document pinning the remaining named cargo-economics descriptor strips on explicit evidence-blocked parity.",
"original_save_filename": "captured-cargo-economics-parity.gms",
"original_save_sha256": "cargo-economics-parity-sample-sha256",
"notes": [
"tracked as JSON save-slice document rather than raw .smp",
"pins named cargo price and named cargo production rows until exact descriptor-to-cargo ordering is grounded strongly enough"
]
},
"save_slice": {
"file_extension_hint": "gms",
"container_profile_family": "rt3-classic-save-container-v1",
"mechanism_family": "classic-save-rehydrate-v1",
"mechanism_confidence": "grounded",
"trailer_family": null,
"bridge_family": null,
"profile": null,
"candidate_availability_table": null,
"named_locomotive_availability_table": null,
"locomotive_catalog": null,
"cargo_catalog": null,
"company_roster": null,
"chairman_profile_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": 33408,
"records_tag_offset": 33664,
"close_tag_offset": 34176,
"packed_state_version": 1001,
"packed_state_version_hex": "0x000003e9",
"live_id_bound": 65,
"live_record_count": 1,
"live_entry_ids": [65],
"decoded_record_count": 1,
"imported_runtime_record_count": 0,
"records": [
{
"record_index": 0,
"live_entry_id": 65,
"payload_offset": 33696,
"payload_len": 128,
"decode_status": "parity_only",
"payload_family": "real_packed_v1",
"trigger_kind": 7,
"one_shot": false,
"compact_control": {
"mode_byte_0x7ef": 7,
"primary_selector_0x7f0": 0,
"grouped_mode_0x7f4": 2,
"one_shot_header_0x7f5": 0,
"modifier_flag_0x7f9": 0,
"modifier_flag_0x7fa": 0,
"grouped_target_scope_ordinals_0x7fb": [0, 0, 0, 0],
"grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0],
"summary_toggle_0x800": 1,
"grouped_territory_selectors_0x80f": [-1, -1, -1, -1]
},
"text_bands": [],
"standalone_condition_row_count": 0,
"standalone_condition_rows": [],
"grouped_effect_row_counts": [2, 0, 0, 0],
"grouped_effect_rows": [
{
"group_index": 0,
"row_index": 0,
"descriptor_id": 106,
"descriptor_label": "Unknown Cargo Price",
"target_mask_bits": 8,
"parameter_family": "cargo_price_scalar",
"opcode": 3,
"raw_scalar_value": 140,
"value_byte_0x09": 0,
"value_dword_0x0d": 0,
"value_byte_0x11": 0,
"value_byte_0x12": 0,
"value_word_0x14": 0,
"value_word_0x16": 0,
"row_shape": "scalar_assignment",
"semantic_family": "scalar_assignment",
"semantic_preview": "Set Unknown Cargo Price to 140",
"recovered_cargo_slot": null,
"recovered_cargo_class": null,
"recovered_locomotive_id": null,
"locomotive_name": null,
"notes": [
"descriptor recovered from checked-in EventEffects semantic catalog",
"exact named cargo ordering for the price strip is not yet pinned"
]
},
{
"group_index": 0,
"row_index": 1,
"descriptor_id": 180,
"descriptor_label": "Unknown Cargo Production",
"target_mask_bits": 8,
"parameter_family": "cargo_production_scalar",
"opcode": 3,
"raw_scalar_value": 160,
"value_byte_0x09": 0,
"value_dword_0x0d": 0,
"value_byte_0x11": 0,
"value_byte_0x12": 0,
"value_word_0x14": 0,
"value_word_0x16": 0,
"row_shape": "scalar_assignment",
"semantic_family": "scalar_assignment",
"semantic_preview": "Set Unknown Cargo Production to 160",
"recovered_cargo_slot": null,
"recovered_cargo_class": null,
"recovered_locomotive_id": null,
"locomotive_name": null,
"notes": [
"descriptor recovered from checked-in EventEffects semantic catalog",
"exact named cargo ordering for the production strip is not yet pinned"
]
}
],
"decoded_actions": [],
"executable_import_ready": false,
"notes": [
"named cargo-economics descriptor strips remain explicit evidence-blocked parity"
]
}
]
},
"notes": [
"named cargo economics evidence-blocked parity sample"
]
}
}

View file

@ -0,0 +1,75 @@
{
"format_version": 1,
"fixture_id": "packed-event-cargo-economics-save-slice-fixture",
"source": {
"kind": "captured-runtime",
"description": "Fixture proving the grounded aggregate cargo-economics descriptors execute through bounded cargo override surfaces."
},
"state_save_slice_path": "packed-event-cargo-economics-save-slice.json",
"commands": [
{
"kind": "service_trigger_kind",
"trigger_kind": 7
}
],
"expected_summary": {
"calendar_projection_source": "default-1830-placeholder",
"calendar_projection_is_placeholder": true,
"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,
"total_event_record_service_count": 1,
"total_trigger_dispatch_count": 1
},
"expected_state_fragment": {
"all_cargo_price_override": 180,
"all_cargo_production_override": 210,
"factory_cargo_production_override": 225,
"farm_mine_cargo_production_override": 175,
"packed_event_collection": {
"records": [
{
"import_outcome": "imported"
}
]
},
"event_runtime_records": [
{
"record_id": 64,
"service_count": 1,
"effects": [
{
"kind": "set_cargo_price_override",
"target": {
"kind": "all"
},
"value": 180
},
{
"kind": "set_cargo_production_override",
"target": {
"kind": "all"
},
"value": 210
},
{
"kind": "set_cargo_production_override",
"target": {
"kind": "factory"
},
"value": 225
},
{
"kind": "set_cargo_production_override",
"target": {
"kind": "farm_mine"
},
"value": 175
}
]
}
]
}
}

View file

@ -0,0 +1,216 @@
{
"format_version": 1,
"save_slice_id": "packed-event-cargo-economics-save-slice",
"source": {
"description": "Tracked save-slice document proving the grounded aggregate cargo-economics descriptors execute through bounded cargo override surfaces.",
"original_save_filename": "captured-cargo-economics.gms",
"original_save_sha256": "cargo-economics-sample-sha256",
"notes": [
"tracked as JSON save-slice document rather than raw .smp",
"pins the grounded aggregate descriptors 105 and 177..179 while named cargo strips remain evidence-blocked"
]
},
"save_slice": {
"file_extension_hint": "gms",
"container_profile_family": "rt3-classic-save-container-v1",
"mechanism_family": "classic-save-rehydrate-v1",
"mechanism_confidence": "grounded",
"trailer_family": null,
"bridge_family": null,
"profile": null,
"candidate_availability_table": null,
"named_locomotive_availability_table": null,
"locomotive_catalog": null,
"cargo_catalog": null,
"company_roster": null,
"chairman_profile_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": 32512,
"records_tag_offset": 32768,
"close_tag_offset": 33280,
"packed_state_version": 1001,
"packed_state_version_hex": "0x000003e9",
"live_id_bound": 64,
"live_record_count": 1,
"live_entry_ids": [64],
"decoded_record_count": 1,
"imported_runtime_record_count": 0,
"records": [
{
"record_index": 0,
"live_entry_id": 64,
"payload_offset": 32800,
"payload_len": 176,
"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": 0,
"standalone_condition_rows": [],
"grouped_effect_row_counts": [4, 0, 0, 0],
"grouped_effect_rows": [
{
"group_index": 0,
"row_index": 0,
"descriptor_id": 105,
"descriptor_label": "All Cargo Prices",
"target_mask_bits": 8,
"parameter_family": "cargo_price_scalar",
"opcode": 3,
"raw_scalar_value": 180,
"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 All Cargo Prices to 180",
"recovered_cargo_slot": null,
"recovered_cargo_class": null,
"recovered_locomotive_id": null,
"locomotive_name": null,
"notes": [
"descriptor recovered from checked-in EventEffects semantic catalog"
]
},
{
"group_index": 0,
"row_index": 1,
"descriptor_id": 177,
"descriptor_label": "All Cargo Production",
"target_mask_bits": 8,
"parameter_family": "cargo_production_scalar",
"opcode": 3,
"raw_scalar_value": 210,
"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 All Cargo Production to 210",
"recovered_cargo_slot": null,
"recovered_cargo_class": null,
"recovered_locomotive_id": null,
"locomotive_name": null,
"notes": [
"descriptor recovered from checked-in EventEffects semantic catalog"
]
},
{
"group_index": 0,
"row_index": 2,
"descriptor_id": 178,
"descriptor_label": "All Factory Production",
"target_mask_bits": 8,
"parameter_family": "cargo_production_scalar",
"opcode": 3,
"raw_scalar_value": 225,
"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 All Factory Production to 225",
"recovered_cargo_slot": null,
"recovered_cargo_class": "factory",
"recovered_locomotive_id": null,
"locomotive_name": null,
"notes": [
"descriptor recovered from checked-in EventEffects semantic catalog"
]
},
{
"group_index": 0,
"row_index": 3,
"descriptor_id": 179,
"descriptor_label": "All Farm/Mine Production",
"target_mask_bits": 8,
"parameter_family": "cargo_production_scalar",
"opcode": 3,
"raw_scalar_value": 175,
"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 All Farm/Mine Production to 175",
"recovered_cargo_slot": null,
"recovered_cargo_class": "farm_mine",
"recovered_locomotive_id": null,
"locomotive_name": null,
"notes": [
"descriptor recovered from checked-in EventEffects semantic catalog"
]
}
],
"decoded_actions": [
{
"kind": "set_cargo_price_override",
"target": {
"kind": "all"
},
"value": 180
},
{
"kind": "set_cargo_production_override",
"target": {
"kind": "all"
},
"value": 210
},
{
"kind": "set_cargo_production_override",
"target": {
"kind": "factory"
},
"value": 225
},
{
"kind": "set_cargo_production_override",
"target": {
"kind": "farm_mine"
},
"value": 175
}
],
"executable_import_ready": true,
"notes": [
"grounded aggregate cargo economics descriptors execute through bounded cargo override surfaces"
]
}
]
},
"notes": [
"aggregate cargo economics executable sample"
]
}
}

View file

@ -55,10 +55,22 @@ def classify(row: dict[str, object]) -> dict[str, object]:
runtime_key = normalize_world_scalar_key(label) runtime_key = normalize_world_scalar_key(label)
runtime_status = "executable" runtime_status = "executable"
executable_in_runtime = True executable_in_runtime = True
elif 105 <= descriptor_id <= 176: elif descriptor_id == 105:
parameter_family = "cargo_price_scalar" parameter_family = "cargo_price_scalar"
elif 177 <= descriptor_id <= 240: runtime_status = "executable"
executable_in_runtime = True
elif 106 <= descriptor_id <= 176:
parameter_family = "cargo_price_scalar"
elif 177 <= descriptor_id <= 179:
parameter_family = "cargo_production_scalar" parameter_family = "cargo_production_scalar"
runtime_status = "executable"
executable_in_runtime = True
elif 180 <= descriptor_id <= 229:
parameter_family = "cargo_production_scalar"
elif 230 <= descriptor_id <= 240:
parameter_family = "cargo_production_scalar"
runtime_status = "executable"
executable_in_runtime = True
elif 241 <= descriptor_id <= 351 or 457 <= descriptor_id <= 474: elif 241 <= descriptor_id <= 351 or 457 <= descriptor_id <= 474:
parameter_family = "locomotive_availability_scalar" parameter_family = "locomotive_availability_scalar"
elif 352 <= descriptor_id <= 451 or 475 <= descriptor_id <= 502: elif 352 <= descriptor_id <= 451 or 475 <= descriptor_id <= 502: