Close EventEffects semantic descriptor frontier
This commit is contained in:
parent
3dbcec688f
commit
51a7bbd756
18 changed files with 5432 additions and 175 deletions
20
README.md
20
README.md
|
|
@ -31,12 +31,21 @@ company-targeted and chairman-targeted descriptor and condition batches can exec
|
||||||
save-slice fixtures without overlay snapshots when that context is present; raw `.gms` inspection
|
save-slice fixtures without overlay snapshots when that context is present; raw `.gms` inspection
|
||||||
still does not reconstruct those company/chairman collections automatically. A checked-in
|
still does not reconstruct those company/chairman collections automatically. A checked-in
|
||||||
`EventEffects` export now exists too in
|
`EventEffects` export now exists too in
|
||||||
`artifacts/exports/rt3-1.06/event-effects-table.json`, and the first recovered governance
|
`artifacts/exports/rt3-1.06/event-effects-table.json`, and a checked-in semantic closure layer now
|
||||||
descriptor tranche now imports through the generic company-governance scalar effect surface:
|
exists beside it in `artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json`. Recovered
|
||||||
|
descriptor rows now land on explicit semantic frontier buckets such as
|
||||||
|
`blocked_shell_owned_descriptor`, `blocked_evidence_blocked_descriptor`, and
|
||||||
|
`blocked_variant_or_scope_blocked_descriptor` instead of generic anonymous descriptor residue. The
|
||||||
|
first recovered governance descriptor tranche now imports through the generic
|
||||||
|
company-governance scalar effect surface:
|
||||||
descriptor `56` `Credit Rating` and descriptor `57` `Prime Rate` execute from ordinary real packed
|
descriptor `56` `Credit Rating` and descriptor `57` `Prime Rate` execute from ordinary real packed
|
||||||
rows, while adjacent recovered finance/control-transfer descriptors such as `55` `Stock Prices`
|
rows, while adjacent recovered finance/control-transfer descriptors such as `55` `Stock Prices`
|
||||||
and `58` `Merger Premium` now land on explicit shell-owned parity instead of anonymous unmapped
|
and `58` `Merger Premium` now land on explicit shell-owned parity instead of anonymous unmapped
|
||||||
descriptor residue. The first grounded
|
descriptor residue. The recovered whole-game scalar economy/performance strip `59..104` now has a
|
||||||
|
bounded runtime landing surface too: representative descriptors import into
|
||||||
|
`RuntimeState.world_scalar_overrides` through stable normalized keys such as
|
||||||
|
`world.build_stations_cost`, `world.track_maintenance_cost`, `world.all_engine_speeds`, and
|
||||||
|
`world.hotel_revenue`. 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
|
||||||
|
|
@ -82,9 +91,8 @@ same world-scalar runtime surfaces too: named locomotive availability thresholds
|
||||||
locomotive cost thresholds, named cargo-production slot thresholds, aggregate cargo-production
|
locomotive cost thresholds, named cargo-production slot thresholds, aggregate cargo-production
|
||||||
thresholds, factory/farm-mine/other cargo-production thresholds, limited-track-building-amount
|
thresholds, factory/farm-mine/other cargo-production thresholds, limited-track-building-amount
|
||||||
thresholds, and territory-access-cost thresholds all gate imported runtime records through the
|
thresholds, and territory-access-cost thresholds all gate imported runtime records through the
|
||||||
same service path. Explicit
|
same service path. Explicit unmapped world-condition frontier buckets still remain where current
|
||||||
unmapped world-condition and world-descriptor
|
checked-in metadata stops, and
|
||||||
frontier buckets still remain where current checked-in metadata stops, and
|
|
||||||
`blocked_missing_locomotive_catalog_context` is now reserved for intentionally incomplete save-side
|
`blocked_missing_locomotive_catalog_context` is now reserved for intentionally incomplete save-side
|
||||||
catalog context instead of the normal save-slice path. Cargo slot identity and class metadata are
|
catalog context instead of the normal save-slice path. Cargo slot identity and class metadata are
|
||||||
now save-native too: the recipe-book probe lowers into `RuntimeState.cargo_catalog`, so save-slice
|
now save-native too: the recipe-book probe lowers into `RuntimeState.cargo_catalog`, so save-slice
|
||||||
|
|
|
||||||
4687
artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json
Normal file
4687
artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -4476,6 +4476,9 @@ mod tests {
|
||||||
let world_scalar_executable_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
|
let world_scalar_executable_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
|
||||||
"../../fixtures/runtime/packed-event-world-scalar-executable-save-slice-fixture.json",
|
"../../fixtures/runtime/packed-event-world-scalar-executable-save-slice-fixture.json",
|
||||||
);
|
);
|
||||||
|
let world_scalar_override_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
|
||||||
|
"../../fixtures/runtime/packed-event-world-scalar-override-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",
|
||||||
);
|
);
|
||||||
|
|
@ -4585,6 +4588,8 @@ mod tests {
|
||||||
.expect("save-slice-backed recovered scalar-band parity fixture should summarize");
|
.expect("save-slice-backed recovered scalar-band parity fixture should summarize");
|
||||||
run_runtime_summarize_fixture(&world_scalar_executable_fixture)
|
run_runtime_summarize_fixture(&world_scalar_executable_fixture)
|
||||||
.expect("save-slice-backed executable world-scalar fixture should summarize");
|
.expect("save-slice-backed executable world-scalar fixture should summarize");
|
||||||
|
run_runtime_summarize_fixture(&world_scalar_override_fixture)
|
||||||
|
.expect("save-slice-backed world-scalar override 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)
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
},
|
},
|
||||||
|
|
@ -377,6 +378,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,10 @@ pub struct ExpectedRuntimeSummary {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub packed_event_blocked_shell_owned_descriptor_count: Option<usize>,
|
pub packed_event_blocked_shell_owned_descriptor_count: Option<usize>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub packed_event_blocked_evidence_blocked_descriptor_count: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub packed_event_blocked_variant_or_scope_blocked_descriptor_count: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
pub packed_event_blocked_unmapped_real_descriptor_count: Option<usize>,
|
pub packed_event_blocked_unmapped_real_descriptor_count: Option<usize>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub packed_event_blocked_unmapped_world_descriptor_count: Option<usize>,
|
pub packed_event_blocked_unmapped_world_descriptor_count: Option<usize>,
|
||||||
|
|
@ -184,6 +188,8 @@ pub struct ExpectedRuntimeSummary {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub cargo_production_override_count: Option<usize>,
|
pub cargo_production_override_count: Option<usize>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub world_scalar_override_count: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
pub special_condition_count: Option<usize>,
|
pub special_condition_count: Option<usize>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub enabled_special_condition_count: Option<usize>,
|
pub enabled_special_condition_count: Option<usize>,
|
||||||
|
|
@ -761,6 +767,22 @@ impl ExpectedRuntimeSummary {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(count) = self.packed_event_blocked_evidence_blocked_descriptor_count {
|
||||||
|
if actual.packed_event_blocked_evidence_blocked_descriptor_count != count {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"packed_event_blocked_evidence_blocked_descriptor_count mismatch: expected {count}, got {}",
|
||||||
|
actual.packed_event_blocked_evidence_blocked_descriptor_count
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(count) = self.packed_event_blocked_variant_or_scope_blocked_descriptor_count {
|
||||||
|
if actual.packed_event_blocked_variant_or_scope_blocked_descriptor_count != count {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"packed_event_blocked_variant_or_scope_blocked_descriptor_count mismatch: expected {count}, got {}",
|
||||||
|
actual.packed_event_blocked_variant_or_scope_blocked_descriptor_count
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(count) = self.packed_event_blocked_unmapped_real_descriptor_count {
|
if let Some(count) = self.packed_event_blocked_unmapped_real_descriptor_count {
|
||||||
if actual.packed_event_blocked_unmapped_real_descriptor_count != count {
|
if actual.packed_event_blocked_unmapped_real_descriptor_count != count {
|
||||||
mismatches.push(format!(
|
mismatches.push(format!(
|
||||||
|
|
@ -905,6 +927,14 @@ impl ExpectedRuntimeSummary {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(count) = self.world_scalar_override_count {
|
||||||
|
if actual.world_scalar_override_count != count {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"world_scalar_override_count mismatch: expected {count}, got {}",
|
||||||
|
actual.world_scalar_override_count
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(count) = self.special_condition_count {
|
if let Some(count) = self.special_condition_count {
|
||||||
if actual.special_condition_count != count {
|
if actual.special_condition_count != count {
|
||||||
mismatches.push(format!(
|
mismatches.push(format!(
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ pub const REQUIRED_EXPORTS: &[&str] = &[
|
||||||
"artifacts/exports/rt3-1.06/pending-template-store-record-kinds.csv",
|
"artifacts/exports/rt3-1.06/pending-template-store-record-kinds.csv",
|
||||||
"artifacts/exports/rt3-1.06/pending-template-store-management.md",
|
"artifacts/exports/rt3-1.06/pending-template-store-management.md",
|
||||||
"artifacts/exports/rt3-1.06/event-effects-table.json",
|
"artifacts/exports/rt3-1.06/event-effects-table.json",
|
||||||
|
"artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const REQUIRED_ATLAS_HEADINGS: &[&str] = &[
|
pub const REQUIRED_ATLAS_HEADINGS: &[&str] = &[
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ struct SaveSliceProjection {
|
||||||
cargo_catalog: Option<Vec<RuntimeCargoCatalogEntry>>,
|
cargo_catalog: Option<Vec<RuntimeCargoCatalogEntry>>,
|
||||||
named_locomotive_cost: BTreeMap<String, u32>,
|
named_locomotive_cost: BTreeMap<String, u32>,
|
||||||
cargo_production_overrides: BTreeMap<u32, u32>,
|
cargo_production_overrides: BTreeMap<u32, u32>,
|
||||||
|
world_scalar_overrides: BTreeMap<String, i64>,
|
||||||
special_conditions: BTreeMap<String, u32>,
|
special_conditions: BTreeMap<String, u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -277,6 +278,7 @@ pub fn project_save_slice_to_runtime_state_import(
|
||||||
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,
|
||||||
cargo_production_overrides: projection.cargo_production_overrides,
|
cargo_production_overrides: projection.cargo_production_overrides,
|
||||||
|
world_scalar_overrides: projection.world_scalar_overrides,
|
||||||
special_conditions: projection.special_conditions,
|
special_conditions: projection.special_conditions,
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -364,6 +366,7 @@ pub fn project_save_slice_overlay_to_runtime_state_import(
|
||||||
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(),
|
||||||
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(),
|
||||||
special_conditions: projection.special_conditions,
|
special_conditions: projection.special_conditions,
|
||||||
service_state: base_state.service_state.clone(),
|
service_state: base_state.service_state.clone(),
|
||||||
};
|
};
|
||||||
|
|
@ -872,6 +875,7 @@ fn project_save_slice_components(
|
||||||
|
|
||||||
let named_locomotive_cost = BTreeMap::new();
|
let named_locomotive_cost = BTreeMap::new();
|
||||||
let cargo_production_overrides = BTreeMap::new();
|
let cargo_production_overrides = BTreeMap::new();
|
||||||
|
let world_scalar_overrides = BTreeMap::new();
|
||||||
|
|
||||||
let mut packed_event_context = company_context.clone();
|
let mut packed_event_context = company_context.clone();
|
||||||
if has_company_projection {
|
if has_company_projection {
|
||||||
|
|
@ -948,6 +952,7 @@ fn project_save_slice_components(
|
||||||
cargo_catalog,
|
cargo_catalog,
|
||||||
named_locomotive_cost,
|
named_locomotive_cost,
|
||||||
cargo_production_overrides,
|
cargo_production_overrides,
|
||||||
|
world_scalar_overrides,
|
||||||
special_conditions,
|
special_conditions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -1316,6 +1321,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_world_scalar_override_effect(row)? {
|
||||||
|
effects.push(effect);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if let Some(effect) = lower_contextual_cargo_production_effect(row)? {
|
if let Some(effect) = lower_contextual_cargo_production_effect(row)? {
|
||||||
effects.push(effect);
|
effects.push(effect);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1347,6 +1356,28 @@ fn lower_contextual_real_grouped_effects(
|
||||||
Ok(effects)
|
Ok(effects)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lower_contextual_world_scalar_override_effect(
|
||||||
|
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
||||||
|
) -> Result<Option<RuntimeEffect>, ImportBlocker> {
|
||||||
|
if row.parameter_family.as_deref() != Some("world_scalar_override") {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
if row.row_shape != "scalar_assignment" {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let Some(key) = row
|
||||||
|
.descriptor_label
|
||||||
|
.as_deref()
|
||||||
|
.map(crate::smp::runtime_world_scalar_key_from_label)
|
||||||
|
else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
Ok(Some(RuntimeEffect::SetWorldScalarOverride {
|
||||||
|
key,
|
||||||
|
value: i64::from(row.raw_scalar_value),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
fn lower_contextual_locomotive_availability_effect(
|
fn lower_contextual_locomotive_availability_effect(
|
||||||
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
||||||
company_context: &ImportRuntimeContext,
|
company_context: &ImportRuntimeContext,
|
||||||
|
|
@ -1564,6 +1595,12 @@ fn lower_condition_targets_in_effect(
|
||||||
key: key.clone(),
|
key: key.clone(),
|
||||||
value: *value,
|
value: *value,
|
||||||
},
|
},
|
||||||
|
RuntimeEffect::SetWorldScalarOverride { key, value } => {
|
||||||
|
RuntimeEffect::SetWorldScalarOverride {
|
||||||
|
key: key.clone(),
|
||||||
|
value: *value,
|
||||||
|
}
|
||||||
|
}
|
||||||
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
|
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
|
||||||
RuntimeEffect::SetLimitedTrackBuildingAmount { value: *value }
|
RuntimeEffect::SetLimitedTrackBuildingAmount { value: *value }
|
||||||
}
|
}
|
||||||
|
|
@ -2346,6 +2383,12 @@ fn smp_runtime_effect_to_runtime_effect(
|
||||||
value: *value,
|
value: *value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetWorldScalarOverride { key, value } => {
|
||||||
|
Ok(RuntimeEffect::SetWorldScalarOverride {
|
||||||
|
key: key.clone(),
|
||||||
|
value: *value,
|
||||||
|
})
|
||||||
|
}
|
||||||
RuntimeEffect::SetCargoProductionSlot { slot, value } => {
|
RuntimeEffect::SetCargoProductionSlot { slot, value } => {
|
||||||
Ok(RuntimeEffect::SetCargoProductionSlot {
|
Ok(RuntimeEffect::SetCargoProductionSlot {
|
||||||
slot: *slot,
|
slot: *slot,
|
||||||
|
|
@ -2690,6 +2733,27 @@ fn determine_packed_event_import_outcome(
|
||||||
{
|
{
|
||||||
return "blocked_shell_owned_descriptor".to_string();
|
return "blocked_shell_owned_descriptor".to_string();
|
||||||
}
|
}
|
||||||
|
if record
|
||||||
|
.grouped_effect_rows
|
||||||
|
.iter()
|
||||||
|
.any(real_grouped_row_is_evidence_blocked_descriptor_family)
|
||||||
|
{
|
||||||
|
return "blocked_evidence_blocked_descriptor".to_string();
|
||||||
|
}
|
||||||
|
if record
|
||||||
|
.grouped_effect_rows
|
||||||
|
.iter()
|
||||||
|
.any(real_grouped_row_is_variant_or_scope_blocked_descriptor_family)
|
||||||
|
{
|
||||||
|
return "blocked_variant_or_scope_blocked_descriptor".to_string();
|
||||||
|
}
|
||||||
|
if record
|
||||||
|
.grouped_effect_rows
|
||||||
|
.iter()
|
||||||
|
.any(real_grouped_row_is_unsupported_executable_descriptor_variant)
|
||||||
|
{
|
||||||
|
return "blocked_variant_or_scope_blocked_descriptor".to_string();
|
||||||
|
}
|
||||||
if record
|
if record
|
||||||
.grouped_effect_rows
|
.grouped_effect_rows
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -2788,9 +2852,47 @@ fn real_grouped_row_is_world_state_family(
|
||||||
|
|
||||||
fn real_grouped_row_is_shell_owned_descriptor_family(
|
fn real_grouped_row_is_shell_owned_descriptor_family(
|
||||||
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
||||||
|
) -> bool {
|
||||||
|
real_grouped_row_has_runtime_status(row, "shell_owned")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn real_grouped_row_is_evidence_blocked_descriptor_family(
|
||||||
|
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
||||||
|
) -> bool {
|
||||||
|
real_grouped_row_has_runtime_status(row, "evidence_blocked")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn real_grouped_row_is_variant_or_scope_blocked_descriptor_family(
|
||||||
|
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
||||||
|
) -> bool {
|
||||||
|
real_grouped_row_has_runtime_status(row, "variant_or_scope_blocked")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn real_grouped_row_has_runtime_status(
|
||||||
|
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
||||||
|
status: &str,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
crate::smp::grouped_effect_descriptor_runtime_status_name(row.descriptor_id)
|
crate::smp::grouped_effect_descriptor_runtime_status_name(row.descriptor_id)
|
||||||
.is_some_and(|status| status == "shell_owned")
|
.is_some_and(|runtime_status| runtime_status == status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn real_grouped_row_is_unsupported_executable_descriptor_variant(
|
||||||
|
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
||||||
|
) -> bool {
|
||||||
|
if !real_grouped_row_has_runtime_status(row, "executable") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
match row.descriptor_id {
|
||||||
|
1 => !(row.opcode == 8 && row.row_shape == "multivalue_scalar"),
|
||||||
|
2 => !(row.opcode == 8 && row.row_shape == "multivalue_scalar"),
|
||||||
|
8 | 108 | 109 | 122 => row.row_shape != "scalar_assignment",
|
||||||
|
13 | 14 => !(row.row_shape == "bool_toggle" && row.raw_scalar_value != 0),
|
||||||
|
56 | 57 => row.row_shape != "scalar_assignment",
|
||||||
|
_ => {
|
||||||
|
row.parameter_family.as_deref() == Some("world_scalar_override")
|
||||||
|
&& row.row_shape != "scalar_assignment"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn packed_record_company_target_import_blocker(
|
fn packed_record_company_target_import_blocker(
|
||||||
|
|
@ -2980,6 +3082,7 @@ fn runtime_effect_uses_condition_true_company(effect: &RuntimeEffect) -> bool {
|
||||||
.iter()
|
.iter()
|
||||||
.any(runtime_effect_uses_condition_true_company),
|
.any(runtime_effect_uses_condition_true_company),
|
||||||
RuntimeEffect::SetWorldFlag { .. }
|
RuntimeEffect::SetWorldFlag { .. }
|
||||||
|
| RuntimeEffect::SetWorldScalarOverride { .. }
|
||||||
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
||||||
| RuntimeEffect::SetEconomicStatusCode { .. }
|
| RuntimeEffect::SetEconomicStatusCode { .. }
|
||||||
| RuntimeEffect::SetPlayerCash { .. }
|
| RuntimeEffect::SetPlayerCash { .. }
|
||||||
|
|
@ -3093,6 +3196,7 @@ fn runtime_effect_company_target_import_blocker(
|
||||||
runtime_effect_company_target_import_blocker(nested, company_context)
|
runtime_effect_company_target_import_blocker(nested, company_context)
|
||||||
}),
|
}),
|
||||||
RuntimeEffect::SetWorldFlag { .. }
|
RuntimeEffect::SetWorldFlag { .. }
|
||||||
|
| RuntimeEffect::SetWorldScalarOverride { .. }
|
||||||
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
||||||
| RuntimeEffect::SetEconomicStatusCode { .. }
|
| RuntimeEffect::SetEconomicStatusCode { .. }
|
||||||
| RuntimeEffect::SetCandidateAvailability { .. }
|
| RuntimeEffect::SetCandidateAvailability { .. }
|
||||||
|
|
@ -3449,6 +3553,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
}
|
}
|
||||||
|
|
@ -6634,6 +6739,7 @@ mod tests {
|
||||||
]),
|
]),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -7039,6 +7145,7 @@ mod tests {
|
||||||
("Locomotive 101".to_string(), 200000),
|
("Locomotive 101".to_string(), 200000),
|
||||||
]),
|
]),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -7211,7 +7318,7 @@ mod tests {
|
||||||
.packed_event_collection
|
.packed_event_collection
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
|
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
|
||||||
Some("blocked_unmapped_world_descriptor")
|
Some("blocked_evidence_blocked_descriptor")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7439,6 +7546,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -8207,7 +8315,7 @@ mod tests {
|
||||||
.packed_event_collection
|
.packed_event_collection
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
|
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
|
||||||
Some("blocked_unmapped_real_descriptor")
|
Some("blocked_variant_or_scope_blocked_descriptor")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8295,7 +8403,7 @@ mod tests {
|
||||||
.packed_event_collection
|
.packed_event_collection
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
|
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
|
||||||
Some("blocked_unmapped_real_descriptor")
|
Some("blocked_variant_or_scope_blocked_descriptor")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -9713,6 +9821,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -9886,6 +9995,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -11574,6 +11684,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState {
|
service_state: RuntimeServiceState {
|
||||||
periodic_boundary_calls: 9,
|
periodic_boundary_calls: 9,
|
||||||
|
|
@ -11758,6 +11869,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -467,6 +467,10 @@ pub enum RuntimeEffect {
|
||||||
slot: u32,
|
slot: u32,
|
||||||
value: u32,
|
value: u32,
|
||||||
},
|
},
|
||||||
|
SetWorldScalarOverride {
|
||||||
|
key: String,
|
||||||
|
value: i64,
|
||||||
|
},
|
||||||
SetTerritoryAccessCost {
|
SetTerritoryAccessCost {
|
||||||
value: u32,
|
value: u32,
|
||||||
},
|
},
|
||||||
|
|
@ -842,6 +846,8 @@ pub struct RuntimeState {
|
||||||
#[serde(default)]
|
#[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>,
|
||||||
|
#[serde(default)]
|
||||||
pub special_conditions: BTreeMap<String, u32>,
|
pub special_conditions: BTreeMap<String, u32>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub service_state: RuntimeServiceState,
|
pub service_state: RuntimeServiceState,
|
||||||
|
|
@ -1489,6 +1495,11 @@ impl RuntimeState {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for key in self.world_scalar_overrides.keys() {
|
||||||
|
if key.trim().is_empty() {
|
||||||
|
return Err("world_scalar_overrides contains an empty key".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
for key in self.special_conditions.keys() {
|
for key in self.special_conditions.keys() {
|
||||||
if key.trim().is_empty() {
|
if key.trim().is_empty() {
|
||||||
return Err("special_conditions contains an empty key".to_string());
|
return Err("special_conditions contains an empty key".to_string());
|
||||||
|
|
@ -1512,6 +1523,11 @@ fn validate_runtime_effect(
|
||||||
return Err("key must not be empty".to_string());
|
return Err("key must not be empty".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetWorldScalarOverride { key, .. } => {
|
||||||
|
if key.trim().is_empty() {
|
||||||
|
return Err("key must not be empty".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
||||||
| RuntimeEffect::SetEconomicStatusCode { .. } => {}
|
| RuntimeEffect::SetEconomicStatusCode { .. } => {}
|
||||||
RuntimeEffect::SetCompanyCash { target, .. }
|
RuntimeEffect::SetCompanyCash { target, .. }
|
||||||
|
|
@ -1901,6 +1917,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -1964,6 +1981,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2031,6 +2049,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2108,6 +2127,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2210,6 +2230,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2264,6 +2285,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2318,6 +2340,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2389,6 +2412,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2450,6 +2474,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2515,6 +2540,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2576,6 +2602,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2643,6 +2670,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2704,6 +2732,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2765,6 +2794,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2819,6 +2849,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -2883,6 +2914,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -141,20 +141,19 @@ enum RealGroupedEffectRuntimeStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
struct CheckedInEventEffectsTableArtifact {
|
struct CheckedInEventEffectsSemanticCatalogArtifact {
|
||||||
descriptors: Vec<CheckedInEventEffectDescriptorRow>,
|
descriptors: Vec<CheckedInEventEffectSemanticRow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
struct CheckedInEventEffectDescriptorRow {
|
struct CheckedInEventEffectSemanticRow {
|
||||||
descriptor_id: u32,
|
descriptor_id: u32,
|
||||||
selector_order: f32,
|
|
||||||
target_mask_bits: u8,
|
|
||||||
label_id: u32,
|
|
||||||
label: String,
|
label: String,
|
||||||
signature_byte_0x63: u8,
|
target_mask_bits: u8,
|
||||||
signature_byte_0x64: u8,
|
parameter_family: String,
|
||||||
signature_hex_0x63_0x6d: String,
|
runtime_key: Option<String>,
|
||||||
|
runtime_status: String,
|
||||||
|
executable_in_runtime: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
const REAL_GROUPED_EFFECT_DESCRIPTOR_METADATA: [RealGroupedEffectDescriptorMetadata; 12] = [
|
const REAL_GROUPED_EFFECT_DESCRIPTOR_METADATA: [RealGroupedEffectDescriptorMetadata; 12] = [
|
||||||
|
|
@ -281,10 +280,10 @@ fn checked_in_event_effect_descriptor_rows()
|
||||||
-> &'static BTreeMap<u32, RealGroupedEffectDescriptorMetadata> {
|
-> &'static BTreeMap<u32, RealGroupedEffectDescriptorMetadata> {
|
||||||
static ROWS: OnceLock<BTreeMap<u32, RealGroupedEffectDescriptorMetadata>> = OnceLock::new();
|
static ROWS: OnceLock<BTreeMap<u32, RealGroupedEffectDescriptorMetadata>> = OnceLock::new();
|
||||||
ROWS.get_or_init(|| {
|
ROWS.get_or_init(|| {
|
||||||
let artifact: CheckedInEventEffectsTableArtifact = serde_json::from_str(include_str!(
|
let artifact: CheckedInEventEffectsSemanticCatalogArtifact = serde_json::from_str(
|
||||||
"../../../artifacts/exports/rt3-1.06/event-effects-table.json"
|
include_str!("../../../artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json"),
|
||||||
))
|
)
|
||||||
.expect("checked-in event-effects artifact should parse");
|
.expect("checked-in event-effects semantic catalog should parse");
|
||||||
artifact
|
artifact
|
||||||
.descriptors
|
.descriptors
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -299,14 +298,20 @@ fn checked_in_event_effect_descriptor_rows()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn checked_in_event_effect_descriptor_metadata(
|
fn checked_in_event_effect_descriptor_metadata(
|
||||||
row: CheckedInEventEffectDescriptorRow,
|
row: CheckedInEventEffectSemanticRow,
|
||||||
) -> RealGroupedEffectDescriptorMetadata {
|
) -> RealGroupedEffectDescriptorMetadata {
|
||||||
let label = Box::leak(row.label.clone().into_boxed_str()) as &'static str;
|
let label = Box::leak(row.label.clone().into_boxed_str()) as &'static str;
|
||||||
let (parameter_family, runtime_key, runtime_status, executable_in_runtime) =
|
let parameter_family = Box::leak(row.parameter_family.into_boxed_str()) as &'static str;
|
||||||
classify_checked_in_event_effect_descriptor(&row, label);
|
let runtime_key = row
|
||||||
debug_assert!(!row.signature_hex_0x63_0x6d.is_empty());
|
.runtime_key
|
||||||
debug_assert!(row.label_id <= u16::MAX as u32);
|
.map(|key| Box::leak(key.into_boxed_str()) as &'static str);
|
||||||
let _ = row.selector_order;
|
let runtime_status = match row.runtime_status.as_str() {
|
||||||
|
"executable" => RealGroupedEffectRuntimeStatus::Executable,
|
||||||
|
"shell_owned" => RealGroupedEffectRuntimeStatus::ShellOwned,
|
||||||
|
"evidence_blocked" => RealGroupedEffectRuntimeStatus::EvidenceBlocked,
|
||||||
|
"variant_or_scope_blocked" => RealGroupedEffectRuntimeStatus::VariantOrScopeBlocked,
|
||||||
|
other => panic!("unknown checked-in event-effect runtime status {other}"),
|
||||||
|
};
|
||||||
RealGroupedEffectDescriptorMetadata {
|
RealGroupedEffectDescriptorMetadata {
|
||||||
descriptor_id: row.descriptor_id,
|
descriptor_id: row.descriptor_id,
|
||||||
label,
|
label,
|
||||||
|
|
@ -314,141 +319,10 @@ fn checked_in_event_effect_descriptor_metadata(
|
||||||
parameter_family,
|
parameter_family,
|
||||||
runtime_key,
|
runtime_key,
|
||||||
runtime_status,
|
runtime_status,
|
||||||
executable_in_runtime,
|
executable_in_runtime: row.executable_in_runtime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn classify_checked_in_event_effect_descriptor(
|
|
||||||
row: &CheckedInEventEffectDescriptorRow,
|
|
||||||
label: &'static str,
|
|
||||||
) -> (
|
|
||||||
&'static str,
|
|
||||||
Option<&'static str>,
|
|
||||||
RealGroupedEffectRuntimeStatus,
|
|
||||||
bool,
|
|
||||||
) {
|
|
||||||
let descriptor_id = row.descriptor_id;
|
|
||||||
match descriptor_id {
|
|
||||||
4..=7 => {
|
|
||||||
return (
|
|
||||||
"scenario_outcome_shell_action",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::ShellOwned,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
10 | 11 | 12 | 23 => {
|
|
||||||
return (
|
|
||||||
"company_confiscation_variant",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::VariantOrScopeBlocked,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
17..=21 => {
|
|
||||||
return (
|
|
||||||
"company_or_territory_destruction_variant",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::ShellOwned,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
24 => {
|
|
||||||
return (
|
|
||||||
"control_transfer_shell_action",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::ShellOwned,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
56 => {
|
|
||||||
return (
|
|
||||||
"company_governance_scalar",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::Executable,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
57 => {
|
|
||||||
return (
|
|
||||||
"company_governance_scalar",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::Executable,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
58 => {
|
|
||||||
return (
|
|
||||||
"company_finance_shell_scalar",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::ShellOwned,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if row.signature_byte_0x63 == 0 && row.signature_byte_0x64 == 0x8f {
|
|
||||||
return (
|
|
||||||
"runtime_variable_scalar",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::EvidenceBlocked,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if row.target_mask_bits == 0x0b && label == "Stock Prices" {
|
|
||||||
return (
|
|
||||||
"company_finance_shell_scalar",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::ShellOwned,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if label.contains("Cost")
|
|
||||||
|| label.contains("Revenue")
|
|
||||||
|| label.contains("Speed")
|
|
||||||
|| label.contains("Reliability")
|
|
||||||
|| label.contains("Acceleration")
|
|
||||||
|| label.contains("Pulling Power")
|
|
||||||
|| label.contains("Usage Rate")
|
|
||||||
|| label.contains("Maintenance")
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
"world_scalar_economy_or_locomotive",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::EvidenceBlocked,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if label.contains("Earthquake") || label.contains("Storm") {
|
|
||||||
return (
|
|
||||||
"world_disaster_scalar",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::EvidenceBlocked,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if label.contains("Add Building") {
|
|
||||||
return (
|
|
||||||
"world_building_spawn",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::ShellOwned,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
|
||||||
"recovered_effect_table_descriptor",
|
|
||||||
None,
|
|
||||||
RealGroupedEffectRuntimeStatus::EvidenceBlocked,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn grouped_effect_descriptor_runtime_status_name(
|
pub(crate) fn grouped_effect_descriptor_runtime_status_name(
|
||||||
descriptor_id: u32,
|
descriptor_id: u32,
|
||||||
) -> Option<&'static str> {
|
) -> Option<&'static str> {
|
||||||
|
|
@ -4101,7 +3975,27 @@ fn runtime_world_flag_key(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runtime_world_flag_key_from_label(label: &str) -> String {
|
pub(crate) fn runtime_world_flag_key_from_label(label: &str) -> String {
|
||||||
|
normalize_runtime_world_key(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn runtime_world_scalar_key(
|
||||||
|
descriptor_metadata: RealGroupedEffectDescriptorMetadata,
|
||||||
|
) -> Option<String> {
|
||||||
|
descriptor_metadata
|
||||||
|
.runtime_key
|
||||||
|
.map(str::to_string)
|
||||||
|
.or_else(|| {
|
||||||
|
(descriptor_metadata.parameter_family == "world_scalar_override")
|
||||||
|
.then(|| normalize_runtime_world_key(descriptor_metadata.label))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn runtime_world_scalar_key_from_label(label: &str) -> String {
|
||||||
|
normalize_runtime_world_key(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_runtime_world_key(label: &str) -> String {
|
||||||
let mut key = String::with_capacity(label.len() + 6);
|
let mut key = String::with_capacity(label.len() + 6);
|
||||||
key.push_str("world.");
|
key.push_str("world.");
|
||||||
let mut last_was_underscore = false;
|
let mut last_was_underscore = false;
|
||||||
|
|
@ -4140,6 +4034,9 @@ fn derive_real_grouped_target_subject(
|
||||||
if row.parameter_family.as_deref() == Some("company_governance_scalar") {
|
if row.parameter_family.as_deref() == Some("company_governance_scalar") {
|
||||||
return Some(RealGroupedTargetSubject::Company);
|
return Some(RealGroupedTargetSubject::Company);
|
||||||
}
|
}
|
||||||
|
if row.parameter_family.as_deref() == Some("world_scalar_override") {
|
||||||
|
return Some(RealGroupedTargetSubject::WholeGame);
|
||||||
|
}
|
||||||
match row.target_mask_bits {
|
match row.target_mask_bits {
|
||||||
Some(0x08) => Some(RealGroupedTargetSubject::WholeGame),
|
Some(0x08) => Some(RealGroupedTargetSubject::WholeGame),
|
||||||
Some(0x01) => Some(RealGroupedTargetSubject::Company),
|
Some(0x01) => Some(RealGroupedTargetSubject::Company),
|
||||||
|
|
@ -4353,6 +4250,16 @@ fn decode_real_grouped_effect_action(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if descriptor_metadata.executable_in_runtime
|
||||||
|
&& descriptor_metadata.parameter_family == "world_scalar_override"
|
||||||
|
&& row.row_shape == "scalar_assignment"
|
||||||
|
{
|
||||||
|
return Some(RuntimeEffect::SetWorldScalarOverride {
|
||||||
|
key: runtime_world_scalar_key(descriptor_metadata)?,
|
||||||
|
value: i64::from(row.raw_scalar_value),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
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"
|
||||||
|
|
@ -4657,6 +4564,7 @@ fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
|
||||||
| RuntimeEffect::SetNamedLocomotiveAvailabilityValue { .. }
|
| RuntimeEffect::SetNamedLocomotiveAvailabilityValue { .. }
|
||||||
| RuntimeEffect::SetNamedLocomotiveCost { .. }
|
| RuntimeEffect::SetNamedLocomotiveCost { .. }
|
||||||
| RuntimeEffect::SetCargoProductionSlot { .. }
|
| RuntimeEffect::SetCargoProductionSlot { .. }
|
||||||
|
| RuntimeEffect::SetWorldScalarOverride { .. }
|
||||||
| RuntimeEffect::SetTerritoryAccessCost { .. }
|
| RuntimeEffect::SetTerritoryAccessCost { .. }
|
||||||
| RuntimeEffect::SetSpecialCondition { .. }
|
| RuntimeEffect::SetSpecialCondition { .. }
|
||||||
| RuntimeEffect::ConfiscateCompanyAssets { .. }
|
| RuntimeEffect::ConfiscateCompanyAssets { .. }
|
||||||
|
|
|
||||||
|
|
@ -313,6 +313,9 @@ fn apply_runtime_effects(
|
||||||
RuntimeEffect::SetWorldFlag { key, value } => {
|
RuntimeEffect::SetWorldFlag { key, value } => {
|
||||||
state.world_flags.insert(key.clone(), *value);
|
state.world_flags.insert(key.clone(), *value);
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetWorldScalarOverride { key, value } => {
|
||||||
|
state.world_scalar_overrides.insert(key.clone(), *value);
|
||||||
|
}
|
||||||
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
|
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
|
||||||
state.world_restore.limited_track_building_amount = Some(*value);
|
state.world_restore.limited_track_building_amount = Some(*value);
|
||||||
}
|
}
|
||||||
|
|
@ -1559,6 +1562,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
}
|
}
|
||||||
|
|
@ -1912,6 +1916,10 @@ mod tests {
|
||||||
has_fired: false,
|
has_fired: false,
|
||||||
conditions: Vec::new(),
|
conditions: Vec::new(),
|
||||||
effects: vec![
|
effects: vec![
|
||||||
|
RuntimeEffect::SetWorldScalarOverride {
|
||||||
|
key: "world.build_stations_cost".to_string(),
|
||||||
|
value: 350000,
|
||||||
|
},
|
||||||
RuntimeEffect::SetCargoProductionSlot {
|
RuntimeEffect::SetCargoProductionSlot {
|
||||||
slot: 1,
|
slot: 1,
|
||||||
value: 125,
|
value: 125,
|
||||||
|
|
@ -1928,9 +1936,15 @@ mod tests {
|
||||||
)
|
)
|
||||||
.expect("world scalar override effects should succeed");
|
.expect("world scalar override effects should succeed");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
state
|
||||||
|
.world_scalar_overrides
|
||||||
|
.get("world.build_stations_cost"),
|
||||||
|
Some(&350000)
|
||||||
|
);
|
||||||
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, 2);
|
assert_eq!(result.service_events[0].applied_effect_count, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,8 @@ pub struct RuntimeSummary {
|
||||||
pub packed_event_blocked_unmapped_world_condition_count: usize,
|
pub packed_event_blocked_unmapped_world_condition_count: usize,
|
||||||
pub packed_event_blocked_missing_compact_control_count: usize,
|
pub packed_event_blocked_missing_compact_control_count: usize,
|
||||||
pub packed_event_blocked_shell_owned_descriptor_count: usize,
|
pub packed_event_blocked_shell_owned_descriptor_count: usize,
|
||||||
|
pub packed_event_blocked_evidence_blocked_descriptor_count: usize,
|
||||||
|
pub packed_event_blocked_variant_or_scope_blocked_descriptor_count: usize,
|
||||||
pub packed_event_blocked_unmapped_real_descriptor_count: usize,
|
pub packed_event_blocked_unmapped_real_descriptor_count: usize,
|
||||||
pub packed_event_blocked_unmapped_world_descriptor_count: usize,
|
pub packed_event_blocked_unmapped_world_descriptor_count: usize,
|
||||||
pub packed_event_blocked_territory_access_variant_count: usize,
|
pub packed_event_blocked_territory_access_variant_count: usize,
|
||||||
|
|
@ -89,6 +91,7 @@ pub struct RuntimeSummary {
|
||||||
pub zero_named_locomotive_availability_count: usize,
|
pub zero_named_locomotive_availability_count: usize,
|
||||||
pub named_locomotive_cost_count: usize,
|
pub named_locomotive_cost_count: usize,
|
||||||
pub cargo_production_override_count: usize,
|
pub cargo_production_override_count: usize,
|
||||||
|
pub world_scalar_override_count: usize,
|
||||||
pub special_condition_count: usize,
|
pub special_condition_count: usize,
|
||||||
pub enabled_special_condition_count: usize,
|
pub enabled_special_condition_count: usize,
|
||||||
pub save_profile_kind: Option<String>,
|
pub save_profile_kind: Option<String>,
|
||||||
|
|
@ -511,6 +514,34 @@ impl RuntimeSummary {
|
||||||
.count()
|
.count()
|
||||||
})
|
})
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
|
packed_event_blocked_evidence_blocked_descriptor_count: state
|
||||||
|
.packed_event_collection
|
||||||
|
.as_ref()
|
||||||
|
.map(|summary| {
|
||||||
|
summary
|
||||||
|
.records
|
||||||
|
.iter()
|
||||||
|
.filter(|record| {
|
||||||
|
record.import_outcome.as_deref()
|
||||||
|
== Some("blocked_evidence_blocked_descriptor")
|
||||||
|
})
|
||||||
|
.count()
|
||||||
|
})
|
||||||
|
.unwrap_or(0),
|
||||||
|
packed_event_blocked_variant_or_scope_blocked_descriptor_count: state
|
||||||
|
.packed_event_collection
|
||||||
|
.as_ref()
|
||||||
|
.map(|summary| {
|
||||||
|
summary
|
||||||
|
.records
|
||||||
|
.iter()
|
||||||
|
.filter(|record| {
|
||||||
|
record.import_outcome.as_deref()
|
||||||
|
== Some("blocked_variant_or_scope_blocked_descriptor")
|
||||||
|
})
|
||||||
|
.count()
|
||||||
|
})
|
||||||
|
.unwrap_or(0),
|
||||||
packed_event_blocked_unmapped_real_descriptor_count: state
|
packed_event_blocked_unmapped_real_descriptor_count: state
|
||||||
.packed_event_collection
|
.packed_event_collection
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
@ -676,6 +707,7 @@ impl RuntimeSummary {
|
||||||
.count(),
|
.count(),
|
||||||
named_locomotive_cost_count: state.named_locomotive_cost.len(),
|
named_locomotive_cost_count: state.named_locomotive_cost.len(),
|
||||||
cargo_production_override_count: state.cargo_production_overrides.len(),
|
cargo_production_override_count: state.cargo_production_overrides.len(),
|
||||||
|
world_scalar_override_count: state.world_scalar_overrides.len(),
|
||||||
special_condition_count: state.special_conditions.len(),
|
special_condition_count: state.special_conditions.len(),
|
||||||
enabled_special_condition_count: state
|
enabled_special_condition_count: state
|
||||||
.special_conditions
|
.special_conditions
|
||||||
|
|
@ -903,6 +935,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -1019,6 +1052,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -1072,6 +1106,7 @@ mod tests {
|
||||||
]),
|
]),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -1117,6 +1152,7 @@ mod tests {
|
||||||
("GP7".to_string(), 175000),
|
("GP7".to_string(), 175000),
|
||||||
]),
|
]),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -1160,6 +1196,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: 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(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -1265,6 +1302,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -1348,6 +1386,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
@ -1427,6 +1466,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -98,12 +98,21 @@ The highest-value next passes are now:
|
||||||
can execute from standalone save-slice fixtures without overlay snapshots when that context is
|
can execute from standalone save-slice fixtures without overlay snapshots when that context is
|
||||||
present; raw `.gms` inspection/export still does not reconstruct those company/chairman surfaces
|
present; raw `.gms` inspection/export still does not reconstruct those company/chairman surfaces
|
||||||
- a checked-in `EventEffects` export now exists at
|
- a checked-in `EventEffects` export now exists at
|
||||||
`artifacts/exports/rt3-1.06/event-effects-table.json`, and the first recovered governance
|
`artifacts/exports/rt3-1.06/event-effects-table.json`, and a checked-in semantic closure layer
|
||||||
descriptor tranche now executes through the generic company-governance scalar effect surface:
|
now exists at `artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json`
|
||||||
descriptor `56` `Credit Rating` and descriptor `57` `Prime Rate`
|
- recovered descriptor rows now land on explicit semantic frontier buckets such as
|
||||||
|
`blocked_shell_owned_descriptor`, `blocked_evidence_blocked_descriptor`, and
|
||||||
|
`blocked_variant_or_scope_blocked_descriptor` instead of generic unmapped-descriptor residue
|
||||||
|
- the first recovered governance descriptor tranche now executes through the generic
|
||||||
|
company-governance scalar effect surface: descriptor `56` `Credit Rating` and descriptor `57`
|
||||||
|
`Prime Rate`
|
||||||
- adjacent recovered finance/control-transfer descriptors such as `55` `Stock Prices` and `58`
|
- adjacent recovered finance/control-transfer descriptors such as `55` `Stock Prices` and `58`
|
||||||
`Merger Premium` now land on explicit shell-owned descriptor parity instead of generic unmapped
|
`Merger Premium` now land on explicit shell-owned descriptor parity instead of generic unmapped
|
||||||
descriptor residue
|
descriptor residue
|
||||||
|
- the recovered whole-game scalar economy/performance strip `59..104` now has a bounded runtime
|
||||||
|
landing surface too: representative rows execute into `RuntimeState.world_scalar_overrides`
|
||||||
|
through stable normalized keys such as `world.build_stations_cost` and
|
||||||
|
`world.track_maintenance_cost`
|
||||||
- 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`
|
||||||
|
|
@ -203,6 +212,14 @@ python3 tools/py/extract_event_effects.py \
|
||||||
artifacts/exports/rt3-1.06/event-effects-table.json
|
artifacts/exports/rt3-1.06/event-effects-table.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Regenerate the checked-in `EventEffects` semantic catalog with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 tools/py/build_event_effect_semantic_catalog.py \
|
||||||
|
artifacts/exports/rt3-1.06/event-effects-table.json \
|
||||||
|
artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json
|
||||||
|
```
|
||||||
|
|
||||||
That default export now walks two roots:
|
That default export now walks two roots:
|
||||||
|
|
||||||
- `entry:0x005a313b`
|
- `entry:0x005a313b`
|
||||||
|
|
|
||||||
|
|
@ -61,13 +61,20 @@ Implemented today:
|
||||||
without overlay snapshots when the checked-in documents include that context, while raw `.gms`
|
without overlay snapshots when the checked-in documents include that context, while raw `.gms`
|
||||||
inspection/export still leaves those company/chairman surfaces absent
|
inspection/export still leaves those company/chairman surfaces absent
|
||||||
- a checked-in `EventEffects` export now exists too at
|
- a checked-in `EventEffects` export now exists too at
|
||||||
`artifacts/exports/rt3-1.06/event-effects-table.json`, and the first recovered
|
`artifacts/exports/rt3-1.06/event-effects-table.json`, and a checked-in semantic closure layer
|
||||||
company-governance descriptor tranche now executes through the generic
|
now exists at `artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json`
|
||||||
|
- recovered descriptor rows now classify into explicit semantic frontier buckets such as
|
||||||
|
`blocked_shell_owned_descriptor`, `blocked_evidence_blocked_descriptor`, and
|
||||||
|
`blocked_variant_or_scope_blocked_descriptor` instead of generic unmapped-descriptor buckets
|
||||||
|
- the first recovered company-governance descriptor tranche now executes through the generic
|
||||||
`SetCompanyGovernanceScalar` surface: descriptor `56` `Credit Rating` and descriptor `57`
|
`SetCompanyGovernanceScalar` surface: descriptor `56` `Credit Rating` and descriptor `57`
|
||||||
`Prime Rate` now import through ordinary company target lowering
|
`Prime Rate` now import through ordinary company target lowering
|
||||||
- adjacent recovered finance/control-transfer descriptors such as `55` `Stock Prices` and `58`
|
- adjacent recovered finance/control-transfer descriptors such as `55` `Stock Prices` and `58`
|
||||||
`Merger Premium` now land on explicit shell-owned descriptor parity instead of generic unmapped
|
`Merger Premium` now land on explicit shell-owned descriptor parity instead of generic unmapped
|
||||||
descriptor buckets
|
descriptor buckets
|
||||||
|
- 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
|
||||||
|
`RuntimeState.world_scalar_overrides`
|
||||||
- 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
|
||||||
|
|
@ -138,11 +145,11 @@ Implemented today:
|
||||||
|
|
||||||
That means the next implementation work is still breadth, not bootstrap. The current descriptor
|
That means the next implementation work is still breadth, not bootstrap. The current descriptor
|
||||||
frontier is no longer anonymous id recovery; it is the remaining recovered-but-nonexecutable
|
frontier is no longer anonymous id recovery; it is the remaining recovered-but-nonexecutable
|
||||||
families from the checked-in effect table, especially broader company/world scalar bands and the
|
families from the checked-in semantic catalog, especially cargo-price, add-building, and other
|
||||||
shell-owned finance/control-transfer rows that still need final classification or bounded runtime
|
descriptor clusters that now have explicit shell-owned or evidence-blocked status but not yet a
|
||||||
landing surfaces. Raw save reconstruction for company/chairman context is still a later tranche
|
bounded executable landing surface. Raw save reconstruction for company/chairman context is still a
|
||||||
once stronger evidence exists. Richer runtime ownership should still be added only where a later
|
later tranche once stronger evidence exists. Richer runtime ownership should still be added only
|
||||||
descriptor or condition family needs more than the current event-owned roster.
|
where a later descriptor or condition family needs more than the current event-owned roster.
|
||||||
|
|
||||||
## Why This Boundary
|
## Why This Boundary
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,9 @@
|
||||||
"packed_event_blocked_missing_condition_context_count": 0,
|
"packed_event_blocked_missing_condition_context_count": 0,
|
||||||
"packed_event_blocked_territory_condition_scope_count": 0,
|
"packed_event_blocked_territory_condition_scope_count": 0,
|
||||||
"packed_event_blocked_missing_compact_control_count": 0,
|
"packed_event_blocked_missing_compact_control_count": 0,
|
||||||
|
"packed_event_blocked_evidence_blocked_descriptor_count": 1,
|
||||||
"packed_event_blocked_unmapped_real_descriptor_count": 0,
|
"packed_event_blocked_unmapped_real_descriptor_count": 0,
|
||||||
"packed_event_blocked_unmapped_world_descriptor_count": 1,
|
"packed_event_blocked_unmapped_world_descriptor_count": 0,
|
||||||
"packed_event_blocked_structural_only_count": 0,
|
"packed_event_blocked_structural_only_count": 0,
|
||||||
"event_runtime_record_count": 2,
|
"event_runtime_record_count": 2,
|
||||||
"cargo_production_override_count": 0,
|
"cargo_production_override_count": 0,
|
||||||
|
|
@ -67,7 +68,7 @@
|
||||||
{
|
{
|
||||||
"decode_status": "parity_only",
|
"decode_status": "parity_only",
|
||||||
"payload_family": "real_packed_v1",
|
"payload_family": "real_packed_v1",
|
||||||
"import_outcome": "blocked_unmapped_world_descriptor",
|
"import_outcome": "blocked_evidence_blocked_descriptor",
|
||||||
"grouped_effect_rows": [
|
"grouped_effect_rows": [
|
||||||
{
|
{
|
||||||
"descriptor_id": 352,
|
"descriptor_id": 352,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
{
|
||||||
|
"format_version": 1,
|
||||||
|
"fixture_id": "packed-event-world-scalar-override-save-slice-fixture",
|
||||||
|
"source": {
|
||||||
|
"kind": "captured-runtime",
|
||||||
|
"description": "Fixture proving representative 59..104 world scalar descriptors execute through the bounded world_scalar_overrides runtime surface."
|
||||||
|
},
|
||||||
|
"state_save_slice_path": "packed-event-world-scalar-override-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,
|
||||||
|
"world_scalar_override_count": 4,
|
||||||
|
"total_event_record_service_count": 1,
|
||||||
|
"total_trigger_dispatch_count": 1
|
||||||
|
},
|
||||||
|
"expected_state_fragment": {
|
||||||
|
"world_scalar_overrides": {
|
||||||
|
"world.build_stations_cost": 350000,
|
||||||
|
"world.track_maintenance_cost": 22000,
|
||||||
|
"world.all_engine_speeds": 115,
|
||||||
|
"world.hotel_revenue": 175
|
||||||
|
},
|
||||||
|
"packed_event_collection": {
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"import_outcome": "imported"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"event_runtime_records": [
|
||||||
|
{
|
||||||
|
"record_id": 61,
|
||||||
|
"service_count": 1,
|
||||||
|
"effects": [
|
||||||
|
{
|
||||||
|
"kind": "set_world_scalar_override",
|
||||||
|
"key": "world.build_stations_cost",
|
||||||
|
"value": 350000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "set_world_scalar_override",
|
||||||
|
"key": "world.track_maintenance_cost",
|
||||||
|
"value": 22000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "set_world_scalar_override",
|
||||||
|
"key": "world.all_engine_speeds",
|
||||||
|
"value": 115
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "set_world_scalar_override",
|
||||||
|
"key": "world.hotel_revenue",
|
||||||
|
"value": 175
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,198 @@
|
||||||
|
{
|
||||||
|
"format_version": 1,
|
||||||
|
"save_slice_id": "packed-event-world-scalar-override-save-slice",
|
||||||
|
"source": {
|
||||||
|
"description": "Tracked save-slice document proving the checked-in scalar economy/performance descriptor band imports into world_scalar_overrides.",
|
||||||
|
"original_save_filename": "captured-world-scalar-override.gms",
|
||||||
|
"original_save_sha256": "world-scalar-override-sample-sha256",
|
||||||
|
"notes": [
|
||||||
|
"tracked as JSON save-slice document rather than raw .smp",
|
||||||
|
"pins representative executable descriptors from the recovered 59..104 economy/performance band"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"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,
|
||||||
|
"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": 31360,
|
||||||
|
"records_tag_offset": 31616,
|
||||||
|
"close_tag_offset": 32128,
|
||||||
|
"packed_state_version": 1001,
|
||||||
|
"packed_state_version_hex": "0x000003e9",
|
||||||
|
"live_id_bound": 61,
|
||||||
|
"live_record_count": 1,
|
||||||
|
"live_entry_ids": [61],
|
||||||
|
"decoded_record_count": 1,
|
||||||
|
"imported_runtime_record_count": 0,
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"record_index": 0,
|
||||||
|
"live_entry_id": 61,
|
||||||
|
"payload_offset": 31648,
|
||||||
|
"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": 59,
|
||||||
|
"descriptor_label": "Build Stations Cost",
|
||||||
|
"target_mask_bits": 15,
|
||||||
|
"parameter_family": "world_scalar_override",
|
||||||
|
"opcode": 3,
|
||||||
|
"raw_scalar_value": 350000,
|
||||||
|
"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 Build Stations Cost to 350000",
|
||||||
|
"recovered_locomotive_id": null,
|
||||||
|
"locomotive_name": null,
|
||||||
|
"notes": [
|
||||||
|
"descriptor recovered from checked-in EventEffects semantic catalog"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_index": 0,
|
||||||
|
"row_index": 1,
|
||||||
|
"descriptor_id": 66,
|
||||||
|
"descriptor_label": "Track Maintenance Cost",
|
||||||
|
"target_mask_bits": 11,
|
||||||
|
"parameter_family": "world_scalar_override",
|
||||||
|
"opcode": 3,
|
||||||
|
"raw_scalar_value": 22000,
|
||||||
|
"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 Track Maintenance Cost to 22000",
|
||||||
|
"recovered_locomotive_id": null,
|
||||||
|
"locomotive_name": null,
|
||||||
|
"notes": [
|
||||||
|
"descriptor recovered from checked-in EventEffects semantic catalog"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_index": 0,
|
||||||
|
"row_index": 2,
|
||||||
|
"descriptor_id": 81,
|
||||||
|
"descriptor_label": "All Engine Speeds",
|
||||||
|
"target_mask_bits": 15,
|
||||||
|
"parameter_family": "world_scalar_override",
|
||||||
|
"opcode": 3,
|
||||||
|
"raw_scalar_value": 115,
|
||||||
|
"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 Engine Speeds to 115",
|
||||||
|
"recovered_locomotive_id": null,
|
||||||
|
"locomotive_name": null,
|
||||||
|
"notes": [
|
||||||
|
"descriptor recovered from checked-in EventEffects semantic catalog"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_index": 0,
|
||||||
|
"row_index": 3,
|
||||||
|
"descriptor_id": 102,
|
||||||
|
"descriptor_label": "Hotel Revenue",
|
||||||
|
"target_mask_bits": 15,
|
||||||
|
"parameter_family": "world_scalar_override",
|
||||||
|
"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 Hotel Revenue to 175",
|
||||||
|
"recovered_locomotive_id": null,
|
||||||
|
"locomotive_name": null,
|
||||||
|
"notes": [
|
||||||
|
"descriptor recovered from checked-in EventEffects semantic catalog"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"decoded_actions": [
|
||||||
|
{
|
||||||
|
"kind": "set_world_scalar_override",
|
||||||
|
"key": "world.build_stations_cost",
|
||||||
|
"value": 350000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "set_world_scalar_override",
|
||||||
|
"key": "world.track_maintenance_cost",
|
||||||
|
"value": 22000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "set_world_scalar_override",
|
||||||
|
"key": "world.all_engine_speeds",
|
||||||
|
"value": 115
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "set_world_scalar_override",
|
||||||
|
"key": "world.hotel_revenue",
|
||||||
|
"value": 175
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"executable_import_ready": true,
|
||||||
|
"notes": [
|
||||||
|
"representative whole-game scalar economy/performance descriptors execute through world_scalar_overrides"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notes": [
|
||||||
|
"world scalar override executable sample"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
124
tools/py/build_event_effect_semantic_catalog.py
Normal file
124
tools/py/build_event_effect_semantic_catalog.py
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_world_scalar_key(label: str) -> str:
|
||||||
|
parts: list[str] = []
|
||||||
|
current = []
|
||||||
|
for ch in label:
|
||||||
|
if ch.isalnum():
|
||||||
|
current.append(ch.lower())
|
||||||
|
elif current:
|
||||||
|
parts.append("".join(current))
|
||||||
|
current = []
|
||||||
|
if current:
|
||||||
|
parts.append("".join(current))
|
||||||
|
return "world." + "_".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
def classify(row: dict[str, object]) -> dict[str, object]:
|
||||||
|
descriptor_id = int(row["descriptor_id"])
|
||||||
|
label = str(row["label"])
|
||||||
|
signature_byte_0x63 = int(row["signature_byte_0x63"])
|
||||||
|
signature_byte_0x64 = int(row["signature_byte_0x64"])
|
||||||
|
|
||||||
|
parameter_family = "recovered_effect_table_descriptor"
|
||||||
|
runtime_key = None
|
||||||
|
runtime_status = "evidence_blocked"
|
||||||
|
executable_in_runtime = False
|
||||||
|
|
||||||
|
if 4 <= descriptor_id <= 7:
|
||||||
|
parameter_family = "scenario_outcome_shell_action"
|
||||||
|
runtime_status = "shell_owned"
|
||||||
|
elif descriptor_id in {10, 11, 12, 23}:
|
||||||
|
parameter_family = "company_confiscation_variant"
|
||||||
|
runtime_status = "variant_or_scope_blocked"
|
||||||
|
elif 17 <= descriptor_id <= 21:
|
||||||
|
parameter_family = "company_or_territory_destruction_variant"
|
||||||
|
runtime_status = "shell_owned"
|
||||||
|
elif descriptor_id == 24:
|
||||||
|
parameter_family = "control_transfer_shell_action"
|
||||||
|
runtime_status = "shell_owned"
|
||||||
|
elif descriptor_id in {55, 58}:
|
||||||
|
parameter_family = "company_finance_shell_scalar"
|
||||||
|
runtime_status = "shell_owned"
|
||||||
|
elif descriptor_id in {56, 57}:
|
||||||
|
parameter_family = "company_governance_scalar"
|
||||||
|
runtime_status = "executable"
|
||||||
|
executable_in_runtime = True
|
||||||
|
elif 59 <= descriptor_id <= 104:
|
||||||
|
parameter_family = "world_scalar_override"
|
||||||
|
runtime_key = normalize_world_scalar_key(label)
|
||||||
|
runtime_status = "executable"
|
||||||
|
executable_in_runtime = True
|
||||||
|
elif 105 <= descriptor_id <= 176:
|
||||||
|
parameter_family = "cargo_price_scalar"
|
||||||
|
elif 177 <= descriptor_id <= 240:
|
||||||
|
parameter_family = "cargo_production_scalar"
|
||||||
|
elif 241 <= descriptor_id <= 351 or 457 <= descriptor_id <= 474:
|
||||||
|
parameter_family = "locomotive_availability_scalar"
|
||||||
|
elif 352 <= descriptor_id <= 451 or 475 <= descriptor_id <= 502:
|
||||||
|
parameter_family = "locomotive_cost_scalar"
|
||||||
|
elif descriptor_id == 453:
|
||||||
|
parameter_family = "territory_access_cost_scalar"
|
||||||
|
runtime_status = "executable"
|
||||||
|
executable_in_runtime = True
|
||||||
|
elif descriptor_id == 454:
|
||||||
|
parameter_family = "world_flag_toggle"
|
||||||
|
runtime_key = "world.all_steam_locos_available"
|
||||||
|
runtime_status = "executable"
|
||||||
|
executable_in_runtime = True
|
||||||
|
elif descriptor_id == 455:
|
||||||
|
parameter_family = "world_flag_toggle"
|
||||||
|
runtime_key = "world.all_diesel_locos_available"
|
||||||
|
runtime_status = "executable"
|
||||||
|
executable_in_runtime = True
|
||||||
|
elif descriptor_id == 456:
|
||||||
|
parameter_family = "world_flag_toggle"
|
||||||
|
runtime_key = "world.all_electric_locos_available"
|
||||||
|
runtime_status = "executable"
|
||||||
|
executable_in_runtime = True
|
||||||
|
elif 503 <= descriptor_id <= 519:
|
||||||
|
parameter_family = "world_building_spawn"
|
||||||
|
runtime_status = "shell_owned"
|
||||||
|
elif signature_byte_0x63 == 0 and signature_byte_0x64 == 0x8F:
|
||||||
|
parameter_family = "runtime_variable_scalar"
|
||||||
|
elif "Earthquake" in label or "Storm" in label:
|
||||||
|
parameter_family = "world_disaster_scalar"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"descriptor_id": descriptor_id,
|
||||||
|
"label": label,
|
||||||
|
"target_mask_bits": int(row["target_mask_bits"]),
|
||||||
|
"parameter_family": parameter_family,
|
||||||
|
"runtime_key": runtime_key,
|
||||||
|
"runtime_status": runtime_status,
|
||||||
|
"executable_in_runtime": executable_in_runtime,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Build a checked-in semantic catalog over the raw RT3 EventEffects table."
|
||||||
|
)
|
||||||
|
parser.add_argument("raw_table", type=Path)
|
||||||
|
parser.add_argument("out", type=Path)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
raw_artifact = json.loads(args.raw_table.read_text(encoding="utf-8"))
|
||||||
|
descriptors = [classify(row) for row in raw_artifact["descriptors"]]
|
||||||
|
artifact = {
|
||||||
|
"descriptor_count": len(descriptors),
|
||||||
|
"raw_table_binary_sha256": raw_artifact.get("binary_sha256"),
|
||||||
|
"semantic_catalog_version": 1,
|
||||||
|
"descriptors": descriptors,
|
||||||
|
}
|
||||||
|
args.out.write_text(json.dumps(artifact, indent=2) + "\n", encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue