Implement world-scalar packed event conditions
This commit is contained in:
parent
b060c42fa2
commit
3f2632e330
12 changed files with 1541 additions and 8 deletions
|
|
@ -58,7 +58,13 @@ rows directly into `RuntimeState.named_locomotive_availability` and
|
|||
`RuntimeState.named_locomotive_cost` without needing overlay snapshots when the save carries enough
|
||||
catalog context. The remaining recovered scalar world families execute too: cargo-production slots
|
||||
`230..240` lower into `cargo_production_overrides`, and descriptor `453` lowers into
|
||||
`world_restore.territory_access_cost`. Explicit unmapped world-condition and world-descriptor
|
||||
`world_restore.territory_access_cost`. Whole-game ordinary-condition breadth now aligns with those
|
||||
same world-scalar runtime surfaces too: named locomotive availability thresholds, named
|
||||
locomotive cost thresholds, aggregate cargo-production thresholds, limited-track-building-amount
|
||||
thresholds, and territory-access-cost thresholds all gate imported runtime records through the
|
||||
same service path. Families the current checked-in metadata still does not ground, such as `All
|
||||
Factory Production`, now remain explicitly visible on `blocked_unmapped_world_condition` rather
|
||||
than collapsing back to generic residue. Explicit unmapped world-condition and world-descriptor
|
||||
frontier buckets still remain where current checked-in metadata stops, and
|
||||
`blocked_missing_locomotive_catalog_context` is now reserved for intentionally incomplete save-side
|
||||
catalog context instead of the normal save-slice path. Shell purchase-flow, Trainbuy refresh,
|
||||
|
|
|
|||
|
|
@ -4476,6 +4476,13 @@ mod tests {
|
|||
let world_scalar_executable_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
|
||||
"../../fixtures/runtime/packed-event-world-scalar-executable-save-slice-fixture.json",
|
||||
);
|
||||
let world_scalar_condition_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
|
||||
"../../fixtures/runtime/packed-event-world-scalar-condition-save-slice-fixture.json",
|
||||
);
|
||||
let world_scalar_condition_parity_fixture =
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
|
||||
"../../fixtures/runtime/packed-event-world-scalar-condition-parity-save-slice-fixture.json",
|
||||
);
|
||||
|
||||
run_runtime_summarize_fixture(&parity_fixture)
|
||||
.expect("save-slice-backed parity fixture should summarize");
|
||||
|
|
@ -4511,6 +4518,10 @@ mod tests {
|
|||
.expect("save-slice-backed recovered scalar-band parity fixture should summarize");
|
||||
run_runtime_summarize_fixture(&world_scalar_executable_fixture)
|
||||
.expect("save-slice-backed executable world-scalar fixture should summarize");
|
||||
run_runtime_summarize_fixture(&world_scalar_condition_fixture)
|
||||
.expect("save-slice-backed executable world-scalar condition fixture should summarize");
|
||||
run_runtime_summarize_fixture(&world_scalar_condition_parity_fixture)
|
||||
.expect("save-slice-backed parity world-scalar condition fixture should summarize");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -1544,6 +1544,42 @@ fn lower_condition_targets_in_condition(
|
|||
comparator: *comparator,
|
||||
value: *value,
|
||||
},
|
||||
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
|
||||
name,
|
||||
comparator,
|
||||
value,
|
||||
} => RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
|
||||
name: name.clone(),
|
||||
comparator: *comparator,
|
||||
value: *value,
|
||||
},
|
||||
RuntimeCondition::NamedLocomotiveCostThreshold {
|
||||
name,
|
||||
comparator,
|
||||
value,
|
||||
} => RuntimeCondition::NamedLocomotiveCostThreshold {
|
||||
name: name.clone(),
|
||||
comparator: *comparator,
|
||||
value: *value,
|
||||
},
|
||||
RuntimeCondition::CargoProductionTotalThreshold { comparator, value } => {
|
||||
RuntimeCondition::CargoProductionTotalThreshold {
|
||||
comparator: *comparator,
|
||||
value: *value,
|
||||
}
|
||||
}
|
||||
RuntimeCondition::LimitedTrackBuildingAmountThreshold { comparator, value } => {
|
||||
RuntimeCondition::LimitedTrackBuildingAmountThreshold {
|
||||
comparator: *comparator,
|
||||
value: *value,
|
||||
}
|
||||
}
|
||||
RuntimeCondition::TerritoryAccessCostThreshold { comparator, value } => {
|
||||
RuntimeCondition::TerritoryAccessCostThreshold {
|
||||
comparator: *comparator,
|
||||
value: *value,
|
||||
}
|
||||
}
|
||||
RuntimeCondition::EconomicStatusCodeThreshold { comparator, value } => {
|
||||
RuntimeCondition::EconomicStatusCodeThreshold {
|
||||
comparator: *comparator,
|
||||
|
|
@ -1633,6 +1669,11 @@ fn condition_uses_condition_true_company(condition: &RuntimeCondition) -> bool {
|
|||
RuntimeCondition::TerritoryNumericThreshold { .. }
|
||||
| RuntimeCondition::SpecialConditionThreshold { .. }
|
||||
| RuntimeCondition::CandidateAvailabilityThreshold { .. }
|
||||
| RuntimeCondition::NamedLocomotiveAvailabilityThreshold { .. }
|
||||
| RuntimeCondition::NamedLocomotiveCostThreshold { .. }
|
||||
| RuntimeCondition::CargoProductionTotalThreshold { .. }
|
||||
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
|
||||
| RuntimeCondition::TerritoryAccessCostThreshold { .. }
|
||||
| RuntimeCondition::EconomicStatusCodeThreshold { .. }
|
||||
| RuntimeCondition::WorldFlagEquals { .. } => false,
|
||||
}
|
||||
|
|
@ -2251,6 +2292,11 @@ fn runtime_condition_is_world_state(condition: &RuntimeCondition) -> bool {
|
|||
condition,
|
||||
RuntimeCondition::SpecialConditionThreshold { .. }
|
||||
| RuntimeCondition::CandidateAvailabilityThreshold { .. }
|
||||
| RuntimeCondition::NamedLocomotiveAvailabilityThreshold { .. }
|
||||
| RuntimeCondition::NamedLocomotiveCostThreshold { .. }
|
||||
| RuntimeCondition::CargoProductionTotalThreshold { .. }
|
||||
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
|
||||
| RuntimeCondition::TerritoryAccessCostThreshold { .. }
|
||||
| RuntimeCondition::EconomicStatusCodeThreshold { .. }
|
||||
| RuntimeCondition::WorldFlagEquals { .. }
|
||||
)
|
||||
|
|
@ -2262,12 +2308,18 @@ fn ordinary_condition_row_is_world_state_family(
|
|||
row.metric.as_deref().is_some_and(|metric| {
|
||||
metric.contains("Special Condition")
|
||||
|| metric.contains("Candidate Availability")
|
||||
|| metric.contains("Named Locomotive")
|
||||
|| metric.contains("Cargo Production")
|
||||
|| metric.contains("Limited Track Building Amount")
|
||||
|| metric.contains("Territory Access Cost")
|
||||
|| metric.contains("Economic Status")
|
||||
|| metric.contains("World Flag")
|
||||
}) || row
|
||||
.semantic_family
|
||||
.as_deref()
|
||||
.is_some_and(|family| family == "world_state_threshold" || family == "world_flag_equals")
|
||||
}) || row.semantic_family.as_deref().is_some_and(|family| {
|
||||
matches!(
|
||||
family,
|
||||
"world_state_threshold" | "world_scalar_threshold" | "world_flag_equals"
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn real_grouped_row_is_world_state_family(
|
||||
|
|
@ -2334,6 +2386,11 @@ fn runtime_condition_company_target_import_blocker(
|
|||
.or_else(|| territory_target_import_blocker(territory, company_context)),
|
||||
RuntimeCondition::SpecialConditionThreshold { .. }
|
||||
| RuntimeCondition::CandidateAvailabilityThreshold { .. }
|
||||
| RuntimeCondition::NamedLocomotiveAvailabilityThreshold { .. }
|
||||
| RuntimeCondition::NamedLocomotiveCostThreshold { .. }
|
||||
| RuntimeCondition::CargoProductionTotalThreshold { .. }
|
||||
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
|
||||
| RuntimeCondition::TerritoryAccessCostThreshold { .. }
|
||||
| RuntimeCondition::EconomicStatusCodeThreshold { .. }
|
||||
| RuntimeCondition::WorldFlagEquals { .. } => None,
|
||||
}
|
||||
|
|
@ -2855,7 +2912,10 @@ fn resolve_document_path(base_dir: &Path, path: &str) -> PathBuf {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{RuntimeTrackPieceCounts, RuntimeTrain, StepCommand, execute_step_command};
|
||||
use crate::{
|
||||
RuntimeConditionComparator, RuntimeTrackPieceCounts, RuntimeTrain, StepCommand,
|
||||
execute_step_command,
|
||||
};
|
||||
|
||||
fn state() -> RuntimeState {
|
||||
RuntimeState {
|
||||
|
|
@ -7859,6 +7919,262 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imports_and_executes_world_scalar_conditions_through_runtime_state() {
|
||||
let save_slice = SmpLoadedSaveSlice {
|
||||
file_extension_hint: Some("gms".to_string()),
|
||||
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||
mechanism_confidence: "grounded".to_string(),
|
||||
trailer_family: None,
|
||||
bridge_family: None,
|
||||
profile: None,
|
||||
candidate_availability_table: None,
|
||||
named_locomotive_availability_table: None,
|
||||
locomotive_catalog: None,
|
||||
special_conditions_table: None,
|
||||
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
|
||||
source_kind: "packed-event-runtime-collection".to_string(),
|
||||
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||
mechanism_confidence: "grounded".to_string(),
|
||||
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||
metadata_tag_offset: 0x7100,
|
||||
records_tag_offset: 0x7200,
|
||||
close_tag_offset: 0x7800,
|
||||
packed_state_version: 0x3e9,
|
||||
packed_state_version_hex: "0x000003e9".to_string(),
|
||||
live_id_bound: 45,
|
||||
live_record_count: 2,
|
||||
live_entry_ids: vec![41, 45],
|
||||
decoded_record_count: 2,
|
||||
imported_runtime_record_count: 2,
|
||||
records: vec![
|
||||
crate::SmpLoadedPackedEventRecordSummary {
|
||||
record_index: 0,
|
||||
live_entry_id: 41,
|
||||
payload_offset: Some(0x7200),
|
||||
payload_len: Some(192),
|
||||
decode_status: "executable".to_string(),
|
||||
payload_family: "real_packed_v1".to_string(),
|
||||
trigger_kind: Some(6),
|
||||
active: None,
|
||||
marks_collection_dirty: None,
|
||||
one_shot: Some(false),
|
||||
compact_control: Some(real_compact_control()),
|
||||
text_bands: packed_text_bands(),
|
||||
standalone_condition_row_count: 0,
|
||||
standalone_condition_rows: vec![],
|
||||
negative_sentinel_scope: None,
|
||||
grouped_effect_row_counts: vec![5, 0, 0, 0],
|
||||
grouped_effect_rows: vec![
|
||||
real_locomotive_availability_row(250, 42),
|
||||
real_locomotive_cost_row(352, 250000),
|
||||
real_cargo_production_row(230, 125),
|
||||
real_limited_track_building_amount_row(18),
|
||||
real_territory_access_cost_row(750000),
|
||||
],
|
||||
decoded_conditions: vec![],
|
||||
decoded_actions: vec![
|
||||
RuntimeEffect::SetNamedLocomotiveAvailabilityValue {
|
||||
name: "Big Boy".to_string(),
|
||||
value: 42,
|
||||
},
|
||||
RuntimeEffect::SetNamedLocomotiveCost {
|
||||
name: "Locomotive 1".to_string(),
|
||||
value: 250000,
|
||||
},
|
||||
RuntimeEffect::SetCargoProductionSlot {
|
||||
slot: 1,
|
||||
value: 125,
|
||||
},
|
||||
RuntimeEffect::SetLimitedTrackBuildingAmount { value: 18 },
|
||||
RuntimeEffect::SetTerritoryAccessCost { value: 750000 },
|
||||
],
|
||||
executable_import_ready: true,
|
||||
notes: vec!["world-scalar setup record".to_string()],
|
||||
},
|
||||
crate::SmpLoadedPackedEventRecordSummary {
|
||||
record_index: 1,
|
||||
live_entry_id: 45,
|
||||
payload_offset: Some(0x7300),
|
||||
payload_len: Some(184),
|
||||
decode_status: "executable".to_string(),
|
||||
payload_family: "real_packed_v1".to_string(),
|
||||
trigger_kind: Some(7),
|
||||
active: None,
|
||||
marks_collection_dirty: None,
|
||||
one_shot: Some(false),
|
||||
compact_control: Some(real_compact_control()),
|
||||
text_bands: packed_text_bands(),
|
||||
standalone_condition_row_count: 5,
|
||||
standalone_condition_rows: vec![
|
||||
crate::SmpLoadedPackedEventConditionRowSummary {
|
||||
row_index: 0,
|
||||
raw_condition_id: 2422,
|
||||
subtype: 4,
|
||||
flag_bytes: {
|
||||
let mut bytes = vec![0; 25];
|
||||
bytes[0..4].copy_from_slice(&42_i32.to_le_bytes());
|
||||
bytes
|
||||
},
|
||||
candidate_name: Some("Big Boy".to_string()),
|
||||
comparator: Some("eq".to_string()),
|
||||
metric: Some("Named Locomotive Availability: Big Boy".to_string()),
|
||||
semantic_family: Some("world_scalar_threshold".to_string()),
|
||||
semantic_preview: Some(
|
||||
"Test Named Locomotive Availability: Big Boy == 42".to_string(),
|
||||
),
|
||||
requires_candidate_name_binding: false,
|
||||
notes: vec![],
|
||||
},
|
||||
crate::SmpLoadedPackedEventConditionRowSummary {
|
||||
row_index: 1,
|
||||
raw_condition_id: 2423,
|
||||
subtype: 4,
|
||||
flag_bytes: {
|
||||
let mut bytes = vec![0; 25];
|
||||
bytes[0..4].copy_from_slice(&250000_i32.to_le_bytes());
|
||||
bytes
|
||||
},
|
||||
candidate_name: Some("Locomotive 1".to_string()),
|
||||
comparator: Some("eq".to_string()),
|
||||
metric: Some("Named Locomotive Cost: Locomotive 1".to_string()),
|
||||
semantic_family: Some("world_scalar_threshold".to_string()),
|
||||
semantic_preview: Some(
|
||||
"Test Named Locomotive Cost: Locomotive 1 == 250000"
|
||||
.to_string(),
|
||||
),
|
||||
requires_candidate_name_binding: false,
|
||||
notes: vec![],
|
||||
},
|
||||
crate::SmpLoadedPackedEventConditionRowSummary {
|
||||
row_index: 2,
|
||||
raw_condition_id: 2418,
|
||||
subtype: 4,
|
||||
flag_bytes: {
|
||||
let mut bytes = vec![0; 25];
|
||||
bytes[0..4].copy_from_slice(&125_i32.to_le_bytes());
|
||||
bytes
|
||||
},
|
||||
candidate_name: None,
|
||||
comparator: Some("eq".to_string()),
|
||||
metric: Some("Cargo Production Total".to_string()),
|
||||
semantic_family: Some("world_scalar_threshold".to_string()),
|
||||
semantic_preview: Some(
|
||||
"Test Cargo Production Total == 125".to_string(),
|
||||
),
|
||||
requires_candidate_name_binding: false,
|
||||
notes: vec![],
|
||||
},
|
||||
crate::SmpLoadedPackedEventConditionRowSummary {
|
||||
row_index: 3,
|
||||
raw_condition_id: 2547,
|
||||
subtype: 4,
|
||||
flag_bytes: {
|
||||
let mut bytes = vec![0; 25];
|
||||
bytes[0..4].copy_from_slice(&18_i32.to_le_bytes());
|
||||
bytes
|
||||
},
|
||||
candidate_name: None,
|
||||
comparator: Some("eq".to_string()),
|
||||
metric: Some("Limited Track Building Amount".to_string()),
|
||||
semantic_family: Some("world_scalar_threshold".to_string()),
|
||||
semantic_preview: Some(
|
||||
"Test Limited Track Building Amount == 18".to_string(),
|
||||
),
|
||||
requires_candidate_name_binding: false,
|
||||
notes: vec![],
|
||||
},
|
||||
crate::SmpLoadedPackedEventConditionRowSummary {
|
||||
row_index: 4,
|
||||
raw_condition_id: 1516,
|
||||
subtype: 4,
|
||||
flag_bytes: {
|
||||
let mut bytes = vec![0; 25];
|
||||
bytes[0..4].copy_from_slice(&750000_i32.to_le_bytes());
|
||||
bytes
|
||||
},
|
||||
candidate_name: None,
|
||||
comparator: Some("eq".to_string()),
|
||||
metric: Some("Territory Access Cost".to_string()),
|
||||
semantic_family: Some("world_scalar_threshold".to_string()),
|
||||
semantic_preview: Some(
|
||||
"Test Territory Access Cost == 750000".to_string(),
|
||||
),
|
||||
requires_candidate_name_binding: false,
|
||||
notes: vec![],
|
||||
},
|
||||
],
|
||||
negative_sentinel_scope: None,
|
||||
grouped_effect_row_counts: vec![1, 0, 0, 0],
|
||||
grouped_effect_rows: vec![real_world_flag_row(
|
||||
110,
|
||||
"Disable Stock Buying and Selling",
|
||||
true,
|
||||
)],
|
||||
decoded_conditions: vec![
|
||||
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
|
||||
name: "Big Boy".to_string(),
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 42,
|
||||
},
|
||||
RuntimeCondition::NamedLocomotiveCostThreshold {
|
||||
name: "Locomotive 1".to_string(),
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 250000,
|
||||
},
|
||||
RuntimeCondition::CargoProductionTotalThreshold {
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 125,
|
||||
},
|
||||
RuntimeCondition::LimitedTrackBuildingAmountThreshold {
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 18,
|
||||
},
|
||||
RuntimeCondition::TerritoryAccessCostThreshold {
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 750000,
|
||||
},
|
||||
],
|
||||
decoded_actions: vec![RuntimeEffect::SetWorldFlag {
|
||||
key: "world.world_scalar_conditions_passed".to_string(),
|
||||
value: true,
|
||||
}],
|
||||
executable_import_ready: true,
|
||||
notes: vec!["world-scalar conditions gate a world-side effect".to_string()],
|
||||
},
|
||||
],
|
||||
}),
|
||||
notes: vec![],
|
||||
};
|
||||
|
||||
let mut import = project_save_slice_to_runtime_state_import(
|
||||
&save_slice,
|
||||
"world-scalar-condition-save-slice",
|
||||
None,
|
||||
)
|
||||
.expect("save-slice import should project");
|
||||
|
||||
crate::execute_step_command(
|
||||
&mut import.state,
|
||||
&crate::StepCommand::ServiceTriggerKind { trigger_kind: 6 },
|
||||
)
|
||||
.expect("setup trigger should execute");
|
||||
crate::execute_step_command(
|
||||
&mut import.state,
|
||||
&crate::StepCommand::ServiceTriggerKind { trigger_kind: 7 },
|
||||
)
|
||||
.expect("gated trigger should execute");
|
||||
|
||||
assert_eq!(
|
||||
import
|
||||
.state
|
||||
.world_flags
|
||||
.get("world.world_scalar_conditions_passed"),
|
||||
Some(&true)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlays_recovered_world_toggle_batch_into_executable_runtime_record() {
|
||||
let base_state = state();
|
||||
|
|
|
|||
|
|
@ -244,6 +244,28 @@ pub enum RuntimeCondition {
|
|||
comparator: RuntimeConditionComparator,
|
||||
value: i64,
|
||||
},
|
||||
NamedLocomotiveAvailabilityThreshold {
|
||||
name: String,
|
||||
comparator: RuntimeConditionComparator,
|
||||
value: i64,
|
||||
},
|
||||
NamedLocomotiveCostThreshold {
|
||||
name: String,
|
||||
comparator: RuntimeConditionComparator,
|
||||
value: i64,
|
||||
},
|
||||
CargoProductionTotalThreshold {
|
||||
comparator: RuntimeConditionComparator,
|
||||
value: i64,
|
||||
},
|
||||
LimitedTrackBuildingAmountThreshold {
|
||||
comparator: RuntimeConditionComparator,
|
||||
value: i64,
|
||||
},
|
||||
TerritoryAccessCostThreshold {
|
||||
comparator: RuntimeConditionComparator,
|
||||
value: i64,
|
||||
},
|
||||
EconomicStatusCodeThreshold {
|
||||
comparator: RuntimeConditionComparator,
|
||||
value: i64,
|
||||
|
|
@ -1375,6 +1397,17 @@ fn validate_runtime_condition(
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
RuntimeCondition::NamedLocomotiveAvailabilityThreshold { name, .. }
|
||||
| RuntimeCondition::NamedLocomotiveCostThreshold { name, .. } => {
|
||||
if name.trim().is_empty() {
|
||||
Err("name must not be empty".to_string())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
RuntimeCondition::CargoProductionTotalThreshold { .. }
|
||||
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
|
||||
| RuntimeCondition::TerritoryAccessCostThreshold { .. } => Ok(()),
|
||||
RuntimeCondition::EconomicStatusCodeThreshold { .. } => Ok(()),
|
||||
RuntimeCondition::WorldFlagEquals { key, .. } => {
|
||||
if key.trim().is_empty() {
|
||||
|
|
|
|||
|
|
@ -240,6 +240,11 @@ enum RealOrdinaryConditionMetric {
|
|||
enum RealWorldConditionKind {
|
||||
SpecialCondition { label: &'static str },
|
||||
CandidateAvailability,
|
||||
NamedLocomotiveAvailability,
|
||||
NamedLocomotiveCost,
|
||||
CargoProductionTotal,
|
||||
LimitedTrackBuildingAmount,
|
||||
TerritoryAccessCost,
|
||||
EconomicStatus,
|
||||
WorldFlag { key: &'static str },
|
||||
}
|
||||
|
|
@ -258,8 +263,13 @@ struct RealOrdinaryConditionMetadata {
|
|||
}
|
||||
|
||||
const REAL_CANDIDATE_AVAILABILITY_CONDITION_TEMPLATE_ID: i32 = 435;
|
||||
const REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID: i32 = 2422;
|
||||
const REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID: i32 = 2423;
|
||||
const REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID: i32 = 2418;
|
||||
const REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID: i32 = 2547;
|
||||
const REAL_TERRITORY_ACCESS_COST_CONDITION_ID: i32 = 1516;
|
||||
|
||||
const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 24] = [
|
||||
const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 29] = [
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: 1802,
|
||||
label: "Current Cash",
|
||||
|
|
@ -419,6 +429,35 @@ const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 24] = [
|
|||
label: "%1 Avail.",
|
||||
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CandidateAvailability),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID,
|
||||
label: "Unknown Loco Available",
|
||||
kind: RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::NamedLocomotiveAvailability,
|
||||
),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID,
|
||||
label: "Unknown Loco Cost",
|
||||
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID,
|
||||
label: "All Cargo Production",
|
||||
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID,
|
||||
label: "Limited Track Building Amount",
|
||||
kind: RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::LimitedTrackBuildingAmount,
|
||||
),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: REAL_TERRITORY_ACCESS_COST_CONDITION_ID,
|
||||
label: "Access Rights Cost:",
|
||||
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: 2350,
|
||||
label: "Economic Status",
|
||||
|
|
@ -2526,6 +2565,17 @@ fn parse_real_condition_row_summary(
|
|||
.to_string(),
|
||||
);
|
||||
}
|
||||
if ordinary_metadata.is_some_and(|metadata| {
|
||||
matches!(
|
||||
metadata.kind,
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::NamedLocomotiveAvailability
|
||||
| RealWorldConditionKind::NamedLocomotiveCost
|
||||
)
|
||||
) && candidate_name.is_none()
|
||||
}) {
|
||||
notes.push("named locomotive condition row is missing its side-string binding".to_string());
|
||||
}
|
||||
Some(SmpLoadedPackedEventConditionRowSummary {
|
||||
row_index,
|
||||
raw_condition_id,
|
||||
|
|
@ -2645,6 +2695,27 @@ fn real_ordinary_condition_metric_label(
|
|||
None => "Candidate Availability".to_string(),
|
||||
}
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::NamedLocomotiveAvailability,
|
||||
) => match candidate_name {
|
||||
Some(name) => format!("Named Locomotive Availability: {name}"),
|
||||
None => "Named Locomotive Availability".to_string(),
|
||||
},
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost) => {
|
||||
match candidate_name {
|
||||
Some(name) => format!("Named Locomotive Cost: {name}"),
|
||||
None => "Named Locomotive Cost".to_string(),
|
||||
}
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal) => {
|
||||
"Cargo Production Total".to_string()
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::LimitedTrackBuildingAmount,
|
||||
) => "Limited Track Building Amount".to_string(),
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost) => {
|
||||
"Territory Access Cost".to_string()
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => {
|
||||
"Economic Status".to_string()
|
||||
}
|
||||
|
|
@ -2662,6 +2733,13 @@ fn real_ordinary_condition_semantic_family(
|
|||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { .. }) => {
|
||||
"world_flag_equals"
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::NamedLocomotiveAvailability
|
||||
| RealWorldConditionKind::NamedLocomotiveCost
|
||||
| RealWorldConditionKind::CargoProductionTotal
|
||||
| RealWorldConditionKind::LimitedTrackBuildingAmount
|
||||
| RealWorldConditionKind::TerritoryAccessCost,
|
||||
) => "world_scalar_threshold",
|
||||
RealOrdinaryConditionKind::WorldState(_) => "world_state_threshold",
|
||||
}
|
||||
}
|
||||
|
|
@ -2868,6 +2946,32 @@ fn decode_real_condition_row(
|
|||
comparator,
|
||||
value,
|
||||
}),
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::NamedLocomotiveAvailability,
|
||||
) => row.candidate_name.as_ref().map(|name| {
|
||||
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
|
||||
name: name.clone(),
|
||||
comparator,
|
||||
value,
|
||||
}
|
||||
}),
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost) => row
|
||||
.candidate_name
|
||||
.as_ref()
|
||||
.map(|name| RuntimeCondition::NamedLocomotiveCostThreshold {
|
||||
name: name.clone(),
|
||||
comparator,
|
||||
value,
|
||||
}),
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal) => {
|
||||
Some(RuntimeCondition::CargoProductionTotalThreshold { comparator, value })
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::LimitedTrackBuildingAmount,
|
||||
) => Some(RuntimeCondition::LimitedTrackBuildingAmountThreshold { comparator, value }),
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost) => {
|
||||
Some(RuntimeCondition::TerritoryAccessCostThreshold { comparator, value })
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => {
|
||||
Some(RuntimeCondition::EconomicStatusCodeThreshold { comparator, value })
|
||||
}
|
||||
|
|
@ -3655,6 +3759,11 @@ fn runtime_condition_supported_for_save_import(condition: &RuntimeCondition) ->
|
|||
| RuntimeCondition::CompanyTerritoryNumericThreshold { .. }
|
||||
| RuntimeCondition::SpecialConditionThreshold { .. }
|
||||
| RuntimeCondition::CandidateAvailabilityThreshold { .. }
|
||||
| RuntimeCondition::NamedLocomotiveAvailabilityThreshold { .. }
|
||||
| RuntimeCondition::NamedLocomotiveCostThreshold { .. }
|
||||
| RuntimeCondition::CargoProductionTotalThreshold { .. }
|
||||
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
|
||||
| RuntimeCondition::TerritoryAccessCostThreshold { .. }
|
||||
| RuntimeCondition::EconomicStatusCodeThreshold { .. }
|
||||
| RuntimeCondition::WorldFlagEquals { .. } => true,
|
||||
}
|
||||
|
|
@ -9431,6 +9540,224 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decodes_real_named_locomotive_availability_threshold_from_checked_in_metadata() {
|
||||
let condition_row = build_real_condition_row_with_threshold(
|
||||
REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID,
|
||||
4,
|
||||
42,
|
||||
Some("Big Boy"),
|
||||
);
|
||||
let record_body = build_real_event_record(
|
||||
[b"World", b"", b"", b"", b"", b""],
|
||||
Some(RealCompactControlSpec {
|
||||
mode_byte_0x7ef: 7,
|
||||
primary_selector_0x7f0: 0,
|
||||
grouped_mode_0x7f4: 2,
|
||||
one_shot_header_0x7f5: 0,
|
||||
modifier_flag_0x7f9: 0,
|
||||
modifier_flag_0x7fa: 0,
|
||||
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
|
||||
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
|
||||
summary_toggle_0x800: 1,
|
||||
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
|
||||
}),
|
||||
&[condition_row],
|
||||
[&[], &[], &[], &[]],
|
||||
);
|
||||
|
||||
let mut bytes = Vec::new();
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
|
||||
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
for word in header_words {
|
||||
bytes.extend_from_slice(&word.to_le_bytes());
|
||||
}
|
||||
bytes.extend_from_slice(&[0x00, 0x00]);
|
||||
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
|
||||
bytes.extend_from_slice(&record_body);
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
|
||||
|
||||
let report = inspect_smp_bytes(&bytes);
|
||||
let summary = report
|
||||
.event_runtime_collection_summary
|
||||
.as_ref()
|
||||
.expect("event runtime collection summary should parse");
|
||||
|
||||
assert_eq!(
|
||||
summary.records[0].standalone_condition_rows[0]
|
||||
.metric
|
||||
.as_deref(),
|
||||
Some("Named Locomotive Availability: Big Boy")
|
||||
);
|
||||
assert_eq!(
|
||||
summary.records[0].standalone_condition_rows[0]
|
||||
.semantic_family
|
||||
.as_deref(),
|
||||
Some("world_scalar_threshold")
|
||||
);
|
||||
assert_eq!(
|
||||
summary.records[0].decoded_conditions,
|
||||
vec![RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
|
||||
name: "Big Boy".to_string(),
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 42,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decodes_real_named_locomotive_cost_threshold_from_checked_in_metadata() {
|
||||
let condition_row = build_real_condition_row_with_threshold(
|
||||
REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID,
|
||||
0,
|
||||
250000,
|
||||
Some("Locomotive 1"),
|
||||
);
|
||||
let record_body = build_real_event_record(
|
||||
[b"World", b"", b"", b"", b"", b""],
|
||||
Some(RealCompactControlSpec {
|
||||
mode_byte_0x7ef: 7,
|
||||
primary_selector_0x7f0: 0,
|
||||
grouped_mode_0x7f4: 2,
|
||||
one_shot_header_0x7f5: 0,
|
||||
modifier_flag_0x7f9: 0,
|
||||
modifier_flag_0x7fa: 0,
|
||||
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
|
||||
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
|
||||
summary_toggle_0x800: 1,
|
||||
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
|
||||
}),
|
||||
&[condition_row],
|
||||
[&[], &[], &[], &[]],
|
||||
);
|
||||
|
||||
let mut bytes = Vec::new();
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
|
||||
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
for word in header_words {
|
||||
bytes.extend_from_slice(&word.to_le_bytes());
|
||||
}
|
||||
bytes.extend_from_slice(&[0x00, 0x00]);
|
||||
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
|
||||
bytes.extend_from_slice(&record_body);
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
|
||||
|
||||
let report = inspect_smp_bytes(&bytes);
|
||||
let summary = report
|
||||
.event_runtime_collection_summary
|
||||
.as_ref()
|
||||
.expect("event runtime collection summary should parse");
|
||||
|
||||
assert_eq!(
|
||||
summary.records[0].standalone_condition_rows[0]
|
||||
.metric
|
||||
.as_deref(),
|
||||
Some("Named Locomotive Cost: Locomotive 1")
|
||||
);
|
||||
assert_eq!(
|
||||
summary.records[0].decoded_conditions,
|
||||
vec![RuntimeCondition::NamedLocomotiveCostThreshold {
|
||||
name: "Locomotive 1".to_string(),
|
||||
comparator: RuntimeConditionComparator::Ge,
|
||||
value: 250000,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decodes_real_world_scalar_thresholds_from_checked_in_metadata() {
|
||||
let condition_rows = vec![
|
||||
build_real_condition_row_with_threshold(
|
||||
REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID,
|
||||
0,
|
||||
200,
|
||||
None,
|
||||
),
|
||||
build_real_condition_row_with_threshold(
|
||||
REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID,
|
||||
4,
|
||||
18,
|
||||
None,
|
||||
),
|
||||
build_real_condition_row_with_threshold(
|
||||
REAL_TERRITORY_ACCESS_COST_CONDITION_ID,
|
||||
4,
|
||||
750000,
|
||||
None,
|
||||
),
|
||||
];
|
||||
let record_body = build_real_event_record(
|
||||
[b"World", b"", b"", b"", b"", b""],
|
||||
Some(RealCompactControlSpec {
|
||||
mode_byte_0x7ef: 7,
|
||||
primary_selector_0x7f0: 0,
|
||||
grouped_mode_0x7f4: 2,
|
||||
one_shot_header_0x7f5: 0,
|
||||
modifier_flag_0x7f9: 0,
|
||||
modifier_flag_0x7fa: 0,
|
||||
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
|
||||
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
|
||||
summary_toggle_0x800: 1,
|
||||
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
|
||||
}),
|
||||
&condition_rows,
|
||||
[&[], &[], &[], &[]],
|
||||
);
|
||||
|
||||
let mut bytes = Vec::new();
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
|
||||
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
for word in header_words {
|
||||
bytes.extend_from_slice(&word.to_le_bytes());
|
||||
}
|
||||
bytes.extend_from_slice(&[0x00, 0x00]);
|
||||
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
|
||||
bytes.extend_from_slice(&record_body);
|
||||
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
|
||||
|
||||
let report = inspect_smp_bytes(&bytes);
|
||||
let summary = report
|
||||
.event_runtime_collection_summary
|
||||
.as_ref()
|
||||
.expect("event runtime collection summary should parse");
|
||||
|
||||
assert_eq!(
|
||||
summary.records[0].standalone_condition_rows[0]
|
||||
.metric
|
||||
.as_deref(),
|
||||
Some("Cargo Production Total")
|
||||
);
|
||||
assert_eq!(
|
||||
summary.records[0].standalone_condition_rows[0]
|
||||
.semantic_family
|
||||
.as_deref(),
|
||||
Some("world_scalar_threshold")
|
||||
);
|
||||
assert_eq!(
|
||||
summary.records[0].decoded_conditions,
|
||||
vec![
|
||||
RuntimeCondition::CargoProductionTotalThreshold {
|
||||
comparator: RuntimeConditionComparator::Ge,
|
||||
value: 200,
|
||||
},
|
||||
RuntimeCondition::LimitedTrackBuildingAmountThreshold {
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 18,
|
||||
},
|
||||
RuntimeCondition::TerritoryAccessCostThreshold {
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 750000,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decodes_real_world_flag_condition_from_checked_in_world_condition_metadata() {
|
||||
let condition_row = build_real_condition_row_with_threshold(2535, 4, 1, None);
|
||||
|
|
@ -9492,6 +9819,31 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn looks_up_checked_in_world_scalar_condition_metadata() {
|
||||
let availability =
|
||||
real_ordinary_condition_metadata(REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID)
|
||||
.expect("availability condition metadata should exist");
|
||||
assert_eq!(availability.label, "Unknown Loco Available");
|
||||
|
||||
let cost = real_ordinary_condition_metadata(REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID)
|
||||
.expect("cost condition metadata should exist");
|
||||
assert_eq!(cost.label, "Unknown Loco Cost");
|
||||
|
||||
let cargo = real_ordinary_condition_metadata(REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID)
|
||||
.expect("cargo condition metadata should exist");
|
||||
assert_eq!(cargo.label, "All Cargo Production");
|
||||
|
||||
let build_limit =
|
||||
real_ordinary_condition_metadata(REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID)
|
||||
.expect("build-limit condition metadata should exist");
|
||||
assert_eq!(build_limit.label, "Limited Track Building Amount");
|
||||
|
||||
let access_cost = real_ordinary_condition_metadata(REAL_TERRITORY_ACCESS_COST_CONDITION_ID)
|
||||
.expect("territory-access-cost condition metadata should exist");
|
||||
assert_eq!(access_cost.label, "Access Rights Cost:");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn looks_up_checked_in_world_flag_descriptor_metadata() {
|
||||
let metadata =
|
||||
|
|
|
|||
|
|
@ -722,6 +722,67 @@ fn evaluate_record_conditions(
|
|||
return Ok(None);
|
||||
}
|
||||
}
|
||||
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
|
||||
name,
|
||||
comparator,
|
||||
value,
|
||||
} => {
|
||||
let actual = state
|
||||
.named_locomotive_availability
|
||||
.get(name)
|
||||
.copied()
|
||||
.map(i64::from)
|
||||
.unwrap_or(0);
|
||||
if !compare_condition_value(actual, *comparator, *value) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
RuntimeCondition::NamedLocomotiveCostThreshold {
|
||||
name,
|
||||
comparator,
|
||||
value,
|
||||
} => {
|
||||
let actual = state
|
||||
.named_locomotive_cost
|
||||
.get(name)
|
||||
.copied()
|
||||
.map(i64::from)
|
||||
.unwrap_or(0);
|
||||
if !compare_condition_value(actual, *comparator, *value) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
RuntimeCondition::CargoProductionTotalThreshold { comparator, value } => {
|
||||
let actual = state
|
||||
.cargo_production_overrides
|
||||
.values()
|
||||
.copied()
|
||||
.map(i64::from)
|
||||
.sum::<i64>();
|
||||
if !compare_condition_value(actual, *comparator, *value) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
RuntimeCondition::LimitedTrackBuildingAmountThreshold { comparator, value } => {
|
||||
let actual = state
|
||||
.world_restore
|
||||
.limited_track_building_amount
|
||||
.map(i64::from)
|
||||
.unwrap_or(0);
|
||||
if !compare_condition_value(actual, *comparator, *value) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
RuntimeCondition::TerritoryAccessCostThreshold { comparator, value } => {
|
||||
let actual = state
|
||||
.world_restore
|
||||
.territory_access_cost
|
||||
.map(i64::from)
|
||||
.unwrap_or(0);
|
||||
if !compare_condition_value(actual, *comparator, *value) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
RuntimeCondition::EconomicStatusCodeThreshold { comparator, value } => {
|
||||
let actual = state
|
||||
.world_restore
|
||||
|
|
@ -2142,6 +2203,91 @@ mod tests {
|
|||
assert_eq!(state.world_flags.get("world_condition_failed"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn evaluates_world_scalar_conditions_before_effects_run() {
|
||||
let mut state = RuntimeState {
|
||||
world_restore: RuntimeWorldRestoreState {
|
||||
limited_track_building_amount: Some(18),
|
||||
territory_access_cost: Some(750000),
|
||||
..RuntimeWorldRestoreState::default()
|
||||
},
|
||||
named_locomotive_availability: BTreeMap::from([(String::from("Big Boy"), 42)]),
|
||||
named_locomotive_cost: BTreeMap::from([(String::from("GP7"), 175000)]),
|
||||
cargo_production_overrides: BTreeMap::from([(1, 125), (2, 75)]),
|
||||
event_runtime_records: vec![
|
||||
RuntimeEventRecord {
|
||||
record_id: 25,
|
||||
trigger_kind: 7,
|
||||
active: true,
|
||||
service_count: 0,
|
||||
marks_collection_dirty: false,
|
||||
one_shot: false,
|
||||
has_fired: false,
|
||||
conditions: vec![
|
||||
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
|
||||
name: "Big Boy".to_string(),
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 42,
|
||||
},
|
||||
RuntimeCondition::NamedLocomotiveCostThreshold {
|
||||
name: "GP7".to_string(),
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 175000,
|
||||
},
|
||||
RuntimeCondition::CargoProductionTotalThreshold {
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 200,
|
||||
},
|
||||
RuntimeCondition::LimitedTrackBuildingAmountThreshold {
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 18,
|
||||
},
|
||||
RuntimeCondition::TerritoryAccessCostThreshold {
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 750000,
|
||||
},
|
||||
],
|
||||
effects: vec![RuntimeEffect::SetWorldFlag {
|
||||
key: "world_scalar_condition_passed".to_string(),
|
||||
value: true,
|
||||
}],
|
||||
},
|
||||
RuntimeEventRecord {
|
||||
record_id: 26,
|
||||
trigger_kind: 7,
|
||||
active: true,
|
||||
service_count: 0,
|
||||
marks_collection_dirty: false,
|
||||
one_shot: false,
|
||||
has_fired: false,
|
||||
conditions: vec![RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
|
||||
name: "Missing Loco".to_string(),
|
||||
comparator: RuntimeConditionComparator::Gt,
|
||||
value: 0,
|
||||
}],
|
||||
effects: vec![RuntimeEffect::SetWorldFlag {
|
||||
key: "world_scalar_condition_failed".to_string(),
|
||||
value: true,
|
||||
}],
|
||||
},
|
||||
],
|
||||
..state()
|
||||
};
|
||||
|
||||
let result = execute_step_command(
|
||||
&mut state,
|
||||
&StepCommand::ServiceTriggerKind { trigger_kind: 7 },
|
||||
)
|
||||
.expect("world-scalar conditions should evaluate successfully");
|
||||
|
||||
assert_eq!(result.service_events[0].serviced_record_ids, vec![25]);
|
||||
assert_eq!(
|
||||
state.world_flags.get("world_scalar_condition_passed"),
|
||||
Some(&true)
|
||||
);
|
||||
assert_eq!(state.world_flags.get("world_scalar_condition_failed"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_shot_record_only_fires_once() {
|
||||
let mut state = RuntimeState {
|
||||
|
|
|
|||
|
|
@ -138,6 +138,12 @@ The highest-value next passes are now:
|
|||
- 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_restore.territory_access_cost`
|
||||
- world-scalar ordinary-condition coverage now matches those runtime surfaces too: checked-in
|
||||
metadata lowers named locomotive availability, named locomotive cost, aggregate cargo
|
||||
production, limited-track-building-amount, and territory-access-cost rows into explicit runtime
|
||||
condition gates
|
||||
- the remaining world-scalar condition frontier is now narrow and explicit: unsupported families
|
||||
such as `All Factory Production` stay parity-only on `blocked_unmapped_world_condition`
|
||||
- keep in mind that the current local `.gms` corpus still exports with no packed event collection,
|
||||
so real descriptor mapping needs to stay plumbing-first until better captures exist
|
||||
- use `rrt-hook` primarily as optional capture or integration tooling, not as the first execution
|
||||
|
|
|
|||
|
|
@ -97,11 +97,18 @@ Implemented today:
|
|||
- the remaining recovered scalar world families now execute as well: cargo-production `230..240`
|
||||
rows lower into slot-indexed `cargo_production_overrides`, and territory-access-cost descriptor
|
||||
`453` lowers into `world_restore.territory_access_cost`
|
||||
- world-scalar ordinary-condition coverage now aligns with those runtime surfaces too: checked-in
|
||||
metadata lowers named locomotive availability, named locomotive cost, aggregate cargo
|
||||
production, limited-track-building-amount, and territory-access-cost rows into explicit runtime
|
||||
condition gates
|
||||
- the remaining world-side condition frontier is now narrower and more honest: unsupported scalar
|
||||
families such as `All Factory Production` stay visible on `blocked_unmapped_world_condition`
|
||||
instead of falling back to generic placeholder ids
|
||||
|
||||
That means the next implementation work is breadth, not bootstrap. The recommended next slice is
|
||||
broader real grouped-descriptor and ordinary condition-id coverage beyond the current access,
|
||||
whole-game toggle, train, player, numeric-threshold, named locomotive availability, named
|
||||
locomotive cost, and world scalar override batches.
|
||||
locomotive cost, world scalar override, and world-scalar condition batches.
|
||||
Richer runtime ownership should still be added only where a later descriptor or condition family
|
||||
needs more than the current event-owned roster.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"format_version": 1,
|
||||
"fixture_id": "packed-event-world-scalar-condition-parity-save-slice-fixture",
|
||||
"source": {
|
||||
"kind": "captured-runtime",
|
||||
"description": "Fixture pinning one remaining unmapped world-scalar ordinary-condition family after the grounded batch."
|
||||
},
|
||||
"state_save_slice_path": "packed-event-world-scalar-condition-parity-save-slice.json",
|
||||
"commands": [
|
||||
{
|
||||
"kind": "service_trigger_kind",
|
||||
"trigger_kind": 7
|
||||
}
|
||||
],
|
||||
"expected_summary": {
|
||||
"packed_event_collection_present": true,
|
||||
"packed_event_record_count": 1,
|
||||
"packed_event_decoded_record_count": 1,
|
||||
"packed_event_imported_runtime_record_count": 0,
|
||||
"packed_event_parity_only_record_count": 1,
|
||||
"packed_event_blocked_unmapped_world_descriptor_count": 1,
|
||||
"event_runtime_record_count": 0,
|
||||
"world_flag_count": 7,
|
||||
"total_event_record_service_count": 0,
|
||||
"total_trigger_dispatch_count": 1
|
||||
},
|
||||
"expected_state_fragment": {
|
||||
"packed_event_collection": {
|
||||
"records": [
|
||||
{
|
||||
"import_outcome": "blocked_unmapped_world_descriptor",
|
||||
"standalone_condition_rows": [
|
||||
{
|
||||
"raw_condition_id": 2419,
|
||||
"metric": "All Factory Production",
|
||||
"semantic_family": "world_scalar_threshold"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
{
|
||||
"format_version": 1,
|
||||
"save_slice_id": "packed-event-world-scalar-condition-parity-save-slice",
|
||||
"source": {
|
||||
"description": "Tracked save-slice document pinning one remaining unmapped world-scalar condition family after the grounded batch.",
|
||||
"original_save_filename": "captured-world-scalar-condition-parity.gms",
|
||||
"original_save_sha256": "world-scalar-condition-parity-sample-sha256",
|
||||
"notes": [
|
||||
"tracked as JSON save-slice document rather than raw .smp",
|
||||
"keeps the broader all-factory-production family parity-only until a stronger runtime landing surface is grounded"
|
||||
]
|
||||
},
|
||||
"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,
|
||||
"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": 31232,
|
||||
"records_tag_offset": 31488,
|
||||
"close_tag_offset": 31872,
|
||||
"packed_state_version": 1001,
|
||||
"packed_state_version_hex": "0x000003e9",
|
||||
"live_id_bound": 33,
|
||||
"live_record_count": 1,
|
||||
"live_entry_ids": [33],
|
||||
"decoded_record_count": 1,
|
||||
"imported_runtime_record_count": 0,
|
||||
"records": [
|
||||
{
|
||||
"record_index": 0,
|
||||
"live_entry_id": 33,
|
||||
"payload_offset": 31520,
|
||||
"payload_len": 152,
|
||||
"decode_status": "parity_only",
|
||||
"payload_family": "real_packed_v1",
|
||||
"trigger_kind": 7,
|
||||
"one_shot": false,
|
||||
"compact_control": {
|
||||
"mode_byte_0x7ef": 7,
|
||||
"primary_selector_0x7f0": 0,
|
||||
"grouped_mode_0x7f4": 2,
|
||||
"one_shot_header_0x7f5": 0,
|
||||
"modifier_flag_0x7f9": 0,
|
||||
"modifier_flag_0x7fa": 0,
|
||||
"grouped_target_scope_ordinals_0x7fb": [0, 0, 0, 0],
|
||||
"grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0],
|
||||
"summary_toggle_0x800": 1,
|
||||
"grouped_territory_selectors_0x80f": [-1, -1, -1, -1]
|
||||
},
|
||||
"text_bands": [],
|
||||
"standalone_condition_row_count": 1,
|
||||
"standalone_condition_rows": [
|
||||
{
|
||||
"row_index": 0,
|
||||
"raw_condition_id": 2419,
|
||||
"subtype": 4,
|
||||
"flag_bytes": [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
"candidate_name": null,
|
||||
"comparator": null,
|
||||
"metric": "All Factory Production",
|
||||
"semantic_family": "world_scalar_threshold",
|
||||
"semantic_preview": null,
|
||||
"requires_candidate_name_binding": false,
|
||||
"notes": [
|
||||
"checked-in RT3.lng label is known, but this world-scalar condition family is not yet lowered"
|
||||
]
|
||||
}
|
||||
],
|
||||
"negative_sentinel_scope": null,
|
||||
"grouped_effect_row_counts": [1, 0, 0, 0],
|
||||
"grouped_effect_rows": [
|
||||
{
|
||||
"group_index": 0,
|
||||
"row_index": 0,
|
||||
"descriptor_id": 110,
|
||||
"descriptor_label": "Disable Stock Buying and Selling",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "world_flag_toggle",
|
||||
"opcode": 0,
|
||||
"raw_scalar_value": 1,
|
||||
"value_byte_0x09": 0,
|
||||
"value_dword_0x0d": 0,
|
||||
"value_byte_0x11": 0,
|
||||
"value_byte_0x12": 0,
|
||||
"value_word_0x14": 0,
|
||||
"value_word_0x16": 0,
|
||||
"row_shape": "bool_toggle",
|
||||
"semantic_family": "bool_toggle",
|
||||
"semantic_preview": "Set Disable Stock Buying and Selling to TRUE",
|
||||
"recovered_locomotive_id": null,
|
||||
"locomotive_name": null,
|
||||
"notes": []
|
||||
}
|
||||
],
|
||||
"decoded_conditions": [],
|
||||
"decoded_actions": [
|
||||
{
|
||||
"kind": "set_world_flag",
|
||||
"key": "world.disable_stock_buying_and_selling",
|
||||
"value": true
|
||||
}
|
||||
],
|
||||
"executable_import_ready": false,
|
||||
"notes": [
|
||||
"unmapped world-scalar condition parity sample"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"notes": [
|
||||
"world-scalar condition parity sample"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
{
|
||||
"format_version": 1,
|
||||
"fixture_id": "packed-event-world-scalar-condition-save-slice-fixture",
|
||||
"source": {
|
||||
"kind": "captured-runtime",
|
||||
"description": "Fixture proving grounded world-scalar ordinary conditions gate an imported whole-game effect."
|
||||
},
|
||||
"state_save_slice_path": "packed-event-world-scalar-condition-save-slice.json",
|
||||
"commands": [
|
||||
{
|
||||
"kind": "service_trigger_kind",
|
||||
"trigger_kind": 6
|
||||
},
|
||||
{
|
||||
"kind": "service_trigger_kind",
|
||||
"trigger_kind": 7
|
||||
}
|
||||
],
|
||||
"expected_summary": {
|
||||
"packed_event_collection_present": true,
|
||||
"packed_event_record_count": 2,
|
||||
"packed_event_decoded_record_count": 2,
|
||||
"packed_event_imported_runtime_record_count": 2,
|
||||
"event_runtime_record_count": 2,
|
||||
"named_locomotive_availability_count": 1,
|
||||
"zero_named_locomotive_availability_count": 0,
|
||||
"named_locomotive_cost_count": 1,
|
||||
"cargo_production_override_count": 1,
|
||||
"world_restore_limited_track_building_amount": 18,
|
||||
"world_restore_territory_access_cost": 750000,
|
||||
"world_flag_count": 8,
|
||||
"total_event_record_service_count": 2,
|
||||
"total_trigger_dispatch_count": 2
|
||||
},
|
||||
"expected_state_fragment": {
|
||||
"world_flags": {
|
||||
"world.disable_stock_buying_and_selling": true
|
||||
},
|
||||
"world_restore": {
|
||||
"limited_track_building_amount": 18,
|
||||
"territory_access_cost": 750000
|
||||
},
|
||||
"named_locomotive_availability": {
|
||||
"Big Boy": 42
|
||||
},
|
||||
"named_locomotive_cost": {
|
||||
"Locomotive 1": 250000
|
||||
},
|
||||
"cargo_production_overrides": {
|
||||
"1": 125
|
||||
},
|
||||
"packed_event_collection": {
|
||||
"records": [
|
||||
{
|
||||
"import_outcome": "imported"
|
||||
},
|
||||
{
|
||||
"import_outcome": "imported",
|
||||
"decoded_conditions": [
|
||||
{
|
||||
"kind": "named_locomotive_availability_threshold",
|
||||
"name": "Big Boy",
|
||||
"comparator": "eq",
|
||||
"value": 42
|
||||
},
|
||||
{
|
||||
"kind": "named_locomotive_cost_threshold",
|
||||
"name": "Locomotive 1",
|
||||
"comparator": "eq",
|
||||
"value": 250000
|
||||
},
|
||||
{
|
||||
"kind": "cargo_production_total_threshold",
|
||||
"comparator": "eq",
|
||||
"value": 125
|
||||
},
|
||||
{
|
||||
"kind": "limited_track_building_amount_threshold",
|
||||
"comparator": "eq",
|
||||
"value": 18
|
||||
},
|
||||
{
|
||||
"kind": "territory_access_cost_threshold",
|
||||
"comparator": "eq",
|
||||
"value": 750000
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"event_runtime_records": [
|
||||
{
|
||||
"record_id": 41,
|
||||
"service_count": 1
|
||||
},
|
||||
{
|
||||
"record_id": 45,
|
||||
"service_count": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
{
|
||||
"format_version": 1,
|
||||
"save_slice_id": "packed-event-world-scalar-condition-save-slice",
|
||||
"source": {
|
||||
"description": "Tracked save-slice document proving grounded world-scalar ordinary conditions gate a whole-game effect.",
|
||||
"original_save_filename": "captured-world-scalar-condition.gms",
|
||||
"original_save_sha256": "world-scalar-condition-sample-sha256",
|
||||
"notes": [
|
||||
"tracked as JSON save-slice document rather than raw .smp",
|
||||
"uses checked-in RT3.lng condition ids for named locomotive availability, named locomotive cost, aggregate cargo production, limited track building amount, and access rights cost"
|
||||
]
|
||||
},
|
||||
"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,
|
||||
"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": 31488,
|
||||
"records_tag_offset": 31744,
|
||||
"close_tag_offset": 32768,
|
||||
"packed_state_version": 1001,
|
||||
"packed_state_version_hex": "0x000003e9",
|
||||
"live_id_bound": 45,
|
||||
"live_record_count": 2,
|
||||
"live_entry_ids": [41, 45],
|
||||
"decoded_record_count": 2,
|
||||
"imported_runtime_record_count": 2,
|
||||
"records": [
|
||||
{
|
||||
"record_index": 0,
|
||||
"live_entry_id": 41,
|
||||
"payload_offset": 31808,
|
||||
"payload_len": 272,
|
||||
"decode_status": "parity_only",
|
||||
"payload_family": "real_packed_v1",
|
||||
"trigger_kind": 6,
|
||||
"one_shot": false,
|
||||
"compact_control": {
|
||||
"mode_byte_0x7ef": 6,
|
||||
"primary_selector_0x7f0": 0,
|
||||
"grouped_mode_0x7f4": 2,
|
||||
"one_shot_header_0x7f5": 0,
|
||||
"modifier_flag_0x7f9": 0,
|
||||
"modifier_flag_0x7fa": 0,
|
||||
"grouped_target_scope_ordinals_0x7fb": [0, 0, 0, 0],
|
||||
"grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0],
|
||||
"summary_toggle_0x800": 1,
|
||||
"grouped_territory_selectors_0x80f": [-1, -1, -1, -1]
|
||||
},
|
||||
"text_bands": [],
|
||||
"standalone_condition_row_count": 0,
|
||||
"standalone_condition_rows": [],
|
||||
"negative_sentinel_scope": null,
|
||||
"grouped_effect_row_counts": [5, 0, 0, 0],
|
||||
"grouped_effect_rows": [
|
||||
{
|
||||
"group_index": 0,
|
||||
"row_index": 0,
|
||||
"descriptor_id": 250,
|
||||
"descriptor_label": "Unknown Loco Available",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "locomotive_availability_scalar",
|
||||
"opcode": 3,
|
||||
"raw_scalar_value": 42,
|
||||
"value_byte_0x09": 0,
|
||||
"value_dword_0x0d": 0,
|
||||
"value_byte_0x11": 0,
|
||||
"value_byte_0x12": 0,
|
||||
"value_word_0x14": 0,
|
||||
"value_word_0x16": 0,
|
||||
"row_shape": "scalar_assignment",
|
||||
"semantic_family": "scalar_assignment",
|
||||
"semantic_preview": "Set Unknown Loco Available to 42",
|
||||
"recovered_locomotive_id": 10,
|
||||
"locomotive_name": null,
|
||||
"notes": [
|
||||
"locomotive availability descriptor maps to live locomotive id 10"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group_index": 0,
|
||||
"row_index": 1,
|
||||
"descriptor_id": 352,
|
||||
"descriptor_label": "Locomotive 1 Cost",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "locomotive_cost_scalar",
|
||||
"opcode": 3,
|
||||
"raw_scalar_value": 250000,
|
||||
"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 Locomotive 1 Cost to 250000",
|
||||
"recovered_locomotive_id": 1,
|
||||
"locomotive_name": null,
|
||||
"notes": [
|
||||
"locomotive cost descriptor maps to live locomotive id 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group_index": 0,
|
||||
"row_index": 2,
|
||||
"descriptor_id": 230,
|
||||
"descriptor_label": "Cargo Production Slot 1",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "cargo_production_scalar",
|
||||
"opcode": 3,
|
||||
"raw_scalar_value": 125,
|
||||
"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 Cargo Production Slot 1 to 125",
|
||||
"recovered_locomotive_id": null,
|
||||
"locomotive_name": null,
|
||||
"notes": []
|
||||
},
|
||||
{
|
||||
"group_index": 0,
|
||||
"row_index": 3,
|
||||
"descriptor_id": 122,
|
||||
"descriptor_label": "Limited Track Building Amount",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "world_track_build_limit_scalar",
|
||||
"opcode": 3,
|
||||
"raw_scalar_value": 18,
|
||||
"value_byte_0x09": 0,
|
||||
"value_dword_0x0d": 0,
|
||||
"value_byte_0x11": 0,
|
||||
"value_byte_0x12": 0,
|
||||
"value_word_0x14": 0,
|
||||
"value_word_0x16": 0,
|
||||
"row_shape": "scalar_assignment",
|
||||
"semantic_family": "scalar_assignment",
|
||||
"semantic_preview": "Set Limited Track Building Amount to 18",
|
||||
"recovered_locomotive_id": null,
|
||||
"locomotive_name": null,
|
||||
"notes": []
|
||||
},
|
||||
{
|
||||
"group_index": 0,
|
||||
"row_index": 4,
|
||||
"descriptor_id": 453,
|
||||
"descriptor_label": "Territory Access Cost",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "territory_access_cost_scalar",
|
||||
"opcode": 3,
|
||||
"raw_scalar_value": 750000,
|
||||
"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 Access Cost to 750000",
|
||||
"recovered_locomotive_id": null,
|
||||
"locomotive_name": null,
|
||||
"notes": []
|
||||
}
|
||||
],
|
||||
"decoded_conditions": [],
|
||||
"decoded_actions": [
|
||||
{
|
||||
"kind": "set_named_locomotive_availability_value",
|
||||
"name": "Big Boy",
|
||||
"value": 42
|
||||
},
|
||||
{
|
||||
"kind": "set_named_locomotive_cost",
|
||||
"name": "Locomotive 1",
|
||||
"value": 250000
|
||||
},
|
||||
{
|
||||
"kind": "set_cargo_production_slot",
|
||||
"slot": 1,
|
||||
"value": 125
|
||||
},
|
||||
{
|
||||
"kind": "set_limited_track_building_amount",
|
||||
"value": 18
|
||||
},
|
||||
{
|
||||
"kind": "set_territory_access_cost",
|
||||
"value": 750000
|
||||
}
|
||||
],
|
||||
"executable_import_ready": true,
|
||||
"notes": [
|
||||
"world-scalar setup record"
|
||||
]
|
||||
},
|
||||
{
|
||||
"record_index": 1,
|
||||
"live_entry_id": 45,
|
||||
"payload_offset": 32128,
|
||||
"payload_len": 224,
|
||||
"decode_status": "parity_only",
|
||||
"payload_family": "real_packed_v1",
|
||||
"trigger_kind": 7,
|
||||
"one_shot": false,
|
||||
"compact_control": {
|
||||
"mode_byte_0x7ef": 7,
|
||||
"primary_selector_0x7f0": 0,
|
||||
"grouped_mode_0x7f4": 2,
|
||||
"one_shot_header_0x7f5": 0,
|
||||
"modifier_flag_0x7f9": 0,
|
||||
"modifier_flag_0x7fa": 0,
|
||||
"grouped_target_scope_ordinals_0x7fb": [0, 0, 0, 0],
|
||||
"grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0],
|
||||
"summary_toggle_0x800": 1,
|
||||
"grouped_territory_selectors_0x80f": [-1, -1, -1, -1]
|
||||
},
|
||||
"text_bands": [],
|
||||
"standalone_condition_row_count": 5,
|
||||
"standalone_condition_rows": [
|
||||
{
|
||||
"row_index": 0,
|
||||
"raw_condition_id": 2422,
|
||||
"subtype": 4,
|
||||
"flag_bytes": [42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
"candidate_name": "Big Boy",
|
||||
"comparator": "eq",
|
||||
"metric": "Named Locomotive Availability: Big Boy",
|
||||
"semantic_family": "world_scalar_threshold",
|
||||
"semantic_preview": "Test Named Locomotive Availability: Big Boy == 42",
|
||||
"requires_candidate_name_binding": false,
|
||||
"notes": [
|
||||
"checked-in world-scalar condition metadata sample"
|
||||
]
|
||||
},
|
||||
{
|
||||
"row_index": 1,
|
||||
"raw_condition_id": 2423,
|
||||
"subtype": 4,
|
||||
"flag_bytes": [144, 208, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
"candidate_name": "Locomotive 1",
|
||||
"comparator": "eq",
|
||||
"metric": "Named Locomotive Cost: Locomotive 1",
|
||||
"semantic_family": "world_scalar_threshold",
|
||||
"semantic_preview": "Test Named Locomotive Cost: Locomotive 1 == 250000",
|
||||
"requires_candidate_name_binding": false,
|
||||
"notes": [
|
||||
"checked-in world-scalar condition metadata sample"
|
||||
]
|
||||
},
|
||||
{
|
||||
"row_index": 2,
|
||||
"raw_condition_id": 2418,
|
||||
"subtype": 4,
|
||||
"flag_bytes": [125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
"candidate_name": null,
|
||||
"comparator": "eq",
|
||||
"metric": "Cargo Production Total",
|
||||
"semantic_family": "world_scalar_threshold",
|
||||
"semantic_preview": "Test Cargo Production Total == 125",
|
||||
"requires_candidate_name_binding": false,
|
||||
"notes": [
|
||||
"checked-in world-scalar condition metadata sample"
|
||||
]
|
||||
},
|
||||
{
|
||||
"row_index": 3,
|
||||
"raw_condition_id": 2547,
|
||||
"subtype": 4,
|
||||
"flag_bytes": [18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
"candidate_name": null,
|
||||
"comparator": "eq",
|
||||
"metric": "Limited Track Building Amount",
|
||||
"semantic_family": "world_scalar_threshold",
|
||||
"semantic_preview": "Test Limited Track Building Amount == 18",
|
||||
"requires_candidate_name_binding": false,
|
||||
"notes": [
|
||||
"checked-in world-scalar condition metadata sample"
|
||||
]
|
||||
},
|
||||
{
|
||||
"row_index": 4,
|
||||
"raw_condition_id": 1516,
|
||||
"subtype": 4,
|
||||
"flag_bytes": [176, 113, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
"candidate_name": null,
|
||||
"comparator": "eq",
|
||||
"metric": "Territory Access Cost",
|
||||
"semantic_family": "world_scalar_threshold",
|
||||
"semantic_preview": "Test Territory Access Cost == 750000",
|
||||
"requires_candidate_name_binding": false,
|
||||
"notes": [
|
||||
"checked-in world-scalar condition metadata sample"
|
||||
]
|
||||
}
|
||||
],
|
||||
"negative_sentinel_scope": null,
|
||||
"grouped_effect_row_counts": [1, 0, 0, 0],
|
||||
"grouped_effect_rows": [
|
||||
{
|
||||
"group_index": 0,
|
||||
"row_index": 0,
|
||||
"descriptor_id": 110,
|
||||
"descriptor_label": "Disable Stock Buying and Selling",
|
||||
"target_mask_bits": 8,
|
||||
"parameter_family": "world_flag_toggle",
|
||||
"opcode": 0,
|
||||
"raw_scalar_value": 1,
|
||||
"value_byte_0x09": 0,
|
||||
"value_dword_0x0d": 0,
|
||||
"value_byte_0x11": 0,
|
||||
"value_byte_0x12": 0,
|
||||
"value_word_0x14": 0,
|
||||
"value_word_0x16": 0,
|
||||
"row_shape": "bool_toggle",
|
||||
"semantic_family": "bool_toggle",
|
||||
"semantic_preview": "Set Disable Stock Buying and Selling to TRUE",
|
||||
"recovered_locomotive_id": null,
|
||||
"locomotive_name": null,
|
||||
"notes": []
|
||||
}
|
||||
],
|
||||
"decoded_conditions": [
|
||||
{
|
||||
"kind": "named_locomotive_availability_threshold",
|
||||
"name": "Big Boy",
|
||||
"comparator": "eq",
|
||||
"value": 42
|
||||
},
|
||||
{
|
||||
"kind": "named_locomotive_cost_threshold",
|
||||
"name": "Locomotive 1",
|
||||
"comparator": "eq",
|
||||
"value": 250000
|
||||
},
|
||||
{
|
||||
"kind": "cargo_production_total_threshold",
|
||||
"comparator": "eq",
|
||||
"value": 125
|
||||
},
|
||||
{
|
||||
"kind": "limited_track_building_amount_threshold",
|
||||
"comparator": "eq",
|
||||
"value": 18
|
||||
},
|
||||
{
|
||||
"kind": "territory_access_cost_threshold",
|
||||
"comparator": "eq",
|
||||
"value": 750000
|
||||
}
|
||||
],
|
||||
"decoded_actions": [
|
||||
{
|
||||
"kind": "set_world_flag",
|
||||
"key": "world.disable_stock_buying_and_selling",
|
||||
"value": true
|
||||
}
|
||||
],
|
||||
"executable_import_ready": true,
|
||||
"notes": [
|
||||
"world-scalar conditions gate a whole-game effect"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"notes": [
|
||||
"world-scalar condition executable sample"
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue