Execute runtime variable event descriptors
This commit is contained in:
parent
6a5d028d19
commit
d3790c2ae3
17 changed files with 1300 additions and 79 deletions
11
README.md
11
README.md
|
|
@ -45,7 +45,10 @@ 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 grounded aggregate cargo-economics descriptors now have bounded
|
`world.hotel_revenue`. The runtime-variable strip `39..54` now executes too through bounded
|
||||||
|
event-owned scalar maps on world/company/player/territory state, without widening save-native
|
||||||
|
reconstruction or adding a second packed executor. The grounded aggregate cargo-economics
|
||||||
|
descriptors now have bounded
|
||||||
runtime landing surfaces too: descriptor `105` `All Cargo Prices` plus descriptors `177..179`
|
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
|
`All Cargo Production` / `All Factory Production` / `All Farm/Mine Production` import into
|
||||||
event-owned cargo override state, and the grounded named cargo-production strip `180..229` now
|
event-owned cargo override state, and the grounded named cargo-production strip `180..229` now
|
||||||
|
|
@ -90,8 +93,10 @@ scalar bands are now save-native too. Raw `.smp` inspection/export reconstructs
|
||||||
standalone save-slice imports can now lower the grounded lower locomotive availability and
|
standalone save-slice imports can now lower the grounded lower locomotive availability and
|
||||||
locomotive-cost rows directly into `RuntimeState.named_locomotive_availability` and
|
locomotive-cost rows directly into `RuntimeState.named_locomotive_availability` and
|
||||||
`RuntimeState.named_locomotive_cost` without needing overlay snapshots when the save carries enough
|
`RuntimeState.named_locomotive_cost` without needing overlay snapshots when the save carries enough
|
||||||
catalog context; the unresolved lower tail and upper locomotive bands now stay on explicit parity
|
catalog context, and the grounded executable lower prefix now extends through save-backed
|
||||||
instead of synthetic execution. The remaining recovered scalar world families execute too:
|
locomotive id `61` (`Zephyr`); the unresolved lower tail and upper locomotive bands now stay on
|
||||||
|
explicit parity instead of synthetic execution. The remaining recovered scalar world families
|
||||||
|
execute too:
|
||||||
cargo-production slots `230..240` lower into `cargo_production_overrides`, and descriptor `453`
|
cargo-production slots `230..240` lower into `cargo_production_overrides`, and descriptor `453`
|
||||||
lowers into
|
lowers into
|
||||||
`world_restore.territory_access_cost`. Whole-game ordinary-condition breadth now aligns with those
|
`world_restore.territory_access_cost`. Whole-game ordinary-condition breadth now aligns with those
|
||||||
|
|
|
||||||
|
|
@ -360,8 +360,8 @@
|
||||||
"target_mask_bits": 8,
|
"target_mask_bits": 8,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 40,
|
"descriptor_id": 40,
|
||||||
|
|
@ -369,8 +369,8 @@
|
||||||
"target_mask_bits": 8,
|
"target_mask_bits": 8,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 41,
|
"descriptor_id": 41,
|
||||||
|
|
@ -378,8 +378,8 @@
|
||||||
"target_mask_bits": 8,
|
"target_mask_bits": 8,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 42,
|
"descriptor_id": 42,
|
||||||
|
|
@ -387,8 +387,8 @@
|
||||||
"target_mask_bits": 8,
|
"target_mask_bits": 8,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 43,
|
"descriptor_id": 43,
|
||||||
|
|
@ -396,8 +396,8 @@
|
||||||
"target_mask_bits": 1,
|
"target_mask_bits": 1,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 44,
|
"descriptor_id": 44,
|
||||||
|
|
@ -405,8 +405,8 @@
|
||||||
"target_mask_bits": 1,
|
"target_mask_bits": 1,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 45,
|
"descriptor_id": 45,
|
||||||
|
|
@ -414,8 +414,8 @@
|
||||||
"target_mask_bits": 1,
|
"target_mask_bits": 1,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 46,
|
"descriptor_id": 46,
|
||||||
|
|
@ -423,8 +423,8 @@
|
||||||
"target_mask_bits": 1,
|
"target_mask_bits": 1,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 47,
|
"descriptor_id": 47,
|
||||||
|
|
@ -432,8 +432,8 @@
|
||||||
"target_mask_bits": 2,
|
"target_mask_bits": 2,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 48,
|
"descriptor_id": 48,
|
||||||
|
|
@ -441,8 +441,8 @@
|
||||||
"target_mask_bits": 2,
|
"target_mask_bits": 2,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 49,
|
"descriptor_id": 49,
|
||||||
|
|
@ -450,8 +450,8 @@
|
||||||
"target_mask_bits": 2,
|
"target_mask_bits": 2,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 50,
|
"descriptor_id": 50,
|
||||||
|
|
@ -459,8 +459,8 @@
|
||||||
"target_mask_bits": 2,
|
"target_mask_bits": 2,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 51,
|
"descriptor_id": 51,
|
||||||
|
|
@ -468,8 +468,8 @@
|
||||||
"target_mask_bits": 4,
|
"target_mask_bits": 4,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 52,
|
"descriptor_id": 52,
|
||||||
|
|
@ -477,8 +477,8 @@
|
||||||
"target_mask_bits": 4,
|
"target_mask_bits": 4,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 53,
|
"descriptor_id": 53,
|
||||||
|
|
@ -486,8 +486,8 @@
|
||||||
"target_mask_bits": 4,
|
"target_mask_bits": 4,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 54,
|
"descriptor_id": 54,
|
||||||
|
|
@ -495,8 +495,8 @@
|
||||||
"target_mask_bits": 4,
|
"target_mask_bits": 4,
|
||||||
"parameter_family": "runtime_variable_scalar",
|
"parameter_family": "runtime_variable_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 55,
|
"descriptor_id": 55,
|
||||||
|
|
@ -2696,30 +2696,30 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 299,
|
"descriptor_id": 299,
|
||||||
"label": "Lower-Band Locomotive Availability Slot 59",
|
"label": "GP 35 Availability",
|
||||||
"target_mask_bits": 11,
|
"target_mask_bits": 11,
|
||||||
"parameter_family": "locomotive_availability_scalar",
|
"parameter_family": "locomotive_availability_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 300,
|
"descriptor_id": 300,
|
||||||
"label": "Lower-Band Locomotive Availability Slot 60",
|
"label": "U1 Availability",
|
||||||
"target_mask_bits": 11,
|
"target_mask_bits": 11,
|
||||||
"parameter_family": "locomotive_availability_scalar",
|
"parameter_family": "locomotive_availability_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 301,
|
"descriptor_id": 301,
|
||||||
"label": "Lower-Band Locomotive Availability Slot 61",
|
"label": "Zephyr Availability",
|
||||||
"target_mask_bits": 11,
|
"target_mask_bits": 11,
|
||||||
"parameter_family": "locomotive_availability_scalar",
|
"parameter_family": "locomotive_availability_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 302,
|
"descriptor_id": 302,
|
||||||
|
|
@ -3695,30 +3695,30 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 410,
|
"descriptor_id": 410,
|
||||||
"label": "Lower-Band Locomotive Cost Slot 59",
|
"label": "GP 35 Cost",
|
||||||
"target_mask_bits": 11,
|
"target_mask_bits": 11,
|
||||||
"parameter_family": "locomotive_cost_scalar",
|
"parameter_family": "locomotive_cost_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 411,
|
"descriptor_id": 411,
|
||||||
"label": "Lower-Band Locomotive Cost Slot 60",
|
"label": "U1 Cost",
|
||||||
"target_mask_bits": 11,
|
"target_mask_bits": 11,
|
||||||
"parameter_family": "locomotive_cost_scalar",
|
"parameter_family": "locomotive_cost_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 412,
|
"descriptor_id": 412,
|
||||||
"label": "Lower-Band Locomotive Cost Slot 61",
|
"label": "Zephyr Cost",
|
||||||
"target_mask_bits": 11,
|
"target_mask_bits": 11,
|
||||||
"parameter_family": "locomotive_cost_scalar",
|
"parameter_family": "locomotive_cost_scalar",
|
||||||
"runtime_key": null,
|
"runtime_key": null,
|
||||||
"runtime_status": "evidence_blocked",
|
"runtime_status": "executable",
|
||||||
"executable_in_runtime": false
|
"executable_in_runtime": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"descriptor_id": 413,
|
"descriptor_id": 413,
|
||||||
|
|
|
||||||
|
|
@ -4479,6 +4479,8 @@ 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 runtime_variable_overlay_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||||
|
.join("../../fixtures/runtime/packed-event-runtime-variable-overlay-fixture.json");
|
||||||
let cargo_economics_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
let cargo_economics_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||||
.join("../../fixtures/runtime/packed-event-cargo-economics-save-slice-fixture.json");
|
.join("../../fixtures/runtime/packed-event-cargo-economics-save-slice-fixture.json");
|
||||||
let cargo_economics_parity_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
|
let cargo_economics_parity_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
|
||||||
|
|
@ -4595,6 +4597,8 @@ 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(&runtime_variable_overlay_fixture)
|
||||||
|
.expect("overlay-backed runtime-variable fixture should summarize");
|
||||||
run_runtime_summarize_fixture(&cargo_economics_fixture)
|
run_runtime_summarize_fixture(&cargo_economics_fixture)
|
||||||
.expect("save-slice-backed cargo-economics fixture should summarize");
|
.expect("save-slice-backed cargo-economics fixture should summarize");
|
||||||
run_runtime_summarize_fixture(&cargo_economics_parity_fixture)
|
run_runtime_summarize_fixture(&cargo_economics_parity_fixture)
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -390,6 +394,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,14 @@ 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_runtime_variable_count: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub company_runtime_variable_owner_count: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub player_runtime_variable_owner_count: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub territory_runtime_variable_owner_count: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
pub world_scalar_override_count: Option<usize>,
|
pub world_scalar_override_count: Option<usize>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub special_condition_count: Option<usize>,
|
pub special_condition_count: Option<usize>,
|
||||||
|
|
@ -927,6 +935,38 @@ impl ExpectedRuntimeSummary {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(count) = self.world_runtime_variable_count {
|
||||||
|
if actual.world_runtime_variable_count != count {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"world_runtime_variable_count mismatch: expected {count}, got {}",
|
||||||
|
actual.world_runtime_variable_count
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(count) = self.company_runtime_variable_owner_count {
|
||||||
|
if actual.company_runtime_variable_owner_count != count {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"company_runtime_variable_owner_count mismatch: expected {count}, got {}",
|
||||||
|
actual.company_runtime_variable_owner_count
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(count) = self.player_runtime_variable_owner_count {
|
||||||
|
if actual.player_runtime_variable_owner_count != count {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"player_runtime_variable_owner_count mismatch: expected {count}, got {}",
|
||||||
|
actual.player_runtime_variable_owner_count
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(count) = self.territory_runtime_variable_owner_count {
|
||||||
|
if actual.territory_runtime_variable_owner_count != count {
|
||||||
|
mismatches.push(format!(
|
||||||
|
"territory_runtime_variable_owner_count mismatch: expected {count}, got {}",
|
||||||
|
actual.territory_runtime_variable_owner_count
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(count) = self.world_scalar_override_count {
|
if let Some(count) = self.world_scalar_override_count {
|
||||||
if actual.world_scalar_override_count != count {
|
if actual.world_scalar_override_count != count {
|
||||||
mismatches.push(format!(
|
mismatches.push(format!(
|
||||||
|
|
|
||||||
|
|
@ -292,6 +292,10 @@ pub fn project_save_slice_to_runtime_state_import(
|
||||||
farm_mine_cargo_production_override: projection.farm_mine_cargo_production_override,
|
farm_mine_cargo_production_override: projection.farm_mine_cargo_production_override,
|
||||||
named_cargo_production_overrides: projection.named_cargo_production_overrides,
|
named_cargo_production_overrides: projection.named_cargo_production_overrides,
|
||||||
cargo_production_overrides: projection.cargo_production_overrides,
|
cargo_production_overrides: projection.cargo_production_overrides,
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: projection.world_scalar_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(),
|
||||||
|
|
@ -386,6 +390,10 @@ pub fn project_save_slice_overlay_to_runtime_state_import(
|
||||||
farm_mine_cargo_production_override: base_state.farm_mine_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(),
|
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_runtime_variables: base_state.world_runtime_variables.clone(),
|
||||||
|
company_runtime_variables: base_state.company_runtime_variables.clone(),
|
||||||
|
player_runtime_variables: base_state.player_runtime_variables.clone(),
|
||||||
|
territory_runtime_variables: base_state.territory_runtime_variables.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,
|
||||||
service_state: base_state.service_state.clone(),
|
service_state: base_state.service_state.clone(),
|
||||||
|
|
@ -1362,6 +1370,10 @@ fn lower_contextual_real_grouped_effects(
|
||||||
effects.push(effect);
|
effects.push(effect);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if let Some(effect) = lower_contextual_runtime_variable_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;
|
||||||
|
|
@ -1436,6 +1448,25 @@ fn lower_contextual_world_scalar_override_effect(
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lower_contextual_runtime_variable_effect(
|
||||||
|
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
||||||
|
) -> Result<Option<RuntimeEffect>, ImportBlocker> {
|
||||||
|
if row.parameter_family.as_deref() != Some("runtime_variable_scalar") {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
if row.row_shape != "scalar_assignment" {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let value = i64::from(row.raw_scalar_value);
|
||||||
|
Ok(match row.descriptor_id {
|
||||||
|
39..=42 => Some(RuntimeEffect::SetWorldVariable {
|
||||||
|
index: row.descriptor_id - 38,
|
||||||
|
value,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn lower_contextual_locomotive_availability_effect(
|
fn lower_contextual_locomotive_availability_effect(
|
||||||
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
|
||||||
company_context: &ImportRuntimeContext,
|
company_context: &ImportRuntimeContext,
|
||||||
|
|
@ -1682,12 +1713,28 @@ fn lower_condition_targets_in_effect(
|
||||||
value: *value,
|
value: *value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetWorldVariable { index, value } => RuntimeEffect::SetWorldVariable {
|
||||||
|
index: *index,
|
||||||
|
value: *value,
|
||||||
|
},
|
||||||
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
|
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
|
||||||
RuntimeEffect::SetLimitedTrackBuildingAmount { value: *value }
|
RuntimeEffect::SetLimitedTrackBuildingAmount { value: *value }
|
||||||
}
|
}
|
||||||
RuntimeEffect::SetEconomicStatusCode { value } => {
|
RuntimeEffect::SetEconomicStatusCode { value } => {
|
||||||
RuntimeEffect::SetEconomicStatusCode { value: *value }
|
RuntimeEffect::SetEconomicStatusCode { value: *value }
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetCompanyVariable {
|
||||||
|
target,
|
||||||
|
index,
|
||||||
|
value,
|
||||||
|
} => RuntimeEffect::SetCompanyVariable {
|
||||||
|
target: lower_condition_true_company_target_in_company_target(
|
||||||
|
target,
|
||||||
|
lowered_company_target,
|
||||||
|
)?,
|
||||||
|
index: *index,
|
||||||
|
value: *value,
|
||||||
|
},
|
||||||
RuntimeEffect::SetCompanyCash { target, value } => RuntimeEffect::SetCompanyCash {
|
RuntimeEffect::SetCompanyCash { target, value } => RuntimeEffect::SetCompanyCash {
|
||||||
target: lower_condition_true_company_target_in_company_target(
|
target: lower_condition_true_company_target_in_company_target(
|
||||||
target,
|
target,
|
||||||
|
|
@ -1695,6 +1742,18 @@ fn lower_condition_targets_in_effect(
|
||||||
)?,
|
)?,
|
||||||
value: *value,
|
value: *value,
|
||||||
},
|
},
|
||||||
|
RuntimeEffect::SetPlayerVariable {
|
||||||
|
target,
|
||||||
|
index,
|
||||||
|
value,
|
||||||
|
} => RuntimeEffect::SetPlayerVariable {
|
||||||
|
target: lower_condition_true_player_target_in_player_target(
|
||||||
|
target,
|
||||||
|
lowered_player_target,
|
||||||
|
)?,
|
||||||
|
index: *index,
|
||||||
|
value: *value,
|
||||||
|
},
|
||||||
RuntimeEffect::SetPlayerCash { target, value } => RuntimeEffect::SetPlayerCash {
|
RuntimeEffect::SetPlayerCash { target, value } => RuntimeEffect::SetPlayerCash {
|
||||||
target: lower_condition_true_player_target_in_player_target(
|
target: lower_condition_true_player_target_in_player_target(
|
||||||
target,
|
target,
|
||||||
|
|
@ -1823,6 +1882,15 @@ fn lower_condition_targets_in_effect(
|
||||||
value: *value,
|
value: *value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetTerritoryVariable {
|
||||||
|
target,
|
||||||
|
index,
|
||||||
|
value,
|
||||||
|
} => RuntimeEffect::SetTerritoryVariable {
|
||||||
|
target: target.clone(),
|
||||||
|
index: *index,
|
||||||
|
value: *value,
|
||||||
|
},
|
||||||
RuntimeEffect::SetCargoProductionOverride { target, value } => {
|
RuntimeEffect::SetCargoProductionOverride { target, value } => {
|
||||||
RuntimeEffect::SetCargoProductionOverride {
|
RuntimeEffect::SetCargoProductionOverride {
|
||||||
target: target.clone(),
|
target: target.clone(),
|
||||||
|
|
@ -2220,12 +2288,35 @@ fn smp_runtime_effect_to_runtime_effect(
|
||||||
key: key.clone(),
|
key: key.clone(),
|
||||||
value: *value,
|
value: *value,
|
||||||
}),
|
}),
|
||||||
|
RuntimeEffect::SetWorldVariable { index, value } => Ok(RuntimeEffect::SetWorldVariable {
|
||||||
|
index: *index,
|
||||||
|
value: *value,
|
||||||
|
}),
|
||||||
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
|
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
|
||||||
Ok(RuntimeEffect::SetLimitedTrackBuildingAmount { value: *value })
|
Ok(RuntimeEffect::SetLimitedTrackBuildingAmount { value: *value })
|
||||||
}
|
}
|
||||||
RuntimeEffect::SetEconomicStatusCode { value } => {
|
RuntimeEffect::SetEconomicStatusCode { value } => {
|
||||||
Ok(RuntimeEffect::SetEconomicStatusCode { value: *value })
|
Ok(RuntimeEffect::SetEconomicStatusCode { value: *value })
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetCompanyVariable {
|
||||||
|
target,
|
||||||
|
index,
|
||||||
|
value,
|
||||||
|
} => {
|
||||||
|
if company_target_allowed_for_import(
|
||||||
|
target,
|
||||||
|
company_context,
|
||||||
|
allow_condition_true_company,
|
||||||
|
) {
|
||||||
|
Ok(RuntimeEffect::SetCompanyVariable {
|
||||||
|
target: target.clone(),
|
||||||
|
index: *index,
|
||||||
|
value: *value,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(company_target_import_error_message(target, company_context))
|
||||||
|
}
|
||||||
|
}
|
||||||
RuntimeEffect::SetCompanyCash { target, value } => {
|
RuntimeEffect::SetCompanyCash { target, value } => {
|
||||||
if company_target_allowed_for_import(
|
if company_target_allowed_for_import(
|
||||||
target,
|
target,
|
||||||
|
|
@ -2240,6 +2331,25 @@ fn smp_runtime_effect_to_runtime_effect(
|
||||||
Err(company_target_import_error_message(target, company_context))
|
Err(company_target_import_error_message(target, company_context))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetPlayerVariable {
|
||||||
|
target,
|
||||||
|
index,
|
||||||
|
value,
|
||||||
|
} => {
|
||||||
|
if player_target_allowed_for_import(
|
||||||
|
target,
|
||||||
|
company_context,
|
||||||
|
allow_condition_true_player,
|
||||||
|
) {
|
||||||
|
Ok(RuntimeEffect::SetPlayerVariable {
|
||||||
|
target: target.clone(),
|
||||||
|
index: *index,
|
||||||
|
value: *value,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(player_target_import_error_message(target, company_context))
|
||||||
|
}
|
||||||
|
}
|
||||||
RuntimeEffect::SetPlayerCash { target, value } => {
|
RuntimeEffect::SetPlayerCash { target, value } => {
|
||||||
if player_target_allowed_for_import(
|
if player_target_allowed_for_import(
|
||||||
target,
|
target,
|
||||||
|
|
@ -2254,6 +2364,21 @@ fn smp_runtime_effect_to_runtime_effect(
|
||||||
Err(player_target_import_error_message(target, company_context))
|
Err(player_target_import_error_message(target, company_context))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetTerritoryVariable {
|
||||||
|
target,
|
||||||
|
index,
|
||||||
|
value,
|
||||||
|
} => {
|
||||||
|
if territory_target_import_blocker(target, company_context).is_none() {
|
||||||
|
Ok(RuntimeEffect::SetTerritoryVariable {
|
||||||
|
target: target.clone(),
|
||||||
|
index: *index,
|
||||||
|
value: *value,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err("packed effect requires territory runtime context".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
RuntimeEffect::SetChairmanCash { target, value } => {
|
RuntimeEffect::SetChairmanCash { target, value } => {
|
||||||
if chairman_target_import_blocker(target, company_context).is_none() {
|
if chairman_target_import_blocker(target, company_context).is_none() {
|
||||||
Ok(RuntimeEffect::SetChairmanCash {
|
Ok(RuntimeEffect::SetChairmanCash {
|
||||||
|
|
@ -2998,6 +3123,7 @@ fn real_grouped_row_is_unsupported_executable_descriptor_variant(
|
||||||
56 | 57 => row.row_shape != "scalar_assignment",
|
56 | 57 => row.row_shape != "scalar_assignment",
|
||||||
_ => match row.parameter_family.as_deref() {
|
_ => match row.parameter_family.as_deref() {
|
||||||
Some("world_scalar_override") => row.row_shape != "scalar_assignment",
|
Some("world_scalar_override") => row.row_shape != "scalar_assignment",
|
||||||
|
Some("runtime_variable_scalar") => row.row_shape != "scalar_assignment",
|
||||||
Some("locomotive_availability_scalar") => {
|
Some("locomotive_availability_scalar") => {
|
||||||
!(row.row_shape == "scalar_assignment" && row.raw_scalar_value >= 0)
|
!(row.row_shape == "scalar_assignment" && row.raw_scalar_value >= 0)
|
||||||
}
|
}
|
||||||
|
|
@ -3190,6 +3316,7 @@ fn real_grouped_row_is_unsupported_retire_train_scope(
|
||||||
fn runtime_effect_uses_condition_true_company(effect: &RuntimeEffect) -> bool {
|
fn runtime_effect_uses_condition_true_company(effect: &RuntimeEffect) -> bool {
|
||||||
match effect {
|
match effect {
|
||||||
RuntimeEffect::SetCompanyCash { target, .. }
|
RuntimeEffect::SetCompanyCash { target, .. }
|
||||||
|
| RuntimeEffect::SetCompanyVariable { target, .. }
|
||||||
| RuntimeEffect::SetCompanyGovernanceScalar { target, .. }
|
| RuntimeEffect::SetCompanyGovernanceScalar { target, .. }
|
||||||
| RuntimeEffect::SetCompanyTerritoryAccess { target, .. }
|
| RuntimeEffect::SetCompanyTerritoryAccess { target, .. }
|
||||||
| RuntimeEffect::ConfiscateCompanyAssets { target }
|
| RuntimeEffect::ConfiscateCompanyAssets { target }
|
||||||
|
|
@ -3208,10 +3335,12 @@ 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::SetWorldVariable { .. }
|
||||||
| RuntimeEffect::SetWorldScalarOverride { .. }
|
| RuntimeEffect::SetWorldScalarOverride { .. }
|
||||||
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
||||||
| RuntimeEffect::SetEconomicStatusCode { .. }
|
| RuntimeEffect::SetEconomicStatusCode { .. }
|
||||||
| RuntimeEffect::SetPlayerCash { .. }
|
| RuntimeEffect::SetPlayerCash { .. }
|
||||||
|
| RuntimeEffect::SetPlayerVariable { .. }
|
||||||
| RuntimeEffect::SetChairmanCash { .. }
|
| RuntimeEffect::SetChairmanCash { .. }
|
||||||
| RuntimeEffect::DeactivatePlayer { .. }
|
| RuntimeEffect::DeactivatePlayer { .. }
|
||||||
| RuntimeEffect::DeactivateChairman { .. }
|
| RuntimeEffect::DeactivateChairman { .. }
|
||||||
|
|
@ -3222,6 +3351,7 @@ fn runtime_effect_uses_condition_true_company(effect: &RuntimeEffect) -> bool {
|
||||||
| RuntimeEffect::SetCargoPriceOverride { .. }
|
| RuntimeEffect::SetCargoPriceOverride { .. }
|
||||||
| RuntimeEffect::SetCargoProductionOverride { .. }
|
| RuntimeEffect::SetCargoProductionOverride { .. }
|
||||||
| RuntimeEffect::SetCargoProductionSlot { .. }
|
| RuntimeEffect::SetCargoProductionSlot { .. }
|
||||||
|
| RuntimeEffect::SetTerritoryVariable { .. }
|
||||||
| RuntimeEffect::SetTerritoryAccessCost { .. }
|
| RuntimeEffect::SetTerritoryAccessCost { .. }
|
||||||
| RuntimeEffect::SetSpecialCondition { .. }
|
| RuntimeEffect::SetSpecialCondition { .. }
|
||||||
| RuntimeEffect::ActivateEventRecord { .. }
|
| RuntimeEffect::ActivateEventRecord { .. }
|
||||||
|
|
@ -3232,7 +3362,8 @@ fn runtime_effect_uses_condition_true_company(effect: &RuntimeEffect) -> bool {
|
||||||
|
|
||||||
fn runtime_effect_uses_condition_true_player(effect: &RuntimeEffect) -> bool {
|
fn runtime_effect_uses_condition_true_player(effect: &RuntimeEffect) -> bool {
|
||||||
match effect {
|
match effect {
|
||||||
RuntimeEffect::SetPlayerCash { target, .. } => {
|
RuntimeEffect::SetPlayerCash { target, .. }
|
||||||
|
| RuntimeEffect::SetPlayerVariable { target, .. } => {
|
||||||
matches!(target, RuntimePlayerTarget::ConditionTruePlayer)
|
matches!(target, RuntimePlayerTarget::ConditionTruePlayer)
|
||||||
}
|
}
|
||||||
RuntimeEffect::DeactivatePlayer { target } => {
|
RuntimeEffect::DeactivatePlayer { target } => {
|
||||||
|
|
@ -3274,6 +3405,7 @@ fn runtime_effect_company_target_import_blocker(
|
||||||
) -> Option<ImportBlocker> {
|
) -> Option<ImportBlocker> {
|
||||||
match effect {
|
match effect {
|
||||||
RuntimeEffect::SetCompanyCash { target, .. }
|
RuntimeEffect::SetCompanyCash { target, .. }
|
||||||
|
| RuntimeEffect::SetCompanyVariable { target, .. }
|
||||||
| RuntimeEffect::SetCompanyGovernanceScalar { target, .. }
|
| RuntimeEffect::SetCompanyGovernanceScalar { target, .. }
|
||||||
| RuntimeEffect::SetCompanyTerritoryAccess { target, .. }
|
| RuntimeEffect::SetCompanyTerritoryAccess { target, .. }
|
||||||
| RuntimeEffect::ConfiscateCompanyAssets { target }
|
| RuntimeEffect::ConfiscateCompanyAssets { target }
|
||||||
|
|
@ -3293,9 +3425,13 @@ fn runtime_effect_company_target_import_blocker(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RuntimeEffect::SetPlayerCash { target, .. }
|
RuntimeEffect::SetPlayerCash { target, .. }
|
||||||
|
| RuntimeEffect::SetPlayerVariable { target, .. }
|
||||||
| RuntimeEffect::DeactivatePlayer { target } => {
|
| RuntimeEffect::DeactivatePlayer { target } => {
|
||||||
player_target_import_blocker(target, company_context)
|
player_target_import_blocker(target, company_context)
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetTerritoryVariable { target, .. } => {
|
||||||
|
territory_target_import_blocker(target, company_context)
|
||||||
|
}
|
||||||
RuntimeEffect::SetChairmanCash { target, .. }
|
RuntimeEffect::SetChairmanCash { target, .. }
|
||||||
| RuntimeEffect::DeactivateChairman { target } => {
|
| RuntimeEffect::DeactivateChairman { target } => {
|
||||||
chairman_target_import_blocker(target, company_context)
|
chairman_target_import_blocker(target, company_context)
|
||||||
|
|
@ -3324,6 +3460,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::SetWorldVariable { .. }
|
||||||
| RuntimeEffect::SetWorldScalarOverride { .. }
|
| RuntimeEffect::SetWorldScalarOverride { .. }
|
||||||
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
||||||
| RuntimeEffect::SetEconomicStatusCode { .. }
|
| RuntimeEffect::SetEconomicStatusCode { .. }
|
||||||
|
|
@ -3689,6 +3826,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -4245,6 +4386,9 @@ mod tests {
|
||||||
56 => Some("Trans-Euro"),
|
56 => Some("Trans-Euro"),
|
||||||
57 => Some("V200"),
|
57 => Some("V200"),
|
||||||
58 => Some("VL80T"),
|
58 => Some("VL80T"),
|
||||||
|
59 => Some("GP 35"),
|
||||||
|
60 => Some("U1"),
|
||||||
|
61 => Some("Zephyr"),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4361,6 +4505,9 @@ mod tests {
|
||||||
56 => Some("Trans-Euro"),
|
56 => Some("Trans-Euro"),
|
||||||
57 => Some("V200"),
|
57 => Some("V200"),
|
||||||
58 => Some("VL80T"),
|
58 => Some("VL80T"),
|
||||||
|
59 => Some("GP 35"),
|
||||||
|
60 => Some("U1"),
|
||||||
|
61 => Some("Zephyr"),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4471,6 +4618,9 @@ mod tests {
|
||||||
55 => "Trans-Euro",
|
55 => "Trans-Euro",
|
||||||
56 => "V200",
|
56 => "V200",
|
||||||
57 => "VL80T",
|
57 => "VL80T",
|
||||||
|
58 => "GP 35",
|
||||||
|
59 => "U1",
|
||||||
|
60 => "Zephyr",
|
||||||
_ => return format!("Locomotive {}", index + 1),
|
_ => return format!("Locomotive {}", index + 1),
|
||||||
}
|
}
|
||||||
.to_string()
|
.to_string()
|
||||||
|
|
@ -7125,7 +7275,7 @@ mod tests {
|
||||||
bridge_family: None,
|
bridge_family: None,
|
||||||
profile: None,
|
profile: None,
|
||||||
candidate_availability_table: None,
|
candidate_availability_table: None,
|
||||||
named_locomotive_availability_table: Some(save_named_locomotive_table(58)),
|
named_locomotive_availability_table: Some(save_named_locomotive_table(61)),
|
||||||
locomotive_catalog: None,
|
locomotive_catalog: None,
|
||||||
cargo_catalog: None,
|
cargo_catalog: None,
|
||||||
company_roster: None,
|
company_roster: None,
|
||||||
|
|
@ -7165,7 +7315,7 @@ mod tests {
|
||||||
grouped_effect_row_counts: vec![2, 0, 0, 0],
|
grouped_effect_row_counts: vec![2, 0, 0, 0],
|
||||||
grouped_effect_rows: vec![
|
grouped_effect_rows: vec![
|
||||||
real_locomotive_availability_row(250, 42),
|
real_locomotive_availability_row(250, 42),
|
||||||
real_locomotive_availability_row(298, 7),
|
real_locomotive_availability_row(301, 7),
|
||||||
],
|
],
|
||||||
decoded_conditions: Vec::new(),
|
decoded_conditions: Vec::new(),
|
||||||
decoded_actions: vec![],
|
decoded_actions: vec![],
|
||||||
|
|
@ -7186,7 +7336,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.expect("save slice should project");
|
.expect("save slice should project");
|
||||||
|
|
||||||
assert_eq!(import.state.locomotive_catalog.len(), 58);
|
assert_eq!(import.state.locomotive_catalog.len(), 61);
|
||||||
assert_eq!(import.state.event_runtime_records.len(), 1);
|
assert_eq!(import.state.event_runtime_records.len(), 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
import
|
import
|
||||||
|
|
@ -7211,7 +7361,7 @@ mod tests {
|
||||||
Some(&42)
|
Some(&42)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
import.state.named_locomotive_availability.get("VL80T"),
|
import.state.named_locomotive_availability.get("Zephyr"),
|
||||||
Some(&7)
|
Some(&7)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -7242,8 +7392,8 @@ mod tests {
|
||||||
name: "Big Boy 4-8-8-4".to_string(),
|
name: "Big Boy 4-8-8-4".to_string(),
|
||||||
},
|
},
|
||||||
crate::RuntimeLocomotiveCatalogEntry {
|
crate::RuntimeLocomotiveCatalogEntry {
|
||||||
locomotive_id: 58,
|
locomotive_id: 61,
|
||||||
name: "VL80T".to_string(),
|
name: "Zephyr".to_string(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
cargo_catalog: Vec::new(),
|
cargo_catalog: Vec::new(),
|
||||||
|
|
@ -7255,7 +7405,7 @@ mod tests {
|
||||||
candidate_availability: BTreeMap::new(),
|
candidate_availability: BTreeMap::new(),
|
||||||
named_locomotive_availability: BTreeMap::from([
|
named_locomotive_availability: BTreeMap::from([
|
||||||
("Big Boy 4-8-8-4".to_string(), 0),
|
("Big Boy 4-8-8-4".to_string(), 0),
|
||||||
("VL80T".to_string(), 1),
|
("Zephyr".to_string(), 1),
|
||||||
]),
|
]),
|
||||||
named_locomotive_cost: BTreeMap::new(),
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
all_cargo_price_override: None,
|
all_cargo_price_override: None,
|
||||||
|
|
@ -7265,6 +7415,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -7318,7 +7472,7 @@ mod tests {
|
||||||
grouped_effect_row_counts: vec![2, 0, 0, 0],
|
grouped_effect_row_counts: vec![2, 0, 0, 0],
|
||||||
grouped_effect_rows: vec![
|
grouped_effect_rows: vec![
|
||||||
real_locomotive_availability_row(250, 42),
|
real_locomotive_availability_row(250, 42),
|
||||||
real_locomotive_availability_row(298, 7),
|
real_locomotive_availability_row(301, 7),
|
||||||
],
|
],
|
||||||
decoded_conditions: Vec::new(),
|
decoded_conditions: Vec::new(),
|
||||||
decoded_actions: vec![],
|
decoded_actions: vec![],
|
||||||
|
|
@ -7364,7 +7518,7 @@ mod tests {
|
||||||
Some(&42)
|
Some(&42)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
import.state.named_locomotive_availability.get("VL80T"),
|
import.state.named_locomotive_availability.get("Zephyr"),
|
||||||
Some(&7)
|
Some(&7)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -7538,7 +7692,7 @@ mod tests {
|
||||||
bridge_family: None,
|
bridge_family: None,
|
||||||
profile: None,
|
profile: None,
|
||||||
candidate_availability_table: None,
|
candidate_availability_table: None,
|
||||||
named_locomotive_availability_table: Some(save_named_locomotive_table(58)),
|
named_locomotive_availability_table: Some(save_named_locomotive_table(61)),
|
||||||
locomotive_catalog: None,
|
locomotive_catalog: None,
|
||||||
cargo_catalog: None,
|
cargo_catalog: None,
|
||||||
company_roster: None,
|
company_roster: None,
|
||||||
|
|
@ -7578,7 +7732,7 @@ mod tests {
|
||||||
grouped_effect_row_counts: vec![2, 0, 0, 0],
|
grouped_effect_row_counts: vec![2, 0, 0, 0],
|
||||||
grouped_effect_rows: vec![
|
grouped_effect_rows: vec![
|
||||||
real_locomotive_cost_row(352, 250000),
|
real_locomotive_cost_row(352, 250000),
|
||||||
real_locomotive_cost_row(409, 325000),
|
real_locomotive_cost_row(412, 325000),
|
||||||
],
|
],
|
||||||
decoded_conditions: Vec::new(),
|
decoded_conditions: Vec::new(),
|
||||||
decoded_actions: vec![],
|
decoded_actions: vec![],
|
||||||
|
|
@ -7598,7 +7752,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.expect("save slice should project");
|
.expect("save slice should project");
|
||||||
|
|
||||||
assert_eq!(import.state.locomotive_catalog.len(), 58);
|
assert_eq!(import.state.locomotive_catalog.len(), 61);
|
||||||
assert_eq!(import.state.event_runtime_records.len(), 1);
|
assert_eq!(import.state.event_runtime_records.len(), 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
import
|
import
|
||||||
|
|
@ -7620,7 +7774,7 @@ mod tests {
|
||||||
Some(&250000)
|
Some(&250000)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
import.state.named_locomotive_cost.get("VL80T"),
|
import.state.named_locomotive_cost.get("Zephyr"),
|
||||||
Some(&325000)
|
Some(&325000)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -7651,8 +7805,8 @@ mod tests {
|
||||||
name: "2-D-2".to_string(),
|
name: "2-D-2".to_string(),
|
||||||
},
|
},
|
||||||
crate::RuntimeLocomotiveCatalogEntry {
|
crate::RuntimeLocomotiveCatalogEntry {
|
||||||
locomotive_id: 58,
|
locomotive_id: 61,
|
||||||
name: "VL80T".to_string(),
|
name: "Zephyr".to_string(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
cargo_catalog: Vec::new(),
|
cargo_catalog: Vec::new(),
|
||||||
|
|
@ -7665,7 +7819,7 @@ mod tests {
|
||||||
named_locomotive_availability: BTreeMap::new(),
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
named_locomotive_cost: BTreeMap::from([
|
named_locomotive_cost: BTreeMap::from([
|
||||||
("2-D-2".to_string(), 100000),
|
("2-D-2".to_string(), 100000),
|
||||||
("VL80T".to_string(), 200000),
|
("Zephyr".to_string(), 200000),
|
||||||
]),
|
]),
|
||||||
all_cargo_price_override: None,
|
all_cargo_price_override: None,
|
||||||
named_cargo_price_overrides: BTreeMap::new(),
|
named_cargo_price_overrides: BTreeMap::new(),
|
||||||
|
|
@ -7674,6 +7828,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -7727,7 +7885,7 @@ mod tests {
|
||||||
grouped_effect_row_counts: vec![2, 0, 0, 0],
|
grouped_effect_row_counts: vec![2, 0, 0, 0],
|
||||||
grouped_effect_rows: vec![
|
grouped_effect_rows: vec![
|
||||||
real_locomotive_cost_row(352, 250000),
|
real_locomotive_cost_row(352, 250000),
|
||||||
real_locomotive_cost_row(409, 325000),
|
real_locomotive_cost_row(412, 325000),
|
||||||
],
|
],
|
||||||
decoded_conditions: Vec::new(),
|
decoded_conditions: Vec::new(),
|
||||||
decoded_actions: vec![],
|
decoded_actions: vec![],
|
||||||
|
|
@ -7769,7 +7927,7 @@ mod tests {
|
||||||
Some(&250000)
|
Some(&250000)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
import.state.named_locomotive_cost.get("VL80T"),
|
import.state.named_locomotive_cost.get("Zephyr"),
|
||||||
Some(&325000)
|
Some(&325000)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -8427,6 +8585,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -10710,6 +10872,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -10890,6 +11056,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -12585,6 +12755,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState {
|
service_state: RuntimeServiceState {
|
||||||
|
|
@ -12776,6 +12950,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
|
||||||
|
|
@ -491,6 +491,25 @@ pub enum RuntimeEffect {
|
||||||
slot: u32,
|
slot: u32,
|
||||||
value: u32,
|
value: u32,
|
||||||
},
|
},
|
||||||
|
SetWorldVariable {
|
||||||
|
index: u32,
|
||||||
|
value: i64,
|
||||||
|
},
|
||||||
|
SetCompanyVariable {
|
||||||
|
target: RuntimeCompanyTarget,
|
||||||
|
index: u32,
|
||||||
|
value: i64,
|
||||||
|
},
|
||||||
|
SetPlayerVariable {
|
||||||
|
target: RuntimePlayerTarget,
|
||||||
|
index: u32,
|
||||||
|
value: i64,
|
||||||
|
},
|
||||||
|
SetTerritoryVariable {
|
||||||
|
target: RuntimeTerritoryTarget,
|
||||||
|
index: u32,
|
||||||
|
value: i64,
|
||||||
|
},
|
||||||
SetWorldScalarOverride {
|
SetWorldScalarOverride {
|
||||||
key: String,
|
key: String,
|
||||||
value: i64,
|
value: i64,
|
||||||
|
|
@ -882,6 +901,14 @@ 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_runtime_variables: BTreeMap<u32, i64>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub company_runtime_variables: BTreeMap<u32, BTreeMap<u32, i64>>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub player_runtime_variables: BTreeMap<u32, BTreeMap<u32, i64>>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub territory_runtime_variables: BTreeMap<u32, BTreeMap<u32, i64>>,
|
||||||
|
#[serde(default)]
|
||||||
pub world_scalar_overrides: BTreeMap<String, i64>,
|
pub world_scalar_overrides: BTreeMap<String, i64>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub special_conditions: BTreeMap<String, u32>,
|
pub special_conditions: BTreeMap<String, u32>,
|
||||||
|
|
@ -1039,7 +1066,6 @@ impl RuntimeState {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut seen_territory_ids = BTreeSet::new();
|
let mut seen_territory_ids = BTreeSet::new();
|
||||||
let mut seen_territory_names = BTreeSet::new();
|
let mut seen_territory_names = BTreeSet::new();
|
||||||
for territory in &self.territories {
|
for territory in &self.territories {
|
||||||
|
|
@ -1541,6 +1567,62 @@ impl RuntimeState {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for index in self.world_runtime_variables.keys() {
|
||||||
|
if !(1..=4).contains(index) {
|
||||||
|
return Err(format!(
|
||||||
|
"world_runtime_variables contains out-of-range index {}",
|
||||||
|
index
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (company_id, vars) in &self.company_runtime_variables {
|
||||||
|
if !seen_company_ids.contains(company_id) {
|
||||||
|
return Err(format!(
|
||||||
|
"company_runtime_variables references unknown company_id {}",
|
||||||
|
company_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for index in vars.keys() {
|
||||||
|
if !(1..=4).contains(index) {
|
||||||
|
return Err(format!(
|
||||||
|
"company_runtime_variables[{company_id}] contains out-of-range index {}",
|
||||||
|
index
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (player_id, vars) in &self.player_runtime_variables {
|
||||||
|
if !seen_player_ids.contains(player_id) {
|
||||||
|
return Err(format!(
|
||||||
|
"player_runtime_variables references unknown player_id {}",
|
||||||
|
player_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for index in vars.keys() {
|
||||||
|
if !(1..=4).contains(index) {
|
||||||
|
return Err(format!(
|
||||||
|
"player_runtime_variables[{player_id}] contains out-of-range index {}",
|
||||||
|
index
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (territory_id, vars) in &self.territory_runtime_variables {
|
||||||
|
if !seen_territory_ids.contains(territory_id) {
|
||||||
|
return Err(format!(
|
||||||
|
"territory_runtime_variables references unknown territory_id {}",
|
||||||
|
territory_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for index in vars.keys() {
|
||||||
|
if !(1..=4).contains(index) {
|
||||||
|
return Err(format!(
|
||||||
|
"territory_runtime_variables[{territory_id}] contains out-of-range index {}",
|
||||||
|
index
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
for key in self.world_scalar_overrides.keys() {
|
for key in self.world_scalar_overrides.keys() {
|
||||||
if key.trim().is_empty() {
|
if key.trim().is_empty() {
|
||||||
return Err("world_scalar_overrides contains an empty key".to_string());
|
return Err("world_scalar_overrides contains an empty key".to_string());
|
||||||
|
|
@ -1569,6 +1651,13 @@ fn validate_runtime_effect(
|
||||||
return Err("key must not be empty".to_string());
|
return Err("key must not be empty".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetWorldVariable { index, .. } => {
|
||||||
|
if !(1..=4).contains(index) {
|
||||||
|
return Err(format!(
|
||||||
|
"world runtime variable index {index} must be in 1..=4"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
RuntimeEffect::SetWorldScalarOverride { key, .. } => {
|
RuntimeEffect::SetWorldScalarOverride { key, .. } => {
|
||||||
if key.trim().is_empty() {
|
if key.trim().is_empty() {
|
||||||
return Err("key must not be empty".to_string());
|
return Err("key must not be empty".to_string());
|
||||||
|
|
@ -1576,6 +1665,12 @@ fn validate_runtime_effect(
|
||||||
}
|
}
|
||||||
RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
||||||
| RuntimeEffect::SetEconomicStatusCode { .. } => {}
|
| RuntimeEffect::SetEconomicStatusCode { .. } => {}
|
||||||
|
RuntimeEffect::SetCompanyVariable { target, index, .. } => {
|
||||||
|
validate_company_target(target, valid_company_ids)?;
|
||||||
|
if !(1..=4).contains(index) {
|
||||||
|
return Err(format!("runtime variable index {index} must be in 1..=4"));
|
||||||
|
}
|
||||||
|
}
|
||||||
RuntimeEffect::SetCompanyCash { target, .. }
|
RuntimeEffect::SetCompanyCash { target, .. }
|
||||||
| RuntimeEffect::ConfiscateCompanyAssets { target }
|
| RuntimeEffect::ConfiscateCompanyAssets { target }
|
||||||
| RuntimeEffect::DeactivateCompany { target }
|
| RuntimeEffect::DeactivateCompany { target }
|
||||||
|
|
@ -1594,6 +1689,12 @@ fn validate_runtime_effect(
|
||||||
validate_company_target(target, valid_company_ids)?;
|
validate_company_target(target, valid_company_ids)?;
|
||||||
validate_territory_target(territory, valid_territory_ids)?;
|
validate_territory_target(territory, valid_territory_ids)?;
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetPlayerVariable { target, index, .. } => {
|
||||||
|
validate_player_target(target, valid_player_ids)?;
|
||||||
|
if !(1..=4).contains(index) {
|
||||||
|
return Err(format!("runtime variable index {index} must be in 1..=4"));
|
||||||
|
}
|
||||||
|
}
|
||||||
RuntimeEffect::SetPlayerCash { target, .. }
|
RuntimeEffect::SetPlayerCash { target, .. }
|
||||||
| RuntimeEffect::DeactivatePlayer { target } => {
|
| RuntimeEffect::DeactivatePlayer { target } => {
|
||||||
validate_player_target(target, valid_player_ids)?;
|
validate_player_target(target, valid_player_ids)?;
|
||||||
|
|
@ -1669,6 +1770,12 @@ fn validate_runtime_effect(
|
||||||
return Err("slot must be in 1..=11".to_string());
|
return Err("slot must be in 1..=11".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetTerritoryVariable { target, index, .. } => {
|
||||||
|
validate_territory_target(target, valid_territory_ids)?;
|
||||||
|
if !(1..=4).contains(index) {
|
||||||
|
return Err(format!("runtime variable index {index} must be in 1..=4"));
|
||||||
|
}
|
||||||
|
}
|
||||||
RuntimeEffect::SetTerritoryAccessCost { .. } => {}
|
RuntimeEffect::SetTerritoryAccessCost { .. } => {}
|
||||||
RuntimeEffect::SetSpecialCondition { label, .. } => {
|
RuntimeEffect::SetSpecialCondition { label, .. } => {
|
||||||
if label.trim().is_empty() {
|
if label.trim().is_empty() {
|
||||||
|
|
@ -1987,6 +2094,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2057,6 +2168,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2131,6 +2246,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2215,6 +2334,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2324,6 +2447,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2385,6 +2512,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2446,6 +2577,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2524,6 +2659,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2592,6 +2731,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2664,6 +2807,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2732,6 +2879,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2806,6 +2957,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2874,6 +3029,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2942,6 +3101,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -3003,6 +3166,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -3074,6 +3241,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
|
||||||
|
|
@ -446,7 +446,7 @@ const KNOWN_CARGO_SLOT_DEFINITIONS: [KnownCargoSlotDefinition; 11] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const GROUNDED_LOCOMOTIVE_PREFIX: [&str; 58] = [
|
const GROUNDED_LOCOMOTIVE_PREFIX: [&str; 61] = [
|
||||||
"2-D-2",
|
"2-D-2",
|
||||||
"E-88",
|
"E-88",
|
||||||
"Adler 2-2-2",
|
"Adler 2-2-2",
|
||||||
|
|
@ -505,6 +505,9 @@ const GROUNDED_LOCOMOTIVE_PREFIX: [&str; 58] = [
|
||||||
"Trans-Euro",
|
"Trans-Euro",
|
||||||
"V200",
|
"V200",
|
||||||
"VL80T",
|
"VL80T",
|
||||||
|
"GP 35",
|
||||||
|
"U1",
|
||||||
|
"Zephyr",
|
||||||
];
|
];
|
||||||
|
|
||||||
const REAL_CANDIDATE_AVAILABILITY_CONDITION_TEMPLATE_ID: i32 = 435;
|
const REAL_CANDIDATE_AVAILABILITY_CONDITION_TEMPLATE_ID: i32 = 435;
|
||||||
|
|
@ -4313,6 +4316,7 @@ fn derive_real_grouped_target_subject(
|
||||||
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),
|
||||||
|
Some(0x04) => Some(RealGroupedTargetSubject::Territory),
|
||||||
Some(0x02) => match compact_control
|
Some(0x02) => match compact_control
|
||||||
.grouped_scope_checkboxes_0x7ff
|
.grouped_scope_checkboxes_0x7ff
|
||||||
.get(row.group_index)
|
.get(row.group_index)
|
||||||
|
|
@ -4401,6 +4405,16 @@ fn real_grouped_chairman_scope_name(ordinal: u8) -> &'static str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn runtime_variable_index(descriptor_id: u32) -> Option<u32> {
|
||||||
|
match descriptor_id {
|
||||||
|
39..=42 => Some(descriptor_id - 38),
|
||||||
|
43..=46 => Some(descriptor_id - 42),
|
||||||
|
47..=50 => Some(descriptor_id - 46),
|
||||||
|
51..=54 => Some(descriptor_id - 50),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn decode_real_grouped_effect_actions(
|
fn decode_real_grouped_effect_actions(
|
||||||
grouped_effect_rows: &[SmpLoadedPackedEventGroupedEffectRowSummary],
|
grouped_effect_rows: &[SmpLoadedPackedEventGroupedEffectRowSummary],
|
||||||
compact_control: &SmpLoadedPackedEventCompactControlSummary,
|
compact_control: &SmpLoadedPackedEventCompactControlSummary,
|
||||||
|
|
@ -4422,6 +4436,42 @@ fn decode_real_grouped_effect_action(
|
||||||
.copied()?;
|
.copied()?;
|
||||||
let target_subject = derive_real_grouped_target_subject(row, compact_control);
|
let target_subject = derive_real_grouped_target_subject(row, compact_control);
|
||||||
|
|
||||||
|
if descriptor_metadata.executable_in_runtime
|
||||||
|
&& descriptor_metadata.parameter_family == "runtime_variable_scalar"
|
||||||
|
&& row.row_shape == "scalar_assignment"
|
||||||
|
{
|
||||||
|
let index = runtime_variable_index(descriptor_metadata.descriptor_id)?;
|
||||||
|
return match target_subject {
|
||||||
|
Some(RealGroupedTargetSubject::WholeGame) => Some(RuntimeEffect::SetWorldVariable {
|
||||||
|
index,
|
||||||
|
value: i64::from(row.raw_scalar_value),
|
||||||
|
}),
|
||||||
|
Some(RealGroupedTargetSubject::Company) => Some(RuntimeEffect::SetCompanyVariable {
|
||||||
|
target: real_grouped_company_target(target_scope_ordinal)?,
|
||||||
|
index,
|
||||||
|
value: i64::from(row.raw_scalar_value),
|
||||||
|
}),
|
||||||
|
Some(RealGroupedTargetSubject::Player) => Some(RuntimeEffect::SetPlayerVariable {
|
||||||
|
target: real_grouped_player_target(target_scope_ordinal)?,
|
||||||
|
index,
|
||||||
|
value: i64::from(row.raw_scalar_value),
|
||||||
|
}),
|
||||||
|
Some(RealGroupedTargetSubject::Territory) => compact_control
|
||||||
|
.grouped_territory_selectors_0x80f
|
||||||
|
.get(row.group_index)
|
||||||
|
.copied()
|
||||||
|
.filter(|selector| *selector >= 0)
|
||||||
|
.map(|selector| RuntimeEffect::SetTerritoryVariable {
|
||||||
|
target: RuntimeTerritoryTarget::Ids {
|
||||||
|
ids: vec![selector as u32],
|
||||||
|
},
|
||||||
|
index,
|
||||||
|
value: i64::from(row.raw_scalar_value),
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if descriptor_metadata.executable_in_runtime
|
if descriptor_metadata.executable_in_runtime
|
||||||
&& descriptor_metadata.parameter_family == "company_governance_scalar"
|
&& descriptor_metadata.parameter_family == "company_governance_scalar"
|
||||||
&& row.row_shape == "scalar_assignment"
|
&& row.row_shape == "scalar_assignment"
|
||||||
|
|
@ -4858,6 +4908,7 @@ fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
|
||||||
| RuntimeChairmanTarget::Ids { .. }
|
| RuntimeChairmanTarget::Ids { .. }
|
||||||
),
|
),
|
||||||
RuntimeEffect::SetWorldFlag { .. }
|
RuntimeEffect::SetWorldFlag { .. }
|
||||||
|
| RuntimeEffect::SetWorldVariable { .. }
|
||||||
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
|
||||||
| RuntimeEffect::SetEconomicStatusCode { .. }
|
| RuntimeEffect::SetEconomicStatusCode { .. }
|
||||||
| RuntimeEffect::SetCompanyGovernanceScalar { .. }
|
| RuntimeEffect::SetCompanyGovernanceScalar { .. }
|
||||||
|
|
@ -4879,7 +4930,8 @@ fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
|
||||||
| RuntimeEffect::ActivateEventRecord { .. }
|
| RuntimeEffect::ActivateEventRecord { .. }
|
||||||
| RuntimeEffect::DeactivateEventRecord { .. }
|
| RuntimeEffect::DeactivateEventRecord { .. }
|
||||||
| RuntimeEffect::RemoveEventRecord { .. } => true,
|
| RuntimeEffect::RemoveEventRecord { .. } => true,
|
||||||
RuntimeEffect::SetPlayerCash { target, .. } => matches!(
|
RuntimeEffect::SetPlayerCash { target, .. }
|
||||||
|
| RuntimeEffect::SetPlayerVariable { target, .. } => matches!(
|
||||||
target,
|
target,
|
||||||
RuntimePlayerTarget::AllActive
|
RuntimePlayerTarget::AllActive
|
||||||
| RuntimePlayerTarget::Ids { .. }
|
| RuntimePlayerTarget::Ids { .. }
|
||||||
|
|
@ -4905,6 +4957,7 @@ fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
RuntimeEffect::SetCompanyCash { target, .. }
|
RuntimeEffect::SetCompanyCash { target, .. }
|
||||||
|
| RuntimeEffect::SetCompanyVariable { target, .. }
|
||||||
| RuntimeEffect::AdjustCompanyCash { target, .. }
|
| RuntimeEffect::AdjustCompanyCash { target, .. }
|
||||||
| RuntimeEffect::AdjustCompanyDebt { target, .. } => matches!(
|
| RuntimeEffect::AdjustCompanyDebt { target, .. } => matches!(
|
||||||
target,
|
target,
|
||||||
|
|
@ -4915,6 +4968,10 @@ fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
|
||||||
| RuntimeCompanyTarget::SelectedCompany
|
| RuntimeCompanyTarget::SelectedCompany
|
||||||
| RuntimeCompanyTarget::ConditionTrueCompany
|
| RuntimeCompanyTarget::ConditionTrueCompany
|
||||||
),
|
),
|
||||||
|
RuntimeEffect::SetTerritoryVariable { target, .. } => matches!(
|
||||||
|
target,
|
||||||
|
RuntimeTerritoryTarget::AllTerritories | RuntimeTerritoryTarget::Ids { .. }
|
||||||
|
),
|
||||||
RuntimeEffect::AppendEventRecord { record } => record
|
RuntimeEffect::AppendEventRecord { record } => record
|
||||||
.effects
|
.effects
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -11514,6 +11571,17 @@ mod tests {
|
||||||
assert_eq!(recovered_locomotive_availability_loco_id(457), None);
|
assert_eq!(recovered_locomotive_availability_loco_id(457), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn looks_up_extended_lower_band_locomotive_availability_descriptor_metadata() {
|
||||||
|
let metadata =
|
||||||
|
real_grouped_effect_descriptor_metadata(301).expect("descriptor metadata should exist");
|
||||||
|
|
||||||
|
assert_eq!(metadata.label, "Zephyr Availability");
|
||||||
|
assert_eq!(metadata.parameter_family, "locomotive_availability_scalar");
|
||||||
|
assert_eq!(recovered_locomotive_availability_loco_id(301), Some(61));
|
||||||
|
assert!(metadata.executable_in_runtime);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_recovered_locomotive_availability_row_with_structured_locomotive_id() {
|
fn parses_recovered_locomotive_availability_row_with_structured_locomotive_id() {
|
||||||
let row_bytes = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
|
let row_bytes = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
|
||||||
|
|
@ -11568,6 +11636,17 @@ mod tests {
|
||||||
assert!(metadata.executable_in_runtime);
|
assert!(metadata.executable_in_runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn looks_up_runtime_variable_descriptor_metadata() {
|
||||||
|
let metadata =
|
||||||
|
real_grouped_effect_descriptor_metadata(43).expect("descriptor metadata should exist");
|
||||||
|
|
||||||
|
assert_eq!(metadata.label, "Company Variable 1");
|
||||||
|
assert_eq!(metadata.target_mask_bits, 0x01);
|
||||||
|
assert_eq!(metadata.parameter_family, "runtime_variable_scalar");
|
||||||
|
assert!(metadata.executable_in_runtime);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn looks_up_recovered_aggregate_cargo_production_descriptor_metadata() {
|
fn looks_up_recovered_aggregate_cargo_production_descriptor_metadata() {
|
||||||
let metadata =
|
let metadata =
|
||||||
|
|
@ -11616,6 +11695,17 @@ mod tests {
|
||||||
assert!(!metadata.executable_in_runtime);
|
assert!(!metadata.executable_in_runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn looks_up_extended_lower_band_locomotive_cost_descriptor_metadata() {
|
||||||
|
let metadata =
|
||||||
|
real_grouped_effect_descriptor_metadata(412).expect("descriptor metadata should exist");
|
||||||
|
|
||||||
|
assert_eq!(metadata.label, "Zephyr Cost");
|
||||||
|
assert_eq!(metadata.parameter_family, "locomotive_cost_scalar");
|
||||||
|
assert_eq!(recovered_locomotive_cost_loco_id(412), Some(61));
|
||||||
|
assert!(metadata.executable_in_runtime);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn looks_up_recovered_territory_access_cost_descriptor_metadata() {
|
fn looks_up_recovered_territory_access_cost_descriptor_metadata() {
|
||||||
let metadata =
|
let metadata =
|
||||||
|
|
|
||||||
|
|
@ -636,6 +636,52 @@ fn apply_runtime_effects(
|
||||||
RuntimeEffect::SetCargoProductionSlot { slot, value } => {
|
RuntimeEffect::SetCargoProductionSlot { slot, value } => {
|
||||||
state.cargo_production_overrides.insert(*slot, *value);
|
state.cargo_production_overrides.insert(*slot, *value);
|
||||||
}
|
}
|
||||||
|
RuntimeEffect::SetWorldVariable { index, value } => {
|
||||||
|
state.world_runtime_variables.insert(*index, *value);
|
||||||
|
}
|
||||||
|
RuntimeEffect::SetCompanyVariable {
|
||||||
|
target,
|
||||||
|
index,
|
||||||
|
value,
|
||||||
|
} => {
|
||||||
|
let company_ids = resolve_company_target_ids(state, target, condition_context)?;
|
||||||
|
for company_id in company_ids {
|
||||||
|
state
|
||||||
|
.company_runtime_variables
|
||||||
|
.entry(company_id)
|
||||||
|
.or_default()
|
||||||
|
.insert(*index, *value);
|
||||||
|
mutated_company_ids.insert(company_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RuntimeEffect::SetPlayerVariable {
|
||||||
|
target,
|
||||||
|
index,
|
||||||
|
value,
|
||||||
|
} => {
|
||||||
|
let player_ids = resolve_player_target_ids(state, target, condition_context)?;
|
||||||
|
for player_id in player_ids {
|
||||||
|
state
|
||||||
|
.player_runtime_variables
|
||||||
|
.entry(player_id)
|
||||||
|
.or_default()
|
||||||
|
.insert(*index, *value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RuntimeEffect::SetTerritoryVariable {
|
||||||
|
target,
|
||||||
|
index,
|
||||||
|
value,
|
||||||
|
} => {
|
||||||
|
let territory_ids = resolve_territory_target_ids(state, target)?;
|
||||||
|
for territory_id in territory_ids {
|
||||||
|
state
|
||||||
|
.territory_runtime_variables
|
||||||
|
.entry(territory_id)
|
||||||
|
.or_default()
|
||||||
|
.insert(*index, *value);
|
||||||
|
}
|
||||||
|
}
|
||||||
RuntimeEffect::SetTerritoryAccessCost { value } => {
|
RuntimeEffect::SetTerritoryAccessCost { value } => {
|
||||||
state.world_restore.territory_access_cost = Some(*value);
|
state.world_restore.territory_access_cost = Some(*value);
|
||||||
}
|
}
|
||||||
|
|
@ -1596,6 +1642,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -2008,6 +2058,128 @@ mod tests {
|
||||||
assert_eq!(result.service_events[0].applied_effect_count, 7);
|
assert_eq!(result.service_events[0].applied_effect_count, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn applies_runtime_variable_effects() {
|
||||||
|
let mut state = RuntimeState {
|
||||||
|
companies: vec![
|
||||||
|
RuntimeCompany {
|
||||||
|
company_id: 1,
|
||||||
|
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||||
|
current_cash: 10,
|
||||||
|
debt: 0,
|
||||||
|
credit_rating_score: None,
|
||||||
|
prime_rate: None,
|
||||||
|
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||||
|
active: true,
|
||||||
|
available_track_laying_capacity: None,
|
||||||
|
linked_chairman_profile_id: None,
|
||||||
|
book_value_per_share: 0,
|
||||||
|
investor_confidence: 0,
|
||||||
|
management_attitude: 0,
|
||||||
|
takeover_cooldown_year: None,
|
||||||
|
merger_cooldown_year: None,
|
||||||
|
},
|
||||||
|
RuntimeCompany {
|
||||||
|
company_id: 2,
|
||||||
|
controller_kind: RuntimeCompanyControllerKind::Ai,
|
||||||
|
current_cash: 20,
|
||||||
|
debt: 0,
|
||||||
|
credit_rating_score: None,
|
||||||
|
prime_rate: None,
|
||||||
|
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||||
|
active: true,
|
||||||
|
available_track_laying_capacity: None,
|
||||||
|
linked_chairman_profile_id: None,
|
||||||
|
book_value_per_share: 0,
|
||||||
|
investor_confidence: 0,
|
||||||
|
management_attitude: 0,
|
||||||
|
takeover_cooldown_year: None,
|
||||||
|
merger_cooldown_year: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
players: vec![RuntimePlayer {
|
||||||
|
player_id: 9,
|
||||||
|
current_cash: 0,
|
||||||
|
active: true,
|
||||||
|
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||||
|
}],
|
||||||
|
territories: vec![RuntimeTerritory {
|
||||||
|
territory_id: 7,
|
||||||
|
name: Some("North".to_string()),
|
||||||
|
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||||
|
}],
|
||||||
|
event_runtime_records: vec![RuntimeEventRecord {
|
||||||
|
record_id: 14,
|
||||||
|
trigger_kind: 7,
|
||||||
|
active: true,
|
||||||
|
service_count: 0,
|
||||||
|
marks_collection_dirty: false,
|
||||||
|
one_shot: false,
|
||||||
|
has_fired: false,
|
||||||
|
conditions: Vec::new(),
|
||||||
|
effects: vec![
|
||||||
|
RuntimeEffect::SetWorldVariable {
|
||||||
|
index: 1,
|
||||||
|
value: -5,
|
||||||
|
},
|
||||||
|
RuntimeEffect::SetCompanyVariable {
|
||||||
|
target: RuntimeCompanyTarget::AllActive,
|
||||||
|
index: 2,
|
||||||
|
value: 17,
|
||||||
|
},
|
||||||
|
RuntimeEffect::SetPlayerVariable {
|
||||||
|
target: RuntimePlayerTarget::Ids { ids: vec![9] },
|
||||||
|
index: 3,
|
||||||
|
value: 99,
|
||||||
|
},
|
||||||
|
RuntimeEffect::SetTerritoryVariable {
|
||||||
|
target: RuntimeTerritoryTarget::Ids { ids: vec![7] },
|
||||||
|
index: 4,
|
||||||
|
value: 1234,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
..state()
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_step_command(
|
||||||
|
&mut state,
|
||||||
|
&StepCommand::ServiceTriggerKind { trigger_kind: 7 },
|
||||||
|
)
|
||||||
|
.expect("runtime variable effects should succeed");
|
||||||
|
|
||||||
|
assert_eq!(state.world_runtime_variables.get(&1), Some(&-5));
|
||||||
|
assert_eq!(
|
||||||
|
state
|
||||||
|
.company_runtime_variables
|
||||||
|
.get(&1)
|
||||||
|
.and_then(|vars| vars.get(&2)),
|
||||||
|
Some(&17)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
state
|
||||||
|
.company_runtime_variables
|
||||||
|
.get(&2)
|
||||||
|
.and_then(|vars| vars.get(&2)),
|
||||||
|
Some(&17)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
state
|
||||||
|
.player_runtime_variables
|
||||||
|
.get(&9)
|
||||||
|
.and_then(|vars| vars.get(&3)),
|
||||||
|
Some(&99)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
state
|
||||||
|
.territory_runtime_variables
|
||||||
|
.get(&7)
|
||||||
|
.and_then(|vars| vars.get(&4)),
|
||||||
|
Some(&1234)
|
||||||
|
);
|
||||||
|
assert_eq!(result.service_events[0].applied_effect_count, 4);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolves_symbolic_company_targets() {
|
fn resolves_symbolic_company_targets() {
|
||||||
let mut state = RuntimeState {
|
let mut state = RuntimeState {
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,10 @@ 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_runtime_variable_count: usize,
|
||||||
|
pub company_runtime_variable_owner_count: usize,
|
||||||
|
pub player_runtime_variable_owner_count: usize,
|
||||||
|
pub territory_runtime_variable_owner_count: usize,
|
||||||
pub world_scalar_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,
|
||||||
|
|
@ -707,6 +711,10 @@ 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_runtime_variable_count: state.world_runtime_variables.len(),
|
||||||
|
company_runtime_variable_owner_count: state.company_runtime_variables.len(),
|
||||||
|
player_runtime_variable_owner_count: state.player_runtime_variables.len(),
|
||||||
|
territory_runtime_variable_owner_count: state.territory_runtime_variables.len(),
|
||||||
world_scalar_override_count: state.world_scalar_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
|
||||||
|
|
@ -747,9 +755,9 @@ mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CalendarPoint, RuntimeCompany, RuntimeCompanyControllerKind,
|
CalendarPoint, RuntimeCompany, RuntimeCompanyControllerKind,
|
||||||
RuntimePackedEventCollectionSummary, RuntimePackedEventRecordSummary,
|
RuntimePackedEventCollectionSummary, RuntimePackedEventRecordSummary, RuntimePlayer,
|
||||||
RuntimeSaveProfileState, RuntimeServiceState, RuntimeState, RuntimeTrackPieceCounts,
|
RuntimeSaveProfileState, RuntimeServiceState, RuntimeState, RuntimeTerritory,
|
||||||
RuntimeWorldRestoreState,
|
RuntimeTrackPieceCounts, RuntimeWorldRestoreState,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::RuntimeSummary;
|
use super::RuntimeSummary;
|
||||||
|
|
@ -941,6 +949,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -1064,6 +1076,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -1124,6 +1140,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -1176,6 +1196,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -1226,6 +1250,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
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_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -1237,6 +1265,85 @@ mod tests {
|
||||||
assert_eq!(summary.world_restore_territory_access_cost, Some(750000));
|
assert_eq!(summary.world_restore_territory_access_cost, Some(750000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn counts_runtime_variable_surfaces() {
|
||||||
|
let state = RuntimeState {
|
||||||
|
calendar: CalendarPoint {
|
||||||
|
year: 1830,
|
||||||
|
month_slot: 0,
|
||||||
|
phase_slot: 0,
|
||||||
|
tick_slot: 0,
|
||||||
|
},
|
||||||
|
world_flags: BTreeMap::new(),
|
||||||
|
save_profile: RuntimeSaveProfileState::default(),
|
||||||
|
world_restore: RuntimeWorldRestoreState::default(),
|
||||||
|
metadata: BTreeMap::new(),
|
||||||
|
companies: vec![RuntimeCompany {
|
||||||
|
company_id: 1,
|
||||||
|
current_cash: 0,
|
||||||
|
debt: 0,
|
||||||
|
credit_rating_score: None,
|
||||||
|
prime_rate: None,
|
||||||
|
active: true,
|
||||||
|
available_track_laying_capacity: None,
|
||||||
|
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||||
|
linked_chairman_profile_id: None,
|
||||||
|
book_value_per_share: 0,
|
||||||
|
investor_confidence: 0,
|
||||||
|
management_attitude: 0,
|
||||||
|
takeover_cooldown_year: None,
|
||||||
|
merger_cooldown_year: None,
|
||||||
|
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||||
|
}],
|
||||||
|
selected_company_id: None,
|
||||||
|
players: vec![RuntimePlayer {
|
||||||
|
player_id: 2,
|
||||||
|
current_cash: 0,
|
||||||
|
active: true,
|
||||||
|
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||||
|
}],
|
||||||
|
selected_player_id: None,
|
||||||
|
chairman_profiles: Vec::new(),
|
||||||
|
selected_chairman_profile_id: None,
|
||||||
|
trains: Vec::new(),
|
||||||
|
locomotive_catalog: Vec::new(),
|
||||||
|
cargo_catalog: Vec::new(),
|
||||||
|
territories: vec![RuntimeTerritory {
|
||||||
|
territory_id: 3,
|
||||||
|
name: Some("East".to_string()),
|
||||||
|
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||||
|
}],
|
||||||
|
company_territory_track_piece_counts: Vec::new(),
|
||||||
|
company_territory_access: Vec::new(),
|
||||||
|
packed_event_collection: None,
|
||||||
|
event_runtime_records: Vec::new(),
|
||||||
|
candidate_availability: BTreeMap::new(),
|
||||||
|
named_locomotive_availability: 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(),
|
||||||
|
world_runtime_variables: BTreeMap::from([(1, 9)]),
|
||||||
|
company_runtime_variables: BTreeMap::from([(1, BTreeMap::from([(2, 11)]))]),
|
||||||
|
player_runtime_variables: BTreeMap::from([(2, BTreeMap::from([(3, 13)]))]),
|
||||||
|
territory_runtime_variables: BTreeMap::from([(3, BTreeMap::from([(4, 15)]))]),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
|
special_conditions: BTreeMap::new(),
|
||||||
|
service_state: RuntimeServiceState::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let summary = RuntimeSummary::from_state(&state);
|
||||||
|
|
||||||
|
assert_eq!(summary.world_runtime_variable_count, 1);
|
||||||
|
assert_eq!(summary.company_runtime_variable_owner_count, 1);
|
||||||
|
assert_eq!(summary.player_runtime_variable_owner_count, 1);
|
||||||
|
assert_eq!(summary.territory_runtime_variable_owner_count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn counts_world_frontier_buckets_separately() {
|
fn counts_world_frontier_buckets_separately() {
|
||||||
let state = RuntimeState {
|
let state = RuntimeState {
|
||||||
|
|
@ -1338,6 +1445,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -1428,6 +1539,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
@ -1514,6 +1629,10 @@ mod tests {
|
||||||
farm_mine_cargo_production_override: None,
|
farm_mine_cargo_production_override: None,
|
||||||
named_cargo_production_overrides: BTreeMap::new(),
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
cargo_production_overrides: BTreeMap::new(),
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
world_scalar_overrides: BTreeMap::new(),
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
special_conditions: BTreeMap::new(),
|
special_conditions: BTreeMap::new(),
|
||||||
service_state: RuntimeServiceState::default(),
|
service_state: RuntimeServiceState::default(),
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,9 @@ 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 runtime-variable strip `39..54` now executes too through bounded event-owned scalar maps on
|
||||||
|
world/company/player/territory state; these variables are runtime-owned only in the current
|
||||||
|
model and are not yet reconstructed from raw saves
|
||||||
- the grounded aggregate cargo-economics descriptors now execute too: descriptor `105`
|
- 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 Cargo Prices` and descriptors `177..179` `All Cargo Production` / `All Factory Production`
|
||||||
/ `All Farm/Mine Production` land on bounded event-owned cargo override state, and the grounded
|
/ `All Farm/Mine Production` land on bounded event-owned cargo override state, and the grounded
|
||||||
|
|
@ -168,6 +171,8 @@ The highest-value next passes are now:
|
||||||
- recovered scalar locomotive availability and locomotive-cost descriptors now import through that
|
- recovered scalar locomotive availability and locomotive-cost descriptors now import through that
|
||||||
save-native or embedded `RuntimeState.locomotive_catalog` context into the ordinary
|
save-native or embedded `RuntimeState.locomotive_catalog` context into the ordinary
|
||||||
`named_locomotive_availability` and `named_locomotive_cost` runtime maps
|
`named_locomotive_availability` and `named_locomotive_cost` runtime maps
|
||||||
|
- the grounded executable lower locomotive prefix now extends through save-backed locomotive id
|
||||||
|
`61` (`Zephyr`); the unresolved lower tail and upper locomotive bands stay on explicit parity
|
||||||
- cargo-production `230..240` and territory-access-cost `453` now execute too through minimal
|
- cargo-production `230..240` and territory-access-cost `453` now execute too through minimal
|
||||||
world-side scalar landing surfaces: slot-indexed `cargo_production_overrides` and
|
world-side scalar landing surfaces: slot-indexed `cargo_production_overrides` and
|
||||||
`world_restore.territory_access_cost`
|
`world_restore.territory_access_cost`
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,9 @@ 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 runtime-variable strip `39..54` now imports and executes too through bounded event-owned
|
||||||
|
world/company/player/territory variable maps, so those descriptors no longer depend on generic
|
||||||
|
evidence parity or ad hoc fixture-only state
|
||||||
- the grounded aggregate cargo-economics descriptors now execute too: descriptor `105`
|
- 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 Cargo Prices` and descriptors `177..179` `All Cargo Production` / `All Factory Production`
|
||||||
/ `All Farm/Mine Production` import through bounded cargo override surfaces, and the grounded
|
/ `All Farm/Mine Production` import through bounded cargo override surfaces, and the grounded
|
||||||
|
|
@ -130,7 +133,8 @@ Implemented today:
|
||||||
through `RuntimeState.locomotive_catalog` into `RuntimeState.named_locomotive_availability`;
|
through `RuntimeState.locomotive_catalog` into `RuntimeState.named_locomotive_availability`;
|
||||||
raw `.smp` inspection/export now reconstructs the save-side locomotive row family and derives the
|
raw `.smp` inspection/export now reconstructs the save-side locomotive row family and derives the
|
||||||
catalog directly into save-slice documents, so standalone save-slice imports can execute those
|
catalog directly into save-slice documents, so standalone save-slice imports can execute those
|
||||||
rows whenever the save carries enough catalog entries
|
rows whenever the save carries enough catalog entries, and the grounded executable lower prefix
|
||||||
|
now extends through save-backed locomotive id `61` (`Zephyr`)
|
||||||
- the grounded lower locomotive-cost band `352..409` now imports too through the same save-native
|
- the grounded lower locomotive-cost band `352..409` now imports too through the same save-native
|
||||||
or embedded catalog into the event-owned `RuntimeState.named_locomotive_cost` map when its
|
or embedded catalog into the event-owned `RuntimeState.named_locomotive_cost` map when its
|
||||||
scalar payloads are nonnegative; the unresolved lower tail and upper cost tail now stay on
|
scalar payloads are nonnegative; the unresolved lower tail and upper cost tail now stay on
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
{
|
||||||
|
"format_version": 1,
|
||||||
|
"fixture_id": "packed-event-runtime-variable-overlay-fixture",
|
||||||
|
"source": {
|
||||||
|
"kind": "captured-runtime",
|
||||||
|
"description": "Fixture proving descriptors 39..54 import and execute through bounded world/company/player/territory runtime-variable surfaces."
|
||||||
|
},
|
||||||
|
"state_import_path": "packed-event-runtime-variable-overlay.json",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"kind": "service_trigger_kind",
|
||||||
|
"trigger_kind": 7
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_summary": {
|
||||||
|
"calendar_projection_source": "base-snapshot-preserved",
|
||||||
|
"calendar_projection_is_placeholder": false,
|
||||||
|
"company_count": 3,
|
||||||
|
"player_count": 2,
|
||||||
|
"territory_count": 2,
|
||||||
|
"packed_event_collection_present": true,
|
||||||
|
"packed_event_record_count": 4,
|
||||||
|
"packed_event_decoded_record_count": 4,
|
||||||
|
"packed_event_imported_runtime_record_count": 4,
|
||||||
|
"event_runtime_record_count": 4,
|
||||||
|
"world_runtime_variable_count": 1,
|
||||||
|
"company_runtime_variable_owner_count": 1,
|
||||||
|
"player_runtime_variable_owner_count": 1,
|
||||||
|
"territory_runtime_variable_owner_count": 1,
|
||||||
|
"total_event_record_service_count": 4,
|
||||||
|
"total_trigger_dispatch_count": 1
|
||||||
|
},
|
||||||
|
"expected_state_fragment": {
|
||||||
|
"world_runtime_variables": {
|
||||||
|
"1": 111
|
||||||
|
},
|
||||||
|
"company_runtime_variables": {
|
||||||
|
"1": {
|
||||||
|
"2": 222
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"player_runtime_variables": {
|
||||||
|
"1": {
|
||||||
|
"3": 333
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"territory_runtime_variables": {
|
||||||
|
"7": {
|
||||||
|
"4": 444
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"packed_event_collection": {
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"import_outcome": "imported"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"import_outcome": "imported"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"import_outcome": "imported"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"import_outcome": "imported"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"event_runtime_records": [
|
||||||
|
{
|
||||||
|
"record_id": 71,
|
||||||
|
"service_count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"record_id": 72,
|
||||||
|
"service_count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"record_id": 73,
|
||||||
|
"service_count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"record_id": 74,
|
||||||
|
"service_count": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"format_version": 1,
|
||||||
|
"import_id": "packed-event-runtime-variable-overlay",
|
||||||
|
"source": {
|
||||||
|
"description": "Overlay import combining company/player/territory runtime context with the runtime-variable descriptor sample."
|
||||||
|
},
|
||||||
|
"base_snapshot_path": "packed-event-territory-player-overlay-base-snapshot.json",
|
||||||
|
"save_slice_path": "packed-event-runtime-variable-save-slice.json"
|
||||||
|
}
|
||||||
320
fixtures/runtime/packed-event-runtime-variable-save-slice.json
Normal file
320
fixtures/runtime/packed-event-runtime-variable-save-slice.json
Normal file
|
|
@ -0,0 +1,320 @@
|
||||||
|
{
|
||||||
|
"format_version": 1,
|
||||||
|
"save_slice_id": "packed-event-runtime-variable-save-slice",
|
||||||
|
"source": {
|
||||||
|
"description": "Tracked save-slice document proving runtime-variable descriptors 39..54 execute through bounded world/company/player/territory variable surfaces.",
|
||||||
|
"original_save_filename": "captured-runtime-variable.gms",
|
||||||
|
"original_save_sha256": "runtime-variable-sample-sha256",
|
||||||
|
"notes": [
|
||||||
|
"tracked as JSON save-slice document rather than raw .smp",
|
||||||
|
"uses overlay-backed company/player/territory context while leaving world variables save-slice-native"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"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": 33280,
|
||||||
|
"records_tag_offset": 33536,
|
||||||
|
"close_tag_offset": 34560,
|
||||||
|
"packed_state_version": 1001,
|
||||||
|
"packed_state_version_hex": "0x000003e9",
|
||||||
|
"live_id_bound": 74,
|
||||||
|
"live_record_count": 4,
|
||||||
|
"live_entry_ids": [71, 72, 73, 74],
|
||||||
|
"decoded_record_count": 4,
|
||||||
|
"imported_runtime_record_count": 0,
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"record_index": 0,
|
||||||
|
"live_entry_id": 71,
|
||||||
|
"payload_offset": 33568,
|
||||||
|
"payload_len": 160,
|
||||||
|
"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": [1, 0, 0, 0],
|
||||||
|
"grouped_effect_rows": [
|
||||||
|
{
|
||||||
|
"group_index": 0,
|
||||||
|
"row_index": 0,
|
||||||
|
"descriptor_id": 39,
|
||||||
|
"descriptor_label": "Game Variable 1",
|
||||||
|
"target_mask_bits": 8,
|
||||||
|
"parameter_family": "runtime_variable_scalar",
|
||||||
|
"opcode": 3,
|
||||||
|
"raw_scalar_value": 111,
|
||||||
|
"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 Game Variable 1 to 111",
|
||||||
|
"grouped_target_subject": "whole_game",
|
||||||
|
"grouped_target_scope": "whole_game",
|
||||||
|
"recovered_locomotive_id": null,
|
||||||
|
"locomotive_name": null,
|
||||||
|
"notes": [
|
||||||
|
"descriptor recovered from checked-in EventEffects semantic catalog"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"decoded_actions": [
|
||||||
|
{
|
||||||
|
"kind": "set_world_variable",
|
||||||
|
"index": 1,
|
||||||
|
"value": 111
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"executable_import_ready": true,
|
||||||
|
"notes": [
|
||||||
|
"runtime variable world sample"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"record_index": 1,
|
||||||
|
"live_entry_id": 72,
|
||||||
|
"payload_offset": 33728,
|
||||||
|
"payload_len": 160,
|
||||||
|
"decode_status": "executable",
|
||||||
|
"payload_family": "real_packed_v1",
|
||||||
|
"trigger_kind": 7,
|
||||||
|
"one_shot": false,
|
||||||
|
"compact_control": {
|
||||||
|
"mode_byte_0x7ef": 7,
|
||||||
|
"primary_selector_0x7f0": 99,
|
||||||
|
"grouped_mode_0x7f4": 2,
|
||||||
|
"one_shot_header_0x7f5": 0,
|
||||||
|
"modifier_flag_0x7f9": 1,
|
||||||
|
"modifier_flag_0x7fa": 0,
|
||||||
|
"grouped_target_scope_ordinals_0x7fb": [1, 1, 1, 1],
|
||||||
|
"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": [1, 0, 0, 0],
|
||||||
|
"grouped_effect_rows": [
|
||||||
|
{
|
||||||
|
"group_index": 0,
|
||||||
|
"row_index": 0,
|
||||||
|
"descriptor_id": 44,
|
||||||
|
"descriptor_label": "Company Variable 2",
|
||||||
|
"target_mask_bits": 1,
|
||||||
|
"parameter_family": "runtime_variable_scalar",
|
||||||
|
"opcode": 3,
|
||||||
|
"raw_scalar_value": 222,
|
||||||
|
"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 Company Variable 2 to 222",
|
||||||
|
"grouped_target_subject": "company",
|
||||||
|
"grouped_target_scope": "selected_company",
|
||||||
|
"recovered_locomotive_id": null,
|
||||||
|
"locomotive_name": null,
|
||||||
|
"notes": [
|
||||||
|
"descriptor recovered from checked-in EventEffects semantic catalog"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"decoded_actions": [
|
||||||
|
{
|
||||||
|
"kind": "set_company_variable",
|
||||||
|
"target": {
|
||||||
|
"kind": "selected_company"
|
||||||
|
},
|
||||||
|
"index": 2,
|
||||||
|
"value": 222
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"executable_import_ready": true,
|
||||||
|
"notes": [
|
||||||
|
"runtime variable company sample"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"record_index": 2,
|
||||||
|
"live_entry_id": 73,
|
||||||
|
"payload_offset": 33888,
|
||||||
|
"payload_len": 160,
|
||||||
|
"decode_status": "executable",
|
||||||
|
"payload_family": "real_packed_v1",
|
||||||
|
"trigger_kind": 7,
|
||||||
|
"one_shot": false,
|
||||||
|
"compact_control": {
|
||||||
|
"mode_byte_0x7ef": 7,
|
||||||
|
"primary_selector_0x7f0": 12,
|
||||||
|
"grouped_mode_0x7f4": 2,
|
||||||
|
"one_shot_header_0x7f5": 0,
|
||||||
|
"modifier_flag_0x7f9": 0,
|
||||||
|
"modifier_flag_0x7fa": 0,
|
||||||
|
"grouped_target_scope_ordinals_0x7fb": [1, 1, 1, 1],
|
||||||
|
"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": [1, 0, 0, 0],
|
||||||
|
"grouped_effect_rows": [
|
||||||
|
{
|
||||||
|
"group_index": 0,
|
||||||
|
"row_index": 0,
|
||||||
|
"descriptor_id": 49,
|
||||||
|
"descriptor_label": "Player Variable 3",
|
||||||
|
"target_mask_bits": 2,
|
||||||
|
"parameter_family": "runtime_variable_scalar",
|
||||||
|
"opcode": 3,
|
||||||
|
"raw_scalar_value": 333,
|
||||||
|
"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 Player Variable 3 to 333",
|
||||||
|
"grouped_target_subject": "player",
|
||||||
|
"grouped_target_scope": "selected_player",
|
||||||
|
"recovered_locomotive_id": null,
|
||||||
|
"locomotive_name": null,
|
||||||
|
"notes": [
|
||||||
|
"descriptor recovered from checked-in EventEffects semantic catalog"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"decoded_actions": [
|
||||||
|
{
|
||||||
|
"kind": "set_player_variable",
|
||||||
|
"target": {
|
||||||
|
"kind": "selected_player"
|
||||||
|
},
|
||||||
|
"index": 3,
|
||||||
|
"value": 333
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"executable_import_ready": true,
|
||||||
|
"notes": [
|
||||||
|
"runtime variable player sample"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"record_index": 3,
|
||||||
|
"live_entry_id": 74,
|
||||||
|
"payload_offset": 34048,
|
||||||
|
"payload_len": 160,
|
||||||
|
"decode_status": "executable",
|
||||||
|
"payload_family": "real_packed_v1",
|
||||||
|
"trigger_kind": 7,
|
||||||
|
"one_shot": false,
|
||||||
|
"compact_control": {
|
||||||
|
"mode_byte_0x7ef": 7,
|
||||||
|
"primary_selector_0x7f0": 12,
|
||||||
|
"grouped_mode_0x7f4": 2,
|
||||||
|
"one_shot_header_0x7f5": 0,
|
||||||
|
"modifier_flag_0x7f9": 0,
|
||||||
|
"modifier_flag_0x7fa": 0,
|
||||||
|
"grouped_target_scope_ordinals_0x7fb": [1, 1, 1, 1],
|
||||||
|
"grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0],
|
||||||
|
"summary_toggle_0x800": 1,
|
||||||
|
"grouped_territory_selectors_0x80f": [7, -1, -1, -1]
|
||||||
|
},
|
||||||
|
"text_bands": [],
|
||||||
|
"standalone_condition_row_count": 0,
|
||||||
|
"standalone_condition_rows": [],
|
||||||
|
"grouped_effect_row_counts": [1, 0, 0, 0],
|
||||||
|
"grouped_effect_rows": [
|
||||||
|
{
|
||||||
|
"group_index": 0,
|
||||||
|
"row_index": 0,
|
||||||
|
"descriptor_id": 54,
|
||||||
|
"descriptor_label": "Territory Variable 4",
|
||||||
|
"target_mask_bits": 4,
|
||||||
|
"parameter_family": "runtime_variable_scalar",
|
||||||
|
"opcode": 3,
|
||||||
|
"raw_scalar_value": 444,
|
||||||
|
"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 Territory Variable 4 to 444",
|
||||||
|
"grouped_target_subject": "territory",
|
||||||
|
"grouped_target_scope": "named_territory",
|
||||||
|
"recovered_locomotive_id": null,
|
||||||
|
"locomotive_name": null,
|
||||||
|
"notes": [
|
||||||
|
"descriptor recovered from checked-in EventEffects semantic catalog"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"decoded_actions": [
|
||||||
|
{
|
||||||
|
"kind": "set_territory_variable",
|
||||||
|
"target": {
|
||||||
|
"kind": "ids",
|
||||||
|
"ids": [7]
|
||||||
|
},
|
||||||
|
"index": 4,
|
||||||
|
"value": 444
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"executable_import_ready": true,
|
||||||
|
"notes": [
|
||||||
|
"runtime variable territory sample"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notes": [
|
||||||
|
"runtime variable descriptor executable sample"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -64,6 +64,9 @@ GROUNDED_LOCOMOTIVE_PREFIX = {
|
||||||
56: "Trans-Euro",
|
56: "Trans-Euro",
|
||||||
57: "V200",
|
57: "V200",
|
||||||
58: "VL80T",
|
58: "VL80T",
|
||||||
|
59: "GP 35",
|
||||||
|
60: "U1",
|
||||||
|
61: "Zephyr",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -208,6 +211,8 @@ def classify(
|
||||||
runtime_status = "shell_owned"
|
runtime_status = "shell_owned"
|
||||||
elif signature_byte_0x63 == 0 and signature_byte_0x64 == 0x8F:
|
elif signature_byte_0x63 == 0 and signature_byte_0x64 == 0x8F:
|
||||||
parameter_family = "runtime_variable_scalar"
|
parameter_family = "runtime_variable_scalar"
|
||||||
|
runtime_status = "executable"
|
||||||
|
executable_in_runtime = True
|
||||||
elif "Earthquake" in label or "Storm" in label:
|
elif "Earthquake" in label or "Storm" in label:
|
||||||
parameter_family = "world_disaster_scalar"
|
parameter_family = "world_disaster_scalar"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue