diff --git a/schema/randomprime.schema.json b/schema/randomprime.schema.json index 3d88506e..74419d8e 100644 --- a/schema/randomprime.schema.json +++ b/schema/randomprime.schema.json @@ -3162,11 +3162,11 @@ } }, "fog": { - "description": "Edit the ambient fog settings for this room.", + "description": "Edit the ambient fog settings for this room. Use \"distanceFogs\" if you need a more specific use case.", "type": "object", "properties": { "mode": { - "description": "[Deprecated]", + "description": "[Deprecated] Fog is always mode=1", "type": "integer", "minimum": 0, "maximum": 15, @@ -3174,8 +3174,9 @@ "deprecated": true }, "explicit": { + "description": "[Deprecated] There is no need to set this", "type": "boolean", - "default": true + "deprecated": true }, "color": { "description": "RGBA fog color for this room.", @@ -4262,6 +4263,87 @@ ], "additionalProperties": false } + }, + "distanceFogs": { + "description": "Add/modify distanceFog objects to this room. If you just want to set the global ambient fog level for this room, see \"fog\".", + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "$ref": "#/$defs/addModifyId" + }, + "layer": { + "$ref": "#/$defs/addModifyLayer" + }, + "active": { + "description": "Default active state of the distanceFog object.", + "type": "boolean", + "default": true + }, + "mode": { + "description": "[Deprecated] Fog is always mode=1", + "type": "integer", + "minimum": 0, + "maximum": 15, + "default": 1, + "deprecated": true + }, + "explicit": { + "description": "If true, this fog is applied as ambient fog without the need to send it an ACTION message.", + "type": "boolean" + }, + "color": { + "description": "RGBA fog color for this room.", + "type": "array", + "items": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0 + }, + "minItems": 4, + "maxItems": 4, + "default": [ + 0.8, + 0.8, + 0.9, + 0.0 + ] + }, + "range": { + "description": "X and Y axis ranges for the fog of this room.", + "type": "array", + "items": { + "type": "number", + "exclusiveMinimum": 0.0 + }, + "minItems": 2, + "maxItems": 2, + "default": [ + 30.0, + 40.0 + ] + }, + "colorDelta": { + "type": "number", + "default": 0.0 + }, + "rangeDelta": { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 2, + "maxItems": 2, + "default": [ + 0.0, + 0.0 + ] + } + }, + "required": [], + "additionalProperties": false + } } }, "additionalProperties": false diff --git a/src/add_modify_obj_patches.rs b/src/add_modify_obj_patches.rs index d70d5340..455551ff 100644 --- a/src/add_modify_obj_patches.rs +++ b/src/add_modify_obj_patches.rs @@ -32,6 +32,7 @@ use crate::{ CounterConfig, SwitchConfig, PlayerHintConfig, + FogConfig, }, pickup_meta::PickupType, door_meta::DoorType, @@ -801,6 +802,45 @@ pub fn patch_add_player_hint<'r>( add_edit_obj_helper!(area, Some(config.id), config.layer, PlayerHint, new, update); } + +pub fn patch_add_distance_fogs<'r>( + _ps: &mut PatcherState, + area: &mut mlvl_wrapper::MlvlArea, + config: FogConfig, +) + -> Result<(), String> +{ + macro_rules! new { + () => { + structs::DistanceFog { + name: b"my fog\0".as_cstr(), + mode: config.mode.unwrap_or(1), + color: config.color.unwrap_or([0.8, 0.8, 0.9, 0.0]).into(), + range: config.range.unwrap_or([30.0, 40.0]).into(), + color_delta: config.color_delta.unwrap_or(0.0), + range_delta: config.range_delta.unwrap_or([0.0, 0.0]).into(), + explicit: config.explicit.unwrap_or(true) as u8, + active: config.active.unwrap_or(true) as u8, + } + }; + } + + macro_rules! update { + ($obj:expr) => { + let property_data = $obj.property_data.as_distance_fog_mut().unwrap(); + if let Some(mode ) = config.mode {property_data.mode = mode } + if let Some(color ) = config.color {property_data.color = color .into() } + if let Some(range ) = config.range {property_data.range = range .into() } + if let Some(color_delta ) = config.color_delta {property_data.color_delta = color_delta } + if let Some(range_delta ) = config.range_delta {property_data.range_delta = range_delta.into() } + if let Some(explicit ) = config.explicit {property_data.explicit = explicit as u8 } + if let Some(active ) = config.active {property_data.active = active as u8 } + }; + } + + add_edit_obj_helper!(area, config.id, config.layer, DistanceFog, new, update); +} + pub fn patch_add_platform<'r>( _ps: &mut PatcherState, area: &mut mlvl_wrapper::MlvlArea<'r, '_, '_, '_>, diff --git a/src/patch_config.rs b/src/patch_config.rs index df7bbe64..81ed4816 100644 --- a/src/patch_config.rs +++ b/src/patch_config.rs @@ -559,6 +559,9 @@ pub struct EditObjConfig #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct FogConfig { + pub id: Option, + pub layer: Option, + pub active: Option, pub mode: Option, pub explicit: Option, pub color: Option<[f32;4]>, // RGBA @@ -867,6 +870,7 @@ pub struct RoomConfig pub counters: Option>, pub switches: Option>, pub player_hints: Option>, + pub distance_fogs: Option>, // Don't forget to update merge_json when adding here } @@ -1698,6 +1702,7 @@ impl PatchConfigPrivate extend_option_vec!(counters , self_room_config, other_room_config); extend_option_vec!(switches , self_room_config, other_room_config); extend_option_vec!(player_hints , self_room_config, other_room_config); + extend_option_vec!(distance_fogs , self_room_config, other_room_config); if let Some(other_layers) = &other_room_config.layers { if self_room_config.layers.is_none() { diff --git a/src/patches.rs b/src/patches.rs index ba80db10..f6800468 100644 --- a/src/patches.rs +++ b/src/patches.rs @@ -5615,18 +5615,22 @@ fn patch_edit_fog<'r>( if distance_fog.is_none() { continue; } + let distance_fog = distance_fog.unwrap(); + if distance_fog.explicit == 0 || distance_fog.active == 0 { + continue; // This isn't generic ambient fog, it's specific fog + } distance_fog.mode = fog.mode.unwrap_or(1); let color = fog.color.unwrap_or([0.8, 0.8, 0.9, 0.0]); distance_fog.color = color.into(); + let range = fog.range.unwrap_or([30.0, 40.0]); distance_fog.range = range.into(); + distance_fog.color_delta = fog.color_delta.unwrap_or(0.0); distance_fog.range_delta = range_delta.into(); - distance_fog.explicit = fog.explicit.unwrap_or(true) as u8; - distance_fog.active = 1; found = true; } @@ -5645,7 +5649,7 @@ fn patch_edit_fog<'r>( range: fog.range.unwrap_or([30.0, 40.0]).into(), color_delta: fog.color_delta.unwrap_or(0.0), range_delta: range_delta.into(), - explicit: fog.explicit.unwrap_or(true) as u8, + explicit: 1, // explicit means it's "ambient" (i.e. it doesn't require an ACTION message) active: 1, }.into(), connections: vec![].into(), @@ -15431,6 +15435,20 @@ fn build_and_run_patches<'r>(gc_disc: &mut structs::GcDisc<'r>, config: &PatchCo } } + + if let Some(distance_fogs) = room.distance_fogs.as_ref() { + for config in distance_fogs { + patcher.add_scly_patch( + (pak_name.as_bytes(), room_info.room_id.to_u32()), + move |ps, area| patch_add_distance_fogs( + ps, + area, + config.clone(), + ), + ); + } + } + if room.streamed_audios.is_some() { for config in room.streamed_audios.as_ref().unwrap() { patcher.add_scly_patch(