From 144c46cdecc34a71b9e17f6c93e0e94d2513a539 Mon Sep 17 00:00:00 2001 From: Wuffindy Date: Tue, 28 Jul 2026 10:11:37 +0700 Subject: [PATCH 01/14] Revert "Give expeds more budget to work with (#1555)" This reverts commit 56551ce9a7d4b159f9623bd297cc14ebd73bd568. un mono exped 1 --- Content.Server/Salvage/SpawnSalvageMissionJob.cs | 1 + Content.Shared/Salvage/SharedSalvageSystem.cs | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index 5b7bc5913ce..bf66d3854b6 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -14,6 +14,7 @@ using Content.Server.Salvage.Expeditions.Structure; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Systems; +using Content.Server.Spawners.Components; using Content.Server.Station.Components; using Content.Server.Station.Systems; using Content.Shared.Atmos; diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 5c1790945c2..1719dad7499 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -58,15 +58,15 @@ public int GetDifficulty(DifficultyRating rating) switch (rating) { case DifficultyRating.Minimal: - return 8; + return 4; case DifficultyRating.Minor: - return 12; + return 6; case DifficultyRating.Moderate: - return 16; + return 8; case DifficultyRating.Hazardous: - return 20; + return 10; case DifficultyRating.Extreme: - return 30; + return 12; default: throw new ArgumentOutOfRangeException(nameof(rating), rating, null); } From e3999137894305e74edf99ff5725f59ef64a5c1a Mon Sep 17 00:00:00 2001 From: Wuffindy Date: Tue, 28 Jul 2026 10:18:27 +0700 Subject: [PATCH 02/14] Revert "Expedition Weather (#1482)" This reverts commit d707d555e899f3be603824472ce7d5d585160d07. revert mono's weather system --- .../Salvage/SalvageSystem.Expeditions.cs | 3 - Content.Server/Salvage/SalvageSystem.cs | 3 - .../Salvage/SpawnSalvageMissionJob.cs | 16 +-- .../Salvage/Expeditions/SalvageExpeditions.cs | 6 - Content.Shared/Salvage/SharedSalvageSystem.cs | 9 +- .../en-US/_NF/procedural/expeditions.ftl | 14 +-- .../Prototypes/Procedural/salvage_mods.yml | 6 +- Resources/Prototypes/Tiles/floors.yml | 1 - .../_NF/Procedural/salvage_mods.yml | 108 +----------------- 9 files changed, 8 insertions(+), 158 deletions(-) diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs index 170aa9d4c62..9af7ada60f3 100644 --- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs +++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs @@ -20,8 +20,6 @@ using Content.Shared.Procedural; using Content.Shared.Salvage; using Robust.Shared.GameStates; -using Content.Server.Weather; -using Content.Shared.Weather; using Robust.Shared.Random; using Robust.Shared.Map; using Content.Shared.Shuttles.Components; // Frontier @@ -323,7 +321,6 @@ private void SpawnMission(SalvageMissionParams missionParams, EntityUid station, _prototypeManager, _anchorable, _biome, - _weather, _dungeon, _shuttle, _station, diff --git a/Content.Server/Salvage/SalvageSystem.cs b/Content.Server/Salvage/SalvageSystem.cs index 2f691df59e2..f478723fd86 100644 --- a/Content.Server/Salvage/SalvageSystem.cs +++ b/Content.Server/Salvage/SalvageSystem.cs @@ -17,8 +17,6 @@ using Robust.Shared.Map.Components; using Robust.Shared.Timing; using Robust.Shared.EntitySerialization.Systems; -using Content.Server.Weather; -using Content.Shared.Weather; namespace Content.Server.Salvage { @@ -31,7 +29,6 @@ public sealed partial class SalvageSystem : SharedSalvageSystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly AnchorableSystem _anchorable = default!; [Dependency] private readonly BiomeSystem _biome = default!; - [Dependency] private readonly WeatherSystem _weather = default!; [Dependency] private readonly DungeonSystem _dungeon = default!; [Dependency] private readonly GravitySystem _gravity = default!; [Dependency] private readonly MapLoaderSystem _loader = default!; diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index bf66d3854b6..8d56072d2ef 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -14,7 +14,6 @@ using Content.Server.Salvage.Expeditions.Structure; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Systems; -using Content.Server.Spawners.Components; using Content.Server.Station.Components; using Content.Server.Station.Systems; using Content.Shared.Atmos; @@ -30,8 +29,6 @@ using Content.Shared.Salvage.Expeditions.Modifiers; using Content.Shared.Shuttles.Components; using Content.Shared.Storage; -using Content.Server.Weather; -using Content.Shared.Weather; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; @@ -51,7 +48,6 @@ public sealed class SpawnSalvageMissionJob : Job private readonly IPrototypeManager _prototypeManager; private readonly AnchorableSystem _anchorable; private readonly BiomeSystem _biome; - private readonly WeatherSystem _weather; private readonly DungeonSystem _dungeon; private readonly MetaDataSystem _metaData; private readonly ShuttleSystem _shuttle; @@ -85,7 +81,6 @@ public SpawnSalvageMissionJob( IPrototypeManager protoManager, AnchorableSystem anchorable, BiomeSystem biome, - WeatherSystem weather, DungeonSystem dungeon, ShuttleSystem shuttle, StationSystem stationSystem, @@ -104,7 +99,6 @@ public SpawnSalvageMissionJob( _prototypeManager = protoManager; _anchorable = anchorable; _biome = biome; - _weather = weather; _dungeon = dungeon; _shuttle = shuttle; _stationSystem = stationSystem; @@ -176,8 +170,7 @@ private async Task InternalProcess() // Frontier: make process an internal var mission = _entManager.System() .GetMission(_missionParams.MissionType, _missionParams.Difficulty, _missionParams.Seed); - var missionWeather = _prototypeManager.Index(mission.Weather); - var missionBiome = _prototypeManager.Index(mission.Biome); + var missionBiome = _prototypeManager.Index(mission.Biome); BiomeComponent? biome = null; if (missionBiome.BiomePrototype != null) @@ -202,13 +195,6 @@ private async Task InternalProcess() // Frontier: make process an internal _entManager.System().SetMapSpace(mapUid, air.Space, atmos); _entManager.System().SetMapGasMixture(mapUid, new GasMixture(moles, mission.Temperature), atmos); - if (!air.Space) - { - var weather = _entManager.EnsureComponent(mapUid); - _entManager.System().SetWeather(mapId, _prototypeManager.Index(missionWeather.WeatherPrototype), null); - _entManager.Dirty(mapUid, weather); - } - if (mission.Color != null) { var lighting = _entManager.EnsureComponent(mapUid); diff --git a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs index 156082e41cc..c1a2053b26f 100644 --- a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs +++ b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs @@ -137,7 +137,6 @@ public sealed record SalvageMission( string Faction, SalvageMissionType Mission, string Biome, - string Weather, string Air, float Temperature, Color? Color, @@ -175,11 +174,6 @@ public sealed record SalvageMission( /// public readonly string Biome = Biome; - /// - /// Weather to be used for the mission's planet. - /// - public readonly string Weather = Weather; - /// /// Air mixture to be used for the mission's planet. /// diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 1719dad7499..85b4b999e67 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -118,13 +118,6 @@ public SalvageMission GetMission(SalvageMissionType config, DifficultyRating dif mods.Add(Loc.GetString(temp.Description)); } - // only show the description if there is an atmosphere since wont matter otherwise - var weather = GetBiomeMod(biome.ID, rand, ref rating); - if (weather.Description != string.Empty && !air.Space) - { - mods.Add(Loc.GetString(weather.Description)); - } - var light = GetBiomeMod(biome.ID, rand, ref rating); if (light.Description != string.Empty) { @@ -143,7 +136,7 @@ public SalvageMission GetMission(SalvageMissionType config, DifficultyRating dif } var rewards = GetRewards(difficulty, rand); - return new SalvageMission(seed, difficulty, dungeon.ID, faction.ID, config, biome.ID, weather.ID, air.ID, temp.Temperature, light.Color, duration, rewards, mods); + return new SalvageMission(seed, difficulty, dungeon.ID, faction.ID, config, biome.ID, air.ID, temp.Temperature, light.Color, duration, rewards, mods); } public T GetBiomeMod(string biome, System.Random rand, ref float rating) where T : class, IPrototype, IBiomeSpecificMod diff --git a/Resources/Locale/en-US/_NF/procedural/expeditions.ftl b/Resources/Locale/en-US/_NF/procedural/expeditions.ftl index bdea86044bb..cbc242978d0 100644 --- a/Resources/Locale/en-US/_NF/procedural/expeditions.ftl +++ b/Resources/Locale/en-US/_NF/procedural/expeditions.ftl @@ -9,19 +9,7 @@ salvage-time-mod-standard-time = Normal Duration salvage-time-mod-rush = Rush salvage-weather-mod-heavy-snowfall = Heavy Snowfall -salvage-weather-mod-medium-snowfall = Medium Snowfall -salvage-weather-mod-light-snowfall = Light Snowfall -salvage-weather-mod-heavy-ashfall = Heavy Ashfall -salvage-weather-mod-medium-ashfall = Medium Ashfall -salvage-weather-mod-light-ashfall = Light Ashfall -salvage-weather-mod-fallout = Fallout -salvage-weather-mod-heavy-sandstorm = Heavy Sandstorm -salvage-weather-mod-sandstorm = Sandstorm -salvage-weather-mod-hail = Hail -salvage-weather-mod-rain-light = Light Rain salvage-weather-mod-rain = Rain -salvage-weather-mod-storm = Storm -salvage-weather-mod-none = Clear Weather salvage-biome-mod-shadow = Shadow @@ -50,4 +38,4 @@ salvage-air-mod-15 = 103 CO2 salvage-air-mod-16 = 34 CO2, 34 NH3, 34 N2O salvage-air-mod-17 = 34 H2O, 34 NH3, 34 N2O salvage-air-mod-18 = 34 H2O, 34 N2O, 17 NH3, 17 CO2 -salvage-air-mod-unknown = Unknown atmosphere +salvage-air-mod-unknown = Unknown atmosphere \ No newline at end of file diff --git a/Resources/Prototypes/Procedural/salvage_mods.yml b/Resources/Prototypes/Procedural/salvage_mods.yml index c041eab9ba1..53f8a6a4625 100644 --- a/Resources/Prototypes/Procedural/salvage_mods.yml +++ b/Resources/Prototypes/Procedural/salvage_mods.yml @@ -9,6 +9,7 @@ id: Caves desc: salvage-biome-mod-caves biome: Caves + cost: 1 # Frontier - type: salvageBiomeMod id: Grasslands @@ -18,12 +19,13 @@ - type: salvageBiomeMod id: Snow desc: salvage-biome-mod-snow + cost: 1 biome: Snow - type: salvageBiomeMod id: Lava desc: salvage-biome-mod-lava - cost: 1 + cost: 2 biome: Lava #- type: salvageBiomeMod @@ -270,4 +272,4 @@ # desc: salvage-dungeon-mod-haunted # proto: Haunted # biomes: - # - Caves + # - Caves \ No newline at end of file diff --git a/Resources/Prototypes/Tiles/floors.yml b/Resources/Prototypes/Tiles/floors.yml index 9995f55c86d..27257edad3f 100644 --- a/Resources/Prototypes/Tiles/floors.yml +++ b/Resources/Prototypes/Tiles/floors.yml @@ -1843,7 +1843,6 @@ - 1.0 baseTurf: Space isSubfloor: true - weather: true # Mono footstepSounds: collection: FootstepAsteroid heatCapacity: 10000 diff --git a/Resources/Prototypes/_NF/Procedural/salvage_mods.yml b/Resources/Prototypes/_NF/Procedural/salvage_mods.yml index 5f7fe419699..0a20eafa46a 100644 --- a/Resources/Prototypes/_NF/Procedural/salvage_mods.yml +++ b/Resources/Prototypes/_NF/Procedural/salvage_mods.yml @@ -121,122 +121,16 @@ cost: 1 # Weather mods - -- type: salvageWeatherMod - id: Hail - desc: salvage-weather-mod-hail - weather: Hail - cost: 2 - biomes: - - Snow - - type: salvageWeatherMod id: SnowfallHeavy desc: salvage-weather-mod-heavy-snowfall weather: MonoBlizzard cost: 1 - biomes: - - Snow - -- type: salvageWeatherMod - id: SnowfallMedium - desc: salvage-weather-mod-medium-snowfall - weather: MonoSnow - cost: 1 - biomes: - - Grasslands - - Snow - -- type: salvageWeatherMod - id: SnowfallLight - desc: salvage-weather-mod-light-snowfall - weather: MonoSnowLight - cost: 1 - biomes: - - Grasslands - - Snow - -- type: salvageWeatherMod - id: AshfallHeavy - desc: salvage-weather-mod-heavy-ashfall - weather: AshfallHeavy - cost: 5 - biomes: - - Lava - -- type: salvageWeatherMod - id: Ashfall - desc: salvage-weather-mod-medium-ashfall - weather: Ashfall - cost: 2 - biomes: - - Lava - - Shadow - -- type: salvageWeatherMod - id: AshfallLight - desc: salvage-weather-mod-light-ashfall - weather: AshfallLight - cost: 1 - biomes: - - Lava - - Shadow - - Caves - - Desert - -- type: salvageWeatherMod - id: Fallout - desc: salvage-weather-mod-fallout - weather: Fallout - cost: 1 - biomes: - - Lava - - Shadow - -- type: salvageWeatherMod - id: SandstormHeavy - desc: salvage-weather-mod-heavy-sandstorm - weather: SandstormHeavy - cost: 1 - biomes: - - Caves - - Desert - -- type: salvageWeatherMod - id: Sandstorm - desc: salvage-weather-mod-sandstorm - weather: Sandstorm - biomes: - - Caves - - Lava - - Desert - -- type: salvageWeatherMod - id: LightRain - desc: salvage-weather-mod-rain-light - weather: MonoLightRain - biomes: - - Grasslands - - Lava # primordial planet or something idk - type: salvageWeatherMod id: Rain desc: salvage-weather-mod-rain - weather: MonoRain - biomes: - - Grasslands - -- type: salvageWeatherMod - id: Storm - desc: salvage-weather-mod-storm - weather: MonoStorm - biomes: - - Grasslands - -- type: salvageWeatherMod - id: ClearWeather - desc: salvage-weather-mod-none - weather: ClearWeather + weather: Rain # Air mixtures - type: salvageAirMod From 4ee1d7f045ca9e8daf4b64fe8890b66c1f4e1219 Mon Sep 17 00:00:00 2001 From: Dvir <39403717+dvir001@users.noreply.github.com> Date: Mon, 7 Apr 2025 19:44:52 +0300 Subject: [PATCH 03/14] Expedition Rework (#3046) * Expo Dework For Rework * Upstream stuff * multiple difficulties, failure timeouts * big wip, comment 33105 cherry-picks * SalvageExpeditions: early finish, mission params * restore more params * random expedition types * compilation fixes, copy OfferingWindow layout * More salvage job jank * expedition/destruction logic, move missions to _NF * early finish handler * lingering FTL * cooldown when in FTL * build errors * Frontier-specific salvage loot * optional loot tables per difficulty * Cleanup * Update SalvageSystem.ExpeditionConsole.cs * Update salvage_factions.yml * Update salvage_factions.yml * mob costs update * order missions by difficulty (scuffed) * Update salvage-faction.ftl * more fiddling with costs * loc strings * expedition map wrangling * frontier comments, empty array safety * return structures/enemies to salvage missions * structure count per difficulty level * asteroid.id is fine * Fix timer bar * "expedition console", objective announcement * Remove difficulty and rewards from expedition comp * salvage system: fix timeout announcements * Remove unneeded grid params, use obj-scoped mapUid * Loot test * Update loot tables test * Update salvage_loot.yml * Make the contravend more of a goal then random syndicate stuff * salvage expeditions: weights and difficulties * debug params, yeet ghosts * using the wrong entity on expedition finish * entity/structure spawning, admin ghost extraction * Increase glider cost to 2 --------- Co-authored-by: Whatstone Co-authored-by: steinhauer.erhard --- ...vageExpeditionConsoleBoundUserInterface.cs | 173 +++++- .../UI/SalvageExpeditionWindow.xaml.cs | 319 ----------- .../Salvage/UI/SalvageExpeditionWindow.xaml | 16 +- .../UI/SalvageExpeditionWindow.xaml.cs | 127 +++++ .../Gateway/Systems/GatewayGeneratorSystem.cs | 2 +- .../DungeonJob/DungeonJob.OreDunGen.cs | 7 +- .../DungeonJob/DungeonJob.PostGenWallMount.cs | 11 +- .../Procedural/DungeonJob/DungeonJob.cs | 6 +- .../Procedural/DungeonSystem.Rooms.cs | 20 +- Content.Server/Procedural/DungeonSystem.cs | 1 + Content.Server/Procedural/RoomFillSystem.cs | 2 +- .../Expeditions/SalvageExpeditionComponent.cs | 15 +- .../SalvageMiningExpeditionComponent.cs | 16 - .../SalvageStructureExpeditionComponent.cs | 13 - .../SalvageSystem.ExpeditionConsole.cs | 153 +++-- .../Salvage/SalvageSystem.Expeditions.cs | 245 +++----- .../Salvage/SalvageSystem.Magnet.cs | 22 +- .../Salvage/SalvageSystem.Runner.cs | 101 ++-- Content.Server/Salvage/SalvageSystem.cs | 9 +- .../Salvage/SpawnSalvageMissionJob.cs | 432 +++++++------- .../Systems/ShuttleSystem.GridFill.cs | 2 +- .../ExpeditionSpawnCompleteEvent.cs | 2 +- .../SalvageDestructionExpeditionComponent.cs | 17 + .../SalvageEliminationExpeditionComponent.cs | 5 +- .../Events/BluespaceErrorRule.cs | 2 +- .../Procedural/DungeonLayers/OreDunGen.cs | 4 +- .../Procedural/DungeonPresetPrototype.cs | 2 +- .../Procedural/DungeonRoomPackPrototype.cs | 2 +- .../Procedural/Loot/BiomeMarkerLoot.cs | 6 +- .../Procedural/Loot/RandomSpawnsLoot.cs | 33 ++ .../Procedural/Loot/SalvageLootPrototype.cs | 12 +- .../Procedural/SalvageDifficultyPrototype.cs | 20 +- Content.Shared/Random/IBudgetEntry.cs | 20 + Content.Shared/Random/RandomSystem.cs | 58 ++ ...iomeMod.cs => SalvageBiomeModPrototype.cs} | 2 +- ...onMod.cs => SalvageDungeonModPrototype.cs} | 0 .../Expeditions/Modifiers/SalvageTimeMod.cs | 29 - .../Salvage/Expeditions/SalvageExpeditions.cs | 96 ++-- .../Expeditions/SalvageFactionPrototype.cs | 14 +- .../Salvage/Expeditions/SalvageMobEntry.cs | 24 + .../Salvage/Expeditions/SalvageMobGroup.cs | 18 - Content.Shared/Salvage/SalvageMapPrototype.cs | 1 - Content.Shared/Salvage/SharedSalvageSystem.cs | 186 ++---- Content.Shared/_NF/CCVar/NFCCVars.cs | 14 +- .../ConfigPresets/Build/development.toml | 11 +- .../IgnoredPrototypes/ignoredPrototypes.yml | 2 + .../Locale/en-US/_NF/adventure/adventure.ftl | 2 + .../en-US/_NF/procedural/expeditions.ftl | 27 +- .../en-US/_NF/procedural/salvage-faction.ftl | 20 +- .../Locale/en-US/procedural/expeditions.ftl | 43 +- .../en-US/procedural/salvage-faction.ftl | 3 +- .../Machines/Computers/computers.yml | 4 +- .../Procedural/Magnet/asteroid_ore_gens.yml | 54 +- .../Procedural/salvage_difficulties.yml | 12 + .../Procedural/salvage_factions.yml | 538 ++---------------- Resources/Prototypes/Procedural/vgroid.yml | 52 +- .../Spawners/Random/Salvage/spawners.yml | 56 +- .../Random/dungeon_items_engineering.yml | 10 +- .../Spawners/Random/dungeon_items_medical.yml | 3 +- .../Random/dungeon_items_mercenary.yml | 2 - .../Random/dungeon_items_research.yml | 1 - .../Spawners/Random/dungeon_items_supply.yml | 2 +- .../_NF/Procedural/salvage_difficulties.yml | 31 + .../_NF/Procedural/salvage_factions.yml | 336 +++++++++++ .../_NF/Procedural/salvage_loot.yml | 41 ++ .../_NF/Procedural/salvage_mods.yml | 14 - 66 files changed, 1716 insertions(+), 1807 deletions(-) delete mode 100644 Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs rename Content.Client/{ => _NF}/Salvage/UI/SalvageExpeditionWindow.xaml (63%) create mode 100644 Content.Client/_NF/Salvage/UI/SalvageExpeditionWindow.xaml.cs delete mode 100644 Content.Server/Salvage/Expeditions/SalvageMiningExpeditionComponent.cs delete mode 100644 Content.Server/Salvage/Expeditions/SalvageStructureExpeditionComponent.cs rename Content.Server/_NF/Salvage/{ => Expeditions}/ExpeditionSpawnCompleteEvent.cs (91%) create mode 100644 Content.Server/_NF/Salvage/Expeditions/SalvageDestructionExpeditionComponent.cs rename Content.Server/{ => _NF}/Salvage/Expeditions/SalvageEliminationExpeditionComponent.cs (82%) create mode 100644 Content.Shared/Procedural/Loot/RandomSpawnsLoot.cs create mode 100644 Content.Shared/Random/IBudgetEntry.cs create mode 100644 Content.Shared/Random/RandomSystem.cs rename Content.Shared/Salvage/Expeditions/Modifiers/{SalvageBiomeMod.cs => SalvageBiomeModPrototype.cs} (96%) rename Content.Shared/Salvage/Expeditions/Modifiers/{SalvageDungeonMod.cs => SalvageDungeonModPrototype.cs} (100%) delete mode 100644 Content.Shared/Salvage/Expeditions/Modifiers/SalvageTimeMod.cs create mode 100644 Content.Shared/Salvage/Expeditions/SalvageMobEntry.cs delete mode 100644 Content.Shared/Salvage/Expeditions/SalvageMobGroup.cs create mode 100644 Resources/Prototypes/Procedural/salvage_difficulties.yml create mode 100644 Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml create mode 100644 Resources/Prototypes/_NF/Procedural/salvage_factions.yml create mode 100644 Resources/Prototypes/_NF/Procedural/salvage_loot.yml diff --git a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs index 8efb64f72b3..87899d9febf 100644 --- a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs +++ b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs @@ -1,6 +1,15 @@ +using System.Linq; +using Content.Client._NF.Salvage.UI; // Frontier +using Content.Client.Stylesheets; +using Content.Shared.CCVar; +using Content.Shared.Procedural; using Content.Shared.Salvage.Expeditions; +using Content.Shared.Salvage.Expeditions.Modifiers; using JetBrains.Annotations; using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Shared.Configuration; +using Robust.Shared.Prototypes; namespace Content.Client.Salvage.UI; @@ -8,10 +17,15 @@ namespace Content.Client.Salvage.UI; public sealed class SalvageExpeditionConsoleBoundUserInterface : BoundUserInterface { [ViewVariables] - private SalvageExpeditionWindow? _window; + private SalvageExpeditionWindow? _window; // Frontier: OfferingWindow(); // Frontier: OfferingWindow - { - SendMessage(new ClaimSalvageMessage() - { - Index = index, - }); - }; - _window.FinishMission += () => SendMessage(new FinishSalvageMessage()); - // End Frontier + _window.OnFinishPressed += () => SendMessage(new FinishSalvageMessage()); // Frontier } protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); - if (state is not SalvageExpeditionConsoleState current) + if (state is not SalvageExpeditionConsoleState current || _window == null) return; - _window?.UpdateState(current); + _window.Progression = null; + _window.Cooldown = current.CooldownTime; + _window.NextOffer = current.NextOffer; + _window.Claimed = current.Claimed; + _window.SetFinishDisabled(!current.CanFinish); // Frontier + _window.ClearOptions(); + var salvage = _entManager.System(); + + for (var i = 0; i < current.Missions.Count; i++) + { + var missionParams = current.Missions[i]; + + var offering = new OfferingWindowOption(); + offering.Title = Loc.GetString($"salvage-expedition-type-{missionParams.MissionType}"); + + var difficultyId = missionParams.Difficulty; // Frontier: Moderate(difficultyId); + // TODO: Selectable difficulty soon. + var mission = salvage.GetMission(missionParams.MissionType, difficultyProto, missionParams.Seed); // Frontier: add missionParams.MissionType + + // Difficulty + // Details + offering.AddContent(new Label() + { + Text = Loc.GetString("salvage-expedition-window-difficulty") + }); + + var difficultyColor = difficultyProto.Color; + + offering.AddContent(new Label + { + Text = Loc.GetString($"salvage-expedition-difficulty-{missionParams.Difficulty}"), // Frontier: parameterize loc string + FontColorOverride = difficultyColor, + HorizontalAlignment = Control.HAlignment.Left, + Margin = new Thickness(0f, 0f, 0f, 5f), + }); + + offering.AddContent(new Label + { + Text = Loc.GetString("salvage-expedition-difficulty-players"), + HorizontalAlignment = Control.HAlignment.Left, + }); + + offering.AddContent(new Label + { + Text = difficultyProto.RecommendedPlayers.ToString(), + FontColorOverride = StyleNano.NanoGold, + HorizontalAlignment = Control.HAlignment.Left, + Margin = new Thickness(0f, 0f, 0f, 5f), + }); + + // Details + offering.AddContent(new Label + { + Text = Loc.GetString("salvage-expedition-window-hostiles") + }); + + var faction = mission.Faction; + + offering.AddContent(new Label + { + Text = string.IsNullOrWhiteSpace(Loc.GetString(_protoManager.Index(faction).Description)) + ? LogAndReturnDefaultFactionDescription(faction) + : Loc.GetString(_protoManager.Index(faction).Description), + FontColorOverride = StyleNano.NanoGold, + HorizontalAlignment = Control.HAlignment.Left, + Margin = new Thickness(0f, 0f, 0f, 5f), + }); + + string LogAndReturnDefaultFactionDescription(string faction) + { + Logger.Error($"Description is null or white space for SalvageFactionPrototype: {faction}"); + return Loc.GetString(_protoManager.Index(faction).ID); + } + + + // Duration + offering.AddContent(new Label + { + Text = Loc.GetString("salvage-expedition-window-duration") + }); + + offering.AddContent(new Label + { + Text = mission.Duration.ToString(), + FontColorOverride = StyleNano.NanoGold, + HorizontalAlignment = Control.HAlignment.Left, + Margin = new Thickness(0f, 0f, 0f, 5f), + }); + + // Biome + offering.AddContent(new Label + { + Text = Loc.GetString("salvage-expedition-window-biome") + }); + + var biome = mission.Biome; + + offering.AddContent(new Label + { + Text = string.IsNullOrWhiteSpace(Loc.GetString(_protoManager.Index(biome).Description)) + ? LogAndReturnDefaultBiomDescription(biome) + : Loc.GetString(_protoManager.Index(biome).Description), + FontColorOverride = StyleNano.NanoGold, + HorizontalAlignment = Control.HAlignment.Left, + Margin = new Thickness(0f, 0f, 0f, 5f), + }); + + string LogAndReturnDefaultBiomDescription(string biome) + { + Logger.Error($"Description is null or white space for SalvageBiomeModPrototype: {biome}"); + return Loc.GetString(_protoManager.Index(biome).ID); + } + + // Modifiers + offering.AddContent(new Label + { + Text = Loc.GetString("salvage-expedition-window-modifiers") + }); + + var mods = mission.Modifiers; + + offering.AddContent(new Label + { + Text = string.Join("\n", mods.Select(o => "- " + o)).TrimEnd(), + FontColorOverride = StyleNano.NanoGold, + HorizontalAlignment = Control.HAlignment.Left, + Margin = new Thickness(0f, 0f, 0f, 5f), + }); + + offering.ClaimPressed += args => + { + SendMessage(new ClaimSalvageMessage() + { + Index = missionParams.Index, + }); + }; + + offering.Claimed = current.ActiveMission == missionParams.Index; + offering.Disabled = current.Claimed || current.Cooldown; + + _window.AddOption(offering); + } } } diff --git a/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs b/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs deleted file mode 100644 index aca20d5feda..00000000000 --- a/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs +++ /dev/null @@ -1,319 +0,0 @@ -using System.Linq; -using Content.Client.Computer; -using Content.Client.Stylesheets; -using Content.Client.UserInterface.Controls; -using Content.Shared.CCVar; -using Content.Shared._NF.CCVar; // Frontier -using Content.Shared.Parallax.Biomes; -using Content.Shared.Salvage; -using Content.Shared.Salvage.Expeditions; -using Content.Shared.Salvage.Expeditions.Modifiers; -using Content.Shared.Shuttles.BUIStates; -using Robust.Client.AutoGenerated; -using Robust.Client.Graphics; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.XAML; -using Robust.Shared.Configuration; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Robust.Shared.Utility; - -namespace Content.Client.Salvage.UI; - -[GenerateTypedNameReferences] -public sealed partial class SalvageExpeditionWindow : FancyWindow, - IComputerWindow -{ - private readonly IConfigurationManager _cfgManager; - private readonly IGameTiming _timing; - private readonly IPrototypeManager _prototype; - private readonly SharedSalvageSystem _salvage; - - public event Action? ClaimMission; - public event Action? FinishMission; // Frontier - private bool _claimed; - private bool _cooldown; - private TimeSpan _nextOffer; - - public SalvageExpeditionWindow() - { - RobustXamlLoader.Load(this); - _cfgManager = IoCManager.Resolve(); - _timing = IoCManager.Resolve(); - _prototype = IoCManager.Resolve(); - _salvage = IoCManager.Resolve().EntitySysManager.GetEntitySystem(); - } - - public void UpdateState(SalvageExpeditionConsoleState state) - { - _claimed = state.Claimed; - _cooldown = state.Cooldown; - _nextOffer = state.NextOffer; - Container.DisposeAllChildren(); - - for (var i = 0; i < state.Missions.Count; i++) - { - var missionParams = state.Missions[i]; - var config = missionParams.MissionType; - var mission = _salvage.GetMission(missionParams.MissionType, missionParams.Difficulty, missionParams.Seed); - - // Mission title - var missionStripe = new StripeBack() - { - Margin = new Thickness(0f, -5f, 0f, 0f) - }; - - missionStripe.AddChild(new Label() - { - Text = Loc.GetString($"salvage-expedition-type-{config.ToString()}"), - HorizontalAlignment = HAlignment.Center, - Margin = new Thickness(0f, 5f, 0f, 5f), - }); - - var lBox = new BoxContainer() - { - Orientation = BoxContainer.LayoutOrientation.Vertical - }; - - // Difficulty - // Details - lBox.AddChild(new Label() - { - Text = Loc.GetString("salvage-expedition-window-difficulty") - }); - - Color difficultyColor; - - switch (missionParams.Difficulty) - { - case DifficultyRating.Minimal: - difficultyColor = Color.FromHex("#52B4E996"); - break; - case DifficultyRating.Minor: - difficultyColor = Color.FromHex("#9FED5896"); - break; - case DifficultyRating.Moderate: - difficultyColor = Color.FromHex("#EFB34196"); - break; - case DifficultyRating.Hazardous: - difficultyColor = Color.FromHex("#DE3A3A96"); - break; - case DifficultyRating.Extreme: - difficultyColor = Color.FromHex("#D381C996"); - break; - default: - throw new ArgumentOutOfRangeException(); - } - - lBox.AddChild(new Label - { - Text = Loc.GetString($"salvage-expedition-difficulty-{missionParams.Difficulty.ToString()}"), - FontColorOverride = difficultyColor, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0f, 0f, 0f, 5f), - }); - - // Details - var details = _salvage.GetMissionDescription(mission); - - lBox.AddChild(new Label - { - Text = Loc.GetString("salvage-expedition-window-details") - }); - - lBox.AddChild(new Label - { - Text = details, - FontColorOverride = StyleNano.NanoGold, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0f, 0f, 0f, 5f), - }); - - // Details - lBox.AddChild(new Label - { - Text = Loc.GetString("salvage-expedition-window-hostiles") - }); - - // Get faction name from description if possible, fallback to ID string - if (!_prototype.TryIndex(mission.Faction, out var factionProto) || - !Loc.TryGetString(factionProto.Description, out var faction)) - faction = mission.Faction; - - lBox.AddChild(new Label - { - Text = faction, - FontColorOverride = StyleNano.NanoGold, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0f, 0f, 0f, 5f), - }); - - // Duration - lBox.AddChild(new Label - { - Text = Loc.GetString("salvage-expedition-window-duration") - }); - - lBox.AddChild(new Label - { - Text = mission.Duration.ToString(), - FontColorOverride = StyleNano.NanoGold, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0f, 0f, 0f, 5f), - }); - - // Biome - lBox.AddChild(new Label - { - Text = Loc.GetString("salvage-expedition-window-biome") - }); - - var biome = mission.Biome; - - lBox.AddChild(new Label - { - Text = Loc.GetString(_prototype.Index(biome).ID), - FontColorOverride = StyleNano.NanoGold, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0f, 0f, 0f, 5f), - }); - - // Modifiers - lBox.AddChild(new Label - { - Text = Loc.GetString("salvage-expedition-window-modifiers") - }); - - var mods = mission.Modifiers; - - lBox.AddChild(new Label - { - Text = string.Join("\n", mods.Select(o => "- " + o)).TrimEnd(), - FontColorOverride = StyleNano.NanoGold, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0f, 0f, 0f, 5f), - }); - - // Frontier: only show rewards if enabled via cvar and not empty - if (_cfgManager.GetCVar(NFCCVars.SalvageExpeditionRewardsEnabled) && mission.Rewards.Count > 0) - { - lBox.AddChild(new Label() - { - Text = Loc.GetString("salvage-expedition-window-rewards") - }); - - var rewards = new Dictionary(); - foreach (var reward in mission.Rewards) - { - var name = _prototype.Index(reward).Name; - var count = rewards.GetOrNew(name); - count++; - rewards[name] = count; - } - - // there will always be 3 or more rewards so no need for 0 check - lBox.AddChild(new Label() - { - Text = string.Join("\n", rewards.Select(o => "- " + o.Key + (o.Value > 1 ? $" x {o.Value}" : ""))).TrimEnd(), - FontColorOverride = StyleNano.ConcerningOrangeFore, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0f, 0f, 0f, 5f) - }); - } - - // Claim - var claimButton = new Button() - { - HorizontalExpand = true, - VerticalAlignment = VAlignment.Bottom, - Pressed = state.ActiveMission == missionParams.Index, - ToggleMode = true, - Disabled = state.Claimed || state.Cooldown, - }; - - claimButton.Label.Margin = new Thickness(0f, 5f); - - claimButton.OnPressed += args => - { - ClaimMission?.Invoke(missionParams.Index); - }; - - if (state.ActiveMission == missionParams.Index) - { - claimButton.Text = Loc.GetString("salvage-expedition-window-claimed"); - claimButton.AddStyleClass(StyleBase.ButtonCaution); - } - else - { - claimButton.Text = Loc.GetString("salvage-expedition-window-claim"); - } - - var box = new PanelContainer - { - PanelOverride = new StyleBoxFlat(new Color(30, 30, 34)), - HorizontalExpand = true, - Margin = new Thickness(5f, 0f), - MinWidth = 280, // Frontier - Children = - { - new BoxContainer - { - Orientation = BoxContainer.LayoutOrientation.Vertical, - Children = - { - missionStripe, - lBox, - new Control() {VerticalExpand = true}, - claimButton, - }, - Margin = new Thickness(5f, 5f) - } - } - }; - - LayoutContainer.SetAnchorPreset(box, LayoutContainer.LayoutPreset.Wide); - - Container.AddChild(box); - } - - // Frontier - Finish.OnPressed += _ => - { - Finish.Disabled = true; - FinishMission?.Invoke(); - }; - - Finish.Disabled = !state.CanFinish; - // Frontier - } - - protected override void FrameUpdate(FrameEventArgs args) - { - base.FrameUpdate(args); - - if (_claimed) - { - NextOfferBar.Value = 0f; - NextOfferText.Text = "00:00"; - return; - } - - var remaining = _nextOffer - _timing.CurTime; - - if (remaining < TimeSpan.Zero) - { - NextOfferBar.Value = 1f; - NextOfferText.Text = "00:00"; - } - else - { - var cooldown = _cooldown - ? TimeSpan.FromSeconds(_cfgManager.GetCVar(NFCCVars.SalvageExpeditionFailedCooldown)) - : TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.SalvageExpeditionCooldown)); - - NextOfferBar.Value = 1f - (float) (remaining / cooldown); - NextOfferText.Text = $"{remaining.Minutes:00}:{remaining.Seconds:00}"; - } - } -} diff --git a/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml b/Content.Client/_NF/Salvage/UI/SalvageExpeditionWindow.xaml similarity index 63% rename from Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml rename to Content.Client/_NF/Salvage/UI/SalvageExpeditionWindow.xaml index 4cfe8b78f09..e5920b02277 100644 --- a/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml +++ b/Content.Client/_NF/Salvage/UI/SalvageExpeditionWindow.xaml @@ -3,10 +3,24 @@ Title="{Loc 'salvage-expedition-window-title'}" MinSize="800 360"> + + + SetWidth="96" + Margin="5"/> +/// Generic window for offering multiple selections with a timer. +/// +[GenerateTypedNameReferences] +public sealed partial class SalvageExpeditionWindow : FancyWindow, + IComputerWindow +{ + [Dependency] private readonly IGameTiming _timing = default!; + + public Action? OnFinishPressed; + + public bool Claimed; + public TimeSpan NextOffer; + private TimeSpan? _progression; + + /// + /// Time between NextOffers + /// + public TimeSpan Cooldown; + + /// + /// Time between Progressions + /// + public TimeSpan ProgressionCooldown; + + /// + /// Secondary timer used for tracking active progress. + /// + public TimeSpan? Progression + { + get => _progression; + set + { + if (_progression == value) + return; + + _progression = value; + + if (value == null) + { + ProgressionBox.Visible = false; + } + else + { + ProgressionBox.Visible = true; + } + } + } + + public SalvageExpeditionWindow() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + + ProgressionBar.ForegroundStyleBoxOverride = new StyleBoxFlat(Color.FromHex("#C74EBD")); + Finish.OnPressed += _ => OnFinishPressed?.Invoke(); + } + + public void AddOption(OfferingWindowOption option) + { + Container.AddChild(option); + } + + public void ClearOptions() + { + Container.DisposeAllChildren(); + } + + public void SetFinishDisabled(bool disabled) + { + Finish.Disabled = disabled; + } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + + if (_progression != null) + { + var remaining = _progression.Value - _timing.CurTime; + + if (remaining < TimeSpan.Zero) + { + ProgressionBar.Value = 1f; + ProgressionText.Text = "00:00"; + } + else + { + ProgressionBar.Value = 1f - (float)(remaining / ProgressionCooldown); + ProgressionText.Text = $"{remaining.Minutes:00}:{remaining.Seconds:00}"; + } + } + + if (Claimed) + { + NextOfferBar.Value = 1f; + NextOfferText.Text = "00:00"; + } + else + { + var remaining = NextOffer - _timing.CurTime; + + if (remaining < TimeSpan.Zero) + { + NextOfferBar.Value = 1f; + NextOfferText.Text = "00:00"; + } + else + { + NextOfferBar.Value = 1f - (float)(remaining / Cooldown); + NextOfferText.Text = $"{remaining.Minutes:00}:{remaining.Seconds:00}"; + } + } + } +} diff --git a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs index 08beded0760..9644b644b4f 100644 --- a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs +++ b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs @@ -185,7 +185,7 @@ private void OnGeneratorOpen(Entity ent, r var dungeonRotation = _dungeon.GetDungeonRotation(seed); var dungeonPosition = (origin + dungeonRotation.RotateVec(new Vector2i(0, dungeonDistance))).Floored(); - _dungeon.GenerateDungeon(_protoManager.Index("Experiment"), "Experiment", args.MapUid, grid, dungeonPosition, seed); // Frontier: added "Experiment" + _dungeon.GenerateDungeon(_protoManager.Index("Experiment"), "Experiment", args.MapUid, grid, dungeonPosition, seed); // Frontier: add "Experiment" arg // TODO: Dungeon mobs + loot. diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.OreDunGen.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.OreDunGen.cs index e21dac63c6d..25efd6bd27f 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.OreDunGen.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.OreDunGen.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using Content.Shared.Maps; +using Content.Shared.Maps; // Upstream#33105 using Content.Shared.Procedural; using Content.Shared.Procedural.Components; using Content.Shared.Procedural.DungeonLayers; @@ -21,6 +21,8 @@ private async Task PostGen( { // Doesn't use dungeon data because layers and we don't need top-down support at the moment. + // Upstream#33105 - maskable room generation (Thank you, TheShuEd!) + var emptyTiles = false; var replaceEntities = new Dictionary(); var availableTiles = new List(); var tiles = _maps.GetAllTilesEnumerator(_gridUid, _grid); @@ -73,6 +75,7 @@ private async Task PostGen( if (!ValidateResume()) return; } + // End Upstream#33105 - maskable room generation (Thank you, TheShuEd!) var remapping = new Dictionary(); @@ -155,7 +158,7 @@ private async Task PostGen( if (groupSize > 0) { - _sawmill.Warning($"Found remaining group size for ore veins of {gen.Entity.Id ?? "null"}!"); + _sawmill.Warning($"Found remaining group size for ore veins of {gen.Entity.Id ?? "null"}!"); // Upstream#33105 - Replacement(); var allExterior = new HashSet(dungeon.CorridorExteriorTiles); @@ -40,9 +42,6 @@ private async Task PostGen(WallMountDunGen gen, DungeonData data, Dungeon dungeo _maps.SetTile(_gridUid, _grid, neighbor, _tile.GetVariantTile(tileDef, random)); var gridPos = _maps.GridTileToLocal(_gridUid, _grid, neighbor); - - if (!validProto) // Frontier: error handling - continue; // Frontier: error handling var protoNames = EntitySpawnCollection.GetSpawns(_prototype.Index(spawnProto).Entries, random); _entManager.SpawnEntities(gridPos, protoNames); diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.cs index c83820b28da..e9861897c84 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.cs @@ -67,7 +67,7 @@ public sealed partial class DungeonJob : Job> private readonly EntityCoordinates? _targetCoordinates; private readonly ISawmill _sawmill; - private readonly string _genId; // Frontier: add ID + private readonly string _genID; // Frontier: add ID public DungeonJob( ISawmill sawmill, @@ -113,7 +113,7 @@ public DungeonJob( _seed = seed; _position = position; _targetCoordinates = targetCoordinates; - _genId = genID; // Frontier + _genID = genID; // Frontier } /// @@ -159,7 +159,7 @@ private async Task> GetDungeons( protected override async Task?> Process() { - _sawmill.Info($"Generating dungeon {_genId} with seed {_seed} on {_entManager.ToPrettyString(_gridUid)}"); // Frontier: _gen<_genId + _sawmill.Info($"Generating dungeon {_genID} with seed {_seed} on {_entManager.ToPrettyString(_gridUid)}"); // Frontier: _gen<_genID _grid.CanSplit = false; var random = new Random(_seed); var position = (_position + random.NextPolarVector2(_gen.MinOffset, _gen.MaxOffset)).Floored(); diff --git a/Content.Server/Procedural/DungeonSystem.Rooms.cs b/Content.Server/Procedural/DungeonSystem.Rooms.cs index 1ea71d1ba58..ca667ae85e1 100644 --- a/Content.Server/Procedural/DungeonSystem.Rooms.cs +++ b/Content.Server/Procedural/DungeonSystem.Rooms.cs @@ -91,7 +91,7 @@ public void SpawnRoom( roomRotation = GetRoomRotation(room, random); } - var roomTransform = Matrix3Helpers.CreateTransform((Vector2) room.Size / 2f, roomRotation); + var roomTransform = Matrix3Helpers.CreateTransform((Vector2)room.Size / 2f, roomRotation); var finalTransform = Matrix3x2.Multiply(roomTransform, originTransform); SpawnRoom(gridUid, grid, finalTransform, room, reservedTiles, clearExisting); @@ -114,20 +114,6 @@ public Angle GetRoomRotation(DungeonRoomPrototype room, Random random) return roomRotation; } - private static Box2 GetRotatedBox(Vector2 point1, Vector2 point2, double angle) - { - if (angle == 0) - return new Box2(point1, point2); - if (Math.Abs(angle - Math.PI / 2) < 1E-5) - return new Box2(point2.X, point1.Y, point1.X, point2.Y); - if (Math.Abs(angle - Math.PI) < 1E-5) - return new Box2(point2, point1); - if (Math.Abs(angle + Math.PI / 2) < 1E-5) - return new Box2(point1.X, point2.Y, point2.X, point1.Y); - - throw new NotImplementedException(); - } - public void SpawnRoom( EntityUid gridUid, MapGridComponent grid, @@ -164,8 +150,6 @@ public async Task SpawnRoomAsync( var templateGrid = Comp(templateMapUid); var roomDimensions = room.Size; - var entitySet = new HashSet(); - var finalRoomRotation = roomTransform.Rotation(); var roomCenter = (room.Offset + room.Size / 2f) * grid.TileSize; @@ -304,7 +288,7 @@ public async Task SpawnRoomAsync( // but place 1 nanometre off grid and fail the add. if (!_maps.TryGetTileRef(gridUid, grid, tilePos, out var tileRef) || tileRef.Tile.IsEmpty) { - _maps.SetTile(gridUid, grid, tilePos, _tile.GetVariantTile((ContentTileDefinition) _tileDefManager[FallbackTileId], _random.GetRandom())); + _maps.SetTile(gridUid, grid, tilePos, _tile.GetVariantTile((ContentTileDefinition)_tileDefManager[FallbackTileId], _random.GetRandom())); } var result = _decals.TryAddDecal( diff --git a/Content.Server/Procedural/DungeonSystem.cs b/Content.Server/Procedural/DungeonSystem.cs index 4274f82f1d5..1890cfefe58 100644 --- a/Content.Server/Procedural/DungeonSystem.cs +++ b/Content.Server/Procedural/DungeonSystem.cs @@ -207,6 +207,7 @@ public void GenerateDungeon(DungeonConfig gen, Log, DungeonJobTime, EntityManager, + _prototype, _tileDefManager, _anchorable, diff --git a/Content.Server/Procedural/RoomFillSystem.cs b/Content.Server/Procedural/RoomFillSystem.cs index f4ccab23673..9ebde1a79f2 100644 --- a/Content.Server/Procedural/RoomFillSystem.cs +++ b/Content.Server/Procedural/RoomFillSystem.cs @@ -28,7 +28,7 @@ private void OnRoomFillMapInit(EntityUid uid, RoomFillComponent component, MapIn _dungeon.SpawnRoom( xform.GridUid.Value, mapGrid, - _maps.LocalToTile(xform.GridUid.Value, mapGrid, xform.Coordinates) - new Vector2i(room.Size.X/2,room.Size.Y/2), + _maps.LocalToTile(xform.GridUid.Value, mapGrid, xform.Coordinates) - new Vector2i(room.Size.X / 2, room.Size.Y / 2), room, random, null, diff --git a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs index 819eecaac6b..81a4bf79235 100644 --- a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs +++ b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs @@ -57,18 +57,5 @@ public sealed partial class SalvageExpeditionComponent : SharedSalvageExpedition /// [DataField] public ResolvedSoundSpecifier SelectedSong; - - // Frontier: expedition difficulty and rewards - /// - /// The difficulty this mission had or, in the future, was selected. - /// - [ViewVariables(VVAccess.ReadWrite), DataField("difficulty")] - public DifficultyRating Difficulty; - - /// - /// List of items to order on mission completion - /// - [ViewVariables(VVAccess.ReadWrite), DataField("rewards", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List Rewards = default!; - // End Frontier: expedition difficulty and rewards + // End Frontier: moved to Shared } diff --git a/Content.Server/Salvage/Expeditions/SalvageMiningExpeditionComponent.cs b/Content.Server/Salvage/Expeditions/SalvageMiningExpeditionComponent.cs deleted file mode 100644 index b9a1379aab9..00000000000 --- a/Content.Server/Salvage/Expeditions/SalvageMiningExpeditionComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Shared.Salvage; - -namespace Content.Server.Salvage.Expeditions; - -/// -/// Tracks expedition data for -/// -[RegisterComponent, Access(typeof(SalvageSystem))] -public sealed partial class SalvageMiningExpeditionComponent : Component -{ - /// - /// Entities that were present on the shuttle and match the loot tax. - /// - [DataField("exemptEntities")] - public List ExemptEntities = new(); -} diff --git a/Content.Server/Salvage/Expeditions/SalvageStructureExpeditionComponent.cs b/Content.Server/Salvage/Expeditions/SalvageStructureExpeditionComponent.cs deleted file mode 100644 index 0dec1f81adf..00000000000 --- a/Content.Server/Salvage/Expeditions/SalvageStructureExpeditionComponent.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Content.Shared.Salvage; - -namespace Content.Server.Salvage.Expeditions.Structure; - -/// -/// Tracks expedition data for -/// -[RegisterComponent, Access(typeof(SalvageSystem), typeof(SpawnSalvageMissionJob))] -public sealed partial class SalvageStructureExpeditionComponent : Component -{ - [DataField("structures")] - public List Structures = new(); -} diff --git a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs index 3b70fc244ed..830aa4727d7 100644 --- a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs +++ b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs @@ -1,19 +1,21 @@ -using Content.Server.Station.Components; -using Content.Shared.Popups; using Content.Shared.Shuttles.Components; +using Content.Shared.Procedural; using Content.Shared.Salvage.Expeditions; -using Robust.Shared.Map.Components; -using Robust.Shared.Physics.Components; +using Content.Shared.Dataset; using Robust.Shared.Prototypes; -using Content.Server.Salvage.Expeditions; // Frontier +using Content.Shared.Popups; // Frontier using Content.Shared._NF.CCVar; // Frontier -using Content.Shared.Mind.Components; // Frontier -using Content.Shared.Mobs.Components; // Frontier -using Content.Shared.NPC.Components; // Frontier -using Content.Shared.IdentityManagement; // Frontier +using Content.Server.Station.Components; // Frontier +using Robust.Shared.Map.Components; // Frontier +using Robust.Shared.Physics.Components; // Frontier using Content.Shared.NPC; // Frontier using Content.Server._NF.Salvage; // Frontier -using Content.Server.Shuttles.Components; +using Content.Shared.NPC.Components; // Frontier +using Content.Server.Salvage.Expeditions; // Frontier +using Content.Shared.Mind.Components; // Frontier +using Content.Shared.Mobs.Components; // Frontier +using Robust.Shared.Physics; // Frontier +using Content.Server.Shuttles.Components; //Mono's Exped Proximity namespace Content.Server.Salvage; @@ -21,61 +23,65 @@ public sealed partial class SalvageSystem { [ValidatePrototypeId] public const string CoordinatesDisk = "CoordinatesDisk"; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; // Frontier + [Dependency] private readonly SalvageSystem _salvage = default!; // Frontier private const float ShuttleFTLRange = 256f; private const float ShuttleFTLMassThreshold = 100f; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - private void OnSalvageClaimMessage(EntityUid uid, SalvageExpeditionConsoleComponent component, ClaimSalvageMessage args) { var station = _station.GetOwningStation(uid); - // Frontier - if (!TryComp(station, out var data) || data.Claimed) // Moved up before the active expedition count + if (!TryComp(station, out var data) || data.Claimed) + return; + + if (!data.Missions.TryGetValue(args.Index, out var missionparams)) return; + // Frontier: prevent expeditions if there are too many out already. var activeExpeditionCount = 0; var expeditionQuery = AllEntityQuery(); while (expeditionQuery.MoveNext(out var expeditionUid, out _, out _)) + { if (TryComp(expeditionUid, out var expeditionData) && expeditionData.Claimed) activeExpeditionCount++; + } if (activeExpeditionCount >= _cfgManager.GetCVar(NFCCVars.SalvageExpeditionMaxActive)) { - PlayDenySound(uid, component); + PlayDenySound((uid, component)); _popupSystem.PopupEntity(Loc.GetString("shuttle-ftl-too-many"), uid, PopupType.MediumCaution); - UpdateConsoles(station.Value, data); + UpdateConsoles((station.Value, data)); return; } // End Frontier - if (!data.Missions.TryGetValue(args.Index, out var missionparams)) - return; + // var cdUid = Spawn(CoordinatesDisk, Transform(uid).Coordinates); // Frontier: no disk-based FTL + // SpawnMission(missionparams, station.Value, cdUid); // Frontier: no disk-based FTL // Frontier: FTL travel is currently restricted to expeditions and such, and so we need to put this here + #region Frontier FTL changes // until FTL changes for us in some way. - if (!component.Debug) // Skip the test - { - if (!TryComp(station, out var stationData)) - return; - if (_station.GetLargestGrid(stationData) is not { Valid: true } grid) - return; - if (!TryComp(grid, out var gridComp)) - return; - // Frontier: check for FTL component - if one exists, the station won't be taken into FTL. - if (HasComp(grid)) + // Run a proximity check (unless using a debug console) + if (_salvage.ProximityCheck && !component.Debug) + { + if (!TryComp(station, out var stationData) + || _station.GetLargestGrid(stationData) is not { Valid: true } ourGrid + || !TryComp(ourGrid, out var gridComp)) { - PlayDenySound(uid, component); - _popupSystem.PopupEntity(Loc.GetString("shuttle-ftl-recharge"), uid, PopupType.MediumCaution); - UpdateConsoles(station.Value, data); // Sure, why not? + PlayDenySound((uid, component)); + _popupSystem.PopupEntity(Loc.GetString("shuttle-ftl-invalid"), uid, PopupType.MediumCaution); + UpdateConsoles((station.Value, data)); return; } - - var xform = Transform(grid); - var bounds = xform.WorldMatrix.TransformBox(gridComp.LocalAABB).Enlarged(ShuttleFTLRange); + var xform = Transform(ourGrid); + var bounds = _transform.GetWorldMatrix(ourGrid).TransformBox(gridComp.LocalAABB).Enlarged(ShuttleFTLRange); var bodyQuery = GetEntityQuery(); + var otherGrids = new List>(); + _mapManager.FindGridsIntersecting(xform.MapID, bounds, ref otherGrids); // Keep track of docked grids to exclude them from the proximity check + var dockedGrids = new HashSet(); // Find all docked grids by looking for DockingComponents on the shuttle @@ -83,7 +89,7 @@ private void OnSalvageClaimMessage(EntityUid uid, SalvageExpeditionConsoleCompon while (dockQuery.MoveNext(out var dockUid, out var dock, out var dockXform)) { // Only consider docks on our grid - if (dockXform.GridUid != grid || !dock.Docked || dock.DockedWith == null) + if (dockXform.GridUid != ourGrid || !dock.Docked || dock.DockedWith == null) continue; // If we have a docked entity, get its grid @@ -107,7 +113,7 @@ private void OnSalvageClaimMessage(EntityUid uid, SalvageExpeditionConsoleCompon // If we have a docked entity and it's not our grid, add its grid to the exclusion list if (TryComp(parentDock.DockedWith.Value, out var siblingDockedXform) && siblingDockedXform.GridUid != null && - siblingDockedXform.GridUid != grid) + siblingDockedXform.GridUid != ourGrid) { dockedGrids.Add(siblingDockedXform.GridUid.Value); } @@ -115,37 +121,36 @@ private void OnSalvageClaimMessage(EntityUid uid, SalvageExpeditionConsoleCompon } } - foreach (var other in _mapManager.FindGridsIntersecting(xform.MapID, bounds)) + foreach (var otherGrid in otherGrids) { - if (other.Owner == grid || - dockedGrids.Contains(other.Owner) || // Skip grids that are docked to us or to the same parent grid - !bodyQuery.TryGetComponent(other.Owner, out var body) || - body.Mass < ShuttleFTLMassThreshold) + if (ourGrid == otherGrid.Owner || + dockedGrids.Contains(otherGrid.Owner) || // Skip grids that are docked to us or to the same parent grid + !bodyQuery.TryGetComponent(otherGrid.Owner, out var body) || + body.Mass < ShuttleFTLMassThreshold && body.BodyType == BodyType.Dynamic) { continue; } - PlayDenySound(uid, component); - _popupSystem.PopupEntity(Loc.GetString("shuttle-ftl-proximity"), uid, PopupType.Medium); - UpdateConsoles(station.Value, data); + PlayDenySound((uid, component)); + _popupSystem.PopupEntity(Loc.GetString("shuttle-ftl-proximity"), uid, PopupType.MediumCaution); + UpdateConsoles((station.Value, data)); return; } } - // End Frontier - - // Frontier change - disable coordinate disks for expedition missions - //var cdUid = Spawn(CoordinatesDisk, Transform(uid).Coordinates); SpawnMission(missionparams, station.Value, null); + #endregion Frontier FTL changes + // End Frontier data.ActiveMission = args.Index; - var mission = GetMission(missionparams.MissionType, missionparams.Difficulty, missionparams.Seed); + var mission = GetMission(missionparams.MissionType, _prototypeManager.Index(missionparams.Difficulty), missionparams.Seed); // Frontier: add MissionType + // Frontier - TODO: move this to progression for secondary window timer data.NextOffer = _timing.CurTime + mission.Duration + TimeSpan.FromSeconds(1); + data.CooldownTime = mission.Duration + TimeSpan.FromSeconds(1); // Frontier - // Frontier change - disable coordinate disks for expedition missions - //_labelSystem.Label(cdUid, GetFTLName(_prototypeManager.Index("NamesBorer"), missionparams.Seed)); - //_audio.PlayPvs(component.PrintSound, uid); + // _labelSystem.Label(cdUid, GetFTLName(_prototypeManager.Index("NamesBorer"), missionparams.Seed)); // Frontier: no disc + // _audio.PlayPvs(component.PrintSound, uid); // Frontier: no disc - UpdateConsoles(station.Value, data); // Frontier: add station + UpdateConsoles((station.Value, data)); } // Frontier: early expedition end @@ -158,9 +163,9 @@ private void OnSalvageFinishMessage(EntityUid entity, SalvageExpeditionConsoleCo // Based on SalvageSystem.Runner:OnConsoleFTLAttempt if (!TryComp(entity, out TransformComponent? xform)) // Get the console's grid (if you move it, rip you) { - PlayDenySound(entity, component); + PlayDenySound((entity, component)); _popupSystem.PopupEntity(Loc.GetString("salvage-expedition-shuttle-not-found"), entity, PopupType.MediumCaution); - UpdateConsoles(station.Value, data); + UpdateConsoles((station.Value, data)); return; } @@ -170,9 +175,9 @@ private void OnSalvageFinishMessage(EntityUid entity, SalvageExpeditionConsoleCo // with it. Block the return until the drive is ready so the ship can actually be evacuated. if (xform.GridUid is { } shuttleGrid && HasComp(shuttleGrid)) { - PlayDenySound(entity, component); + PlayDenySound((entity, component)); _popupSystem.PopupEntity(Loc.GetString("salvage-expedition-ftl-cooldown"), entity, PopupType.MediumCaution); - UpdateConsoles(station.Value, data); + UpdateConsoles((station.Value, data)); return; } @@ -195,23 +200,23 @@ private void OnSalvageFinishMessage(EntityUid entity, SalvageExpeditionConsoleCo if (TryComp(uid, out NpcFactionMemberComponent? npcFaction)) { var hostileFactions = npcFaction.HostileFactions; - if (hostileFactions.Contains("NanoTrasen")) // Nasty - what if we need pirate expeditions? + if (hostileFactions.Contains("NanoTrasen")) // TODO: move away from hardcoded faction continue; } // Okay they're on salvage, so are they on the shuttle. if (mobXform.GridUid != xform.GridUid) { - PlayDenySound(entity, component); - _popupSystem.PopupEntity(Loc.GetString("salvage-expedition-not-everyone-aboard", ("target", Identity.Entity(uid, EntityManager))), entity, PopupType.MediumCaution); - UpdateConsoles(station.Value, data); + PlayDenySound((entity, component)); + _popupSystem.PopupEntity(Loc.GetString("salvage-expedition-not-everyone-aboard", ("target", uid)), entity, PopupType.MediumCaution); + UpdateConsoles((station.Value, data)); return; } } // End SalvageSystem.Runner:OnConsoleFTLAttempt data.CanFinish = false; - UpdateConsoles(station.Value, data); + UpdateConsoles((station.Value, data)); var map = Transform(entity).MapUid; @@ -224,8 +229,9 @@ private void OnSalvageFinishMessage(EntityUid entity, SalvageExpeditionConsoleCo if (expedition.EndTime <= newEndTime) return; - expedition.EndTime = newEndTime; expedition.Stage = ExpeditionStage.FinalCountdown; + expedition.EndTime = newEndTime; + Dirty(map.Value, expedition); Announce(map.Value, Loc.GetString("salvage-expedition-announcement-early-finish", ("departTime", departTime))); } @@ -241,7 +247,7 @@ private void OnSalvageConsoleParent(Entity co UpdateConsole(console); } - private void UpdateConsoles(EntityUid stationUid, SalvageExpeditionDataComponent component) + private void UpdateConsoles(Entity component) { var state = GetState(component); @@ -250,18 +256,9 @@ private void UpdateConsoles(EntityUid stationUid, SalvageExpeditionDataComponent { var station = _station.GetOwningStation(uid, xform); - if (station != stationUid) + if (station != component.Owner) continue; - // Frontier: if we have a lingering FTL component, we cannot start a new mission - if (!TryComp(station, out var stationData) || - _station.GetLargestGrid(stationData) is not { Valid: true } grid || - HasComp(grid)) - { - state.Cooldown = true; //Hack: disable buttons - } - // End Frontier - _ui.SetUiState((uid, uiComp), SalvageConsoleUiKey.Expedition, state); } } @@ -277,7 +274,7 @@ private void UpdateConsole(Entity component) } else { - state = new SalvageExpeditionConsoleState(TimeSpan.Zero, false, true, false, 0, new List()); // Frontier: add false as 4th param + state = new SalvageExpeditionConsoleState(TimeSpan.Zero, false, true, 0, new List(), false, TimeSpan.FromSeconds(1)); // Frontier: add false, 1 second timespan as last args (cannot finish, not on a mission) } // Frontier: if we have a lingering FTL component, we cannot start a new mission @@ -292,8 +289,10 @@ private void UpdateConsole(Entity component) _ui.SetUiState(component.Owner, SalvageConsoleUiKey.Expedition, state); } - private void PlayDenySound(EntityUid uid, SalvageExpeditionConsoleComponent component) + // Frontier: deny sound + private void PlayDenySound(Entity ent) { - _audio.PlayPvs(_audio.GetSound(component.ErrorSound), uid); + _audio.PlayPvs(_audio.ResolveSound(ent.Comp.ErrorSound), ent); } + // End Frontier } diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs index 9af7ada60f3..38bec3df7d6 100644 --- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs +++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs @@ -1,29 +1,26 @@ using System.Linq; using System.Threading; -using Content.Server._NF.Salvage; // Frontier: graceful exped spawn failures -using Content.Server.Cargo.Components; -using Content.Server.Cargo.Systems; using Content.Server.Salvage.Expeditions; using Content.Server.Salvage.Expeditions.Structure; using Content.Shared.CCVar; -using Content.Shared._NF.CCVar; // Frontier using Content.Shared.Examine; using Content.Shared.Random.Helpers; using Content.Shared.Salvage.Expeditions; using Robust.Shared.Audio; using Robust.Shared.CPUJob.JobQueues; using Robust.Shared.CPUJob.JobQueues.Queues; -using Content.Server.Shuttles.Systems; -using Content.Server.Station.Components; -using Content.Server.Station.Systems; -using Content.Shared.Coordinates; -using Content.Shared.Procedural; -using Content.Shared.Salvage; using Robust.Shared.GameStates; -using Robust.Shared.Random; using Robust.Shared.Map; +using Content.Server._NF.Salvage.Expeditions; // Frontier +using Content.Server.Station.Components; // Frontier +using Content.Shared.Procedural; // Frontier +using Content.Shared.Salvage; // Frontier +using Robust.Shared.Prototypes; // Frontier +using Content.Shared._NF.CCVar; // Frontier using Content.Shared.Shuttles.Components; // Frontier -using Robust.Shared.Configuration; // Frontier +using Robust.Shared.Configuration; +using Content.Shared.Ghost; +using System.Numerics; // Frontier namespace Content.Server.Salvage; @@ -33,16 +30,19 @@ public sealed partial class SalvageSystem * Handles setup / teardown of salvage expeditions. */ - private const int MissionLimit = 5; - [Dependency] private readonly IConfigurationManager _cfgManager = default!; // Frontier + private const int MissionLimit = 5; // Frontier: 3<5 private readonly JobQueue _salvageQueue = new(); private readonly List<(SpawnSalvageMissionJob Job, CancellationTokenSource CancelToken)> _salvageJobs = new(); - private readonly List _missionDifficulties = [DifficultyRating.Moderate, DifficultyRating.Hazardous, DifficultyRating.Extreme]; // Frontier private const double SalvageJobTime = 0.002; + private readonly List<(ProtoId id, int value)> _missionDifficulties = [("NFModerate", 0), ("NFHazardous", 1), ("NFExtreme", 2)]; // Frontier: mission difficulties with order + + [Dependency] private readonly IConfigurationManager _cfgManager = default!; // Frontier private float _cooldown; - private float _failedCooldown; + private float _failedCooldown; // Frontier + public float TravelTime { get; private set; } // Frontier + public bool ProximityCheck { get; private set; } // Frontier private void InitializeExpeditions() { @@ -53,16 +53,20 @@ private void InitializeExpeditions() SubscribeLocalEvent(OnSalvageFinishMessage); // Frontier: For early finish SubscribeLocalEvent(OnExpeditionMapInit); - // SubscribeLocalEvent(OnDataUnpaused); // Frontier - SubscribeLocalEvent(OnExpeditionShutdown); - // SubscribeLocalEvent(OnExpeditionUnpaused); // Frontier SubscribeLocalEvent(OnExpeditionGetState); + SubscribeLocalEvent(OnMapTerminating); // Frontier SubscribeLocalEvent(OnStructureExamine); - Subs.CVar(_cfgManager, CCVars.SalvageExpeditionCooldown, SetCooldownChange, true); // Frontier - Subs.CVar(_cfgManager, NFCCVars.SalvageExpeditionFailedCooldown, SetFailedCooldownChange, true); // Frontier + _cooldown = _cfgManager.GetCVar(CCVars.SalvageExpeditionCooldown); + Subs.CVar(_cfgManager, CCVars.SalvageExpeditionCooldown, SetCooldownChange); + _failedCooldown = _cfgManager.GetCVar(NFCCVars.SalvageExpeditionFailedCooldown); // Frontier + Subs.CVar(_cfgManager, NFCCVars.SalvageExpeditionFailedCooldown, SetFailedCooldownChange); // Frontier + TravelTime = _cfgManager.GetCVar(NFCCVars.SalvageExpeditionTravelTime); // Frontier + Subs.CVar(_cfgManager, NFCCVars.SalvageExpeditionTravelTime, SetTravelTime); // Frontier + ProximityCheck = _cfgManager.GetCVar(NFCCVars.SalvageExpeditionProximityCheck); // Frontier + Subs.CVar(_cfgManager, NFCCVars.SalvageExpeditionProximityCheck, SetProximityCheck); // Frontier } private void OnExpeditionGetState(EntityUid uid, SalvageExpeditionComponent component, ref ComponentGetState args) @@ -73,14 +77,6 @@ private void OnExpeditionGetState(EntityUid uid, SalvageExpeditionComponent comp }; } - // Frontier - private void ShutdownExpeditions() - { - _cfgManager.UnsubValueChanged(CCVars.SalvageExpeditionCooldown, SetCooldownChange); - _cfgManager.UnsubValueChanged(NFCCVars.SalvageExpeditionFailedCooldown, SetFailedCooldownChange); - } - // End Frontier - private void SetCooldownChange(float obj) { // Update the active cooldowns if we change it. @@ -96,19 +92,23 @@ private void SetCooldownChange(float obj) _cooldown = obj; } + // Frontier: failed cooldowns private void SetFailedCooldownChange(float obj) { - var diff = obj - _failedCooldown; - - var query = AllEntityQuery(); + // Note: we don't know whether or not players have failed missions, so let's not punish/reward them if this gets changed. + _failedCooldown = obj; + } - while (query.MoveNext(out var comp)) - { - comp.NextOffer += TimeSpan.FromSeconds(diff); - } + private void SetTravelTime(float obj) + { + TravelTime = obj; + } - _failedCooldown = obj; + private void SetProximityCheck(bool obj) + { + ProximityCheck = obj; } + // End Frontier private void OnExpeditionMapInit(EntityUid uid, SalvageExpeditionComponent component, MapInitEvent args) { @@ -134,20 +134,10 @@ private void OnExpeditionShutdown(EntityUid uid, SalvageExpeditionComponent comp // Finish mission if (TryComp(component.Station, out var data)) { - FinishExpedition(data, uid, component, component.Station); // Frontier: null expedition, SalvageExpeditionComponent expeditionComp, EntityUid uid) { - component.NextOffer = _timing.CurTime + TimeSpan.FromSeconds(_cooldown); - Announce(uid, Loc.GetString("salvage-expedition-mission-completed")); - // Finish mission cleanup. - switch (expedition.MissionParams.MissionType) - { - // Handles the mining taxation. - case SalvageMissionType.Mining: - expedition.Completed = true; - - if (shuttle != null && TryComp(uid, out var mining)) - { - var xformQuery = GetEntityQuery(); - var entities = new List(); - MiningTax(entities, shuttle.Value, mining, xformQuery); - - var tax = GetMiningTax(expedition.MissionParams.Difficulty); - _random.Shuffle(entities); - - // TODO: urgh this pr is already taking so long I'll do this later - for (var i = 0; i < Math.Ceiling(entities.Count * tax); i++) - { - // QueueDel(entities[i]); - } - } - - break; - } - - // Handle payout after expedition has finished - if (expedition.Completed) + var component = expedition.Comp; + // Frontier: separate timeout/announcement for success/failures + if (expeditionComp.Completed) { - Log.Debug($"Completed mission {expedition.MissionParams.MissionType} with seed {expedition.MissionParams.Seed}"); component.NextOffer = _timing.CurTime + TimeSpan.FromSeconds(_cooldown); + component.CooldownTime = TimeSpan.FromSeconds(_cooldown); Announce(uid, Loc.GetString("salvage-expedition-mission-completed")); - GiveRewards(expedition); } else { - Log.Debug($"Failed mission {expedition.MissionParams.MissionType} with seed {expedition.MissionParams.Seed}"); component.NextOffer = _timing.CurTime + TimeSpan.FromSeconds(_failedCooldown); + component.CooldownTime = TimeSpan.FromSeconds(_failedCooldown); Announce(uid, Loc.GetString("salvage-expedition-mission-failed")); } - - + // End Frontier: separate timeout/announcement for success/failures component.ActiveMission = 0; component.Cooldown = true; - if (shuttle != null) // Frontier - UpdateConsoles(shuttle.Value, component); // Frontier - } - - /// - /// Deducts ore tax for mining. - /// - private void MiningTax(List entities, EntityUid entity, SalvageMiningExpeditionComponent mining, EntityQuery xformQuery) - { - if (!mining.ExemptEntities.Contains(entity)) - { - entities.Add(entity); - } - - var xform = xformQuery.GetComponent(entity); - var children = xform.ChildEnumerator; - - while (children.MoveNext(out var child)) - { - MiningTax(entities, child, mining, xformQuery); - } + UpdateConsoles(expedition); } private void GenerateMissions(SalvageExpeditionDataComponent component) { component.Missions.Clear(); - var configs = Enum.GetValues().ToList(); - // Temporarily removed coz it SUCKS - configs.Remove(SalvageMissionType.Mining); + // Frontier: generate missions from an arbitrary set of difficulties + if (_missionDifficulties.Count <= 0) + { + Log.Error("No expedition mission difficulties to pick from!"); + return; + } // this doesn't support having more missions than types of ratings // but the previous system didn't do that either. var allDifficulties = _missionDifficulties; // Frontier: Enum.GetValues() < _missionDifficulties _random.Shuffle(allDifficulties); var difficulties = allDifficulties.Take(MissionLimit).ToList(); - // difficulties.Sort(); // Frontier: sort later - // Frontier: multiple missions per difficulty // If we support more missions than there are accepted types, pick more until you're up to MissionLimit while (difficulties.Count < MissionLimit) { var difficultyIndex = _random.Next(_missionDifficulties.Count); difficulties.Add(_missionDifficulties[difficultyIndex]); } - difficulties.Sort(); - // End Frontier: multiple missions per difficulty - - if (configs.Count == 0) - return; + difficulties.Sort((x, y) => { return Comparer.Default.Compare(x.value, y.value); }); for (var i = 0; i < MissionLimit; i++) { - _random.Shuffle(configs); - var rating = difficulties[i]; - - foreach (var config in configs) + var mission = new SalvageMissionParams { - var mission = new SalvageMissionParams - { - Index = component.NextIndex, - MissionType = config, - Seed = _random.Next(), - Difficulty = rating, - }; - - component.Missions[component.NextIndex++] = mission; - break; - } + Index = component.NextIndex, + MissionType = (SalvageMissionType)_random.NextByte((byte)SalvageMissionType.Max + 1), // Frontier + Seed = _random.Next(), + Difficulty = difficulties[i].id, + }; + + component.Missions[component.NextIndex++] = mission; } + // End Frontier: generate missions from an arbitrary set of difficulties } private SalvageExpeditionConsoleState GetState(SalvageExpeditionDataComponent component) { var missions = component.Missions.Values.ToList(); - //return new SalvageExpeditionConsoleState(component.NextOffer, component.Claimed, component.Cooldown, component.ActiveMission, missions); - return new SalvageExpeditionConsoleState(component.NextOffer, component.Claimed, component.Cooldown, component.CanFinish, component.ActiveMission, missions); // Frontier + return new SalvageExpeditionConsoleState(component.NextOffer, component.Claimed, component.Cooldown, component.ActiveMission, missions, component.CanFinish, component.CooldownTime); // Frontier: add CanFinish, CooldownTime } private void SpawnMission(SalvageMissionParams missionParams, EntityUid station, EntityUid? coordinatesDisk) @@ -317,17 +250,18 @@ private void SpawnMission(SalvageMissionParams missionParams, EntityUid station, SalvageJobTime, EntityManager, _timing, + _logManager, _mapManager, _prototypeManager, _anchorable, _biome, _dungeon, - _shuttle, - _station, _metaData, - this, _transform, _mapSystem, + _station, // Frontier + _shuttle, // Frontier + this, // Frontier station, coordinatesDisk, missionParams, @@ -342,38 +276,27 @@ private void OnStructureExamine(EntityUid uid, SalvageStructureComponent compone args.PushMarkup(Loc.GetString("salvage-expedition-structure-examine")); } - private void GiveRewards(SalvageExpeditionComponent comp) + // Frontier: exped job handling, ghost reparenting + // Handle exped spawn job failures gracefully - reset the console + private void OnExpeditionSpawnComplete(EntityUid uid, SalvageExpeditionDataComponent component, ExpeditionSpawnCompleteEvent ev) { - if (!_cfgManager.GetCVar(NFCCVars.SalvageExpeditionRewardsEnabled)) - return; - - var palletList = new List(); - var pallets = EntityQueryEnumerator(); // Frontier CargoPalletComponent 0)) - return; - - foreach (var reward in comp.Rewards) + if (component.ActiveMission == ev.MissionIndex && !ev.Success) { - Spawn(reward, (Transform(_random.Pick(palletList)).MapPosition)); + component.ActiveMission = 0; + component.Cooldown = false; + UpdateConsoles((uid, component)); } } - // Frontier: handle exped spawn job failures gracefully - reset the console - private void OnExpeditionSpawnComplete(EntityUid uid, SalvageExpeditionDataComponent component, ExpeditionSpawnCompleteEvent ev) + // Send all ghosts (relevant for admins) back to the default map so they don't lose their stuff. + private void OnMapTerminating(EntityUid uid, SalvageExpeditionComponent component, EntityTerminatingEvent ev) { - if (component.ActiveMission == ev.MissionIndex && !ev.Success) + var ghosts = EntityQueryEnumerator(); + var newCoords = new MapCoordinates(Vector2.Zero, _gameTicker.DefaultMap); + while (ghosts.MoveNext(out var ghostUid, out _, out var xform)) { - component.ActiveMission = 0; - component.Cooldown = false; - UpdateConsoles(uid, component); + if (xform.MapUid == uid) + _transform.SetMapCoordinates(ghostUid, newCoords); } } // End Frontier diff --git a/Content.Server/Salvage/SalvageSystem.Magnet.cs b/Content.Server/Salvage/SalvageSystem.Magnet.cs index 07014d56920..0e49a495cbb 100644 --- a/Content.Server/Salvage/SalvageSystem.Magnet.cs +++ b/Content.Server/Salvage/SalvageSystem.Magnet.cs @@ -2,19 +2,19 @@ using System.Numerics; using System.Threading.Tasks; using Content.Server.Salvage.Magnet; +using Content.Shared.Humanoid; using Content.Shared.Mobs.Components; using Content.Shared.Procedural; using Content.Shared.Radio; using Content.Shared.Salvage.Magnet; using Robust.Shared.Exceptions; using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Salvage; public sealed partial class SalvageSystem { - [Dependency] private readonly IRuntimeLog _runtimeLog = default!; - [ValidatePrototypeId] private const string MagnetChannel = "Supply"; @@ -45,19 +45,7 @@ private void OnMagnetClaim(EntityUid uid, SalvageMagnetComponent component, ref return; } - var index = args.Index; - async void TryTakeMagnetOffer() - { - try - { - await TakeMagnetOffer((station.Value, dataComp), index, (uid, component)); - } - catch (Exception e) - { - _runtimeLog.LogException(e, $"{nameof(SalvageSystem)}.{nameof(TakeMagnetOffer)}"); - } - } - TryTakeMagnetOffer(); + TakeMagnetOffer((station.Value, dataComp), args.Index, (uid, component)); } private void OnMagnetStartup(EntityUid uid, SalvageMagnetComponent component, ComponentStartup args) @@ -280,12 +268,12 @@ private async Task TakeMagnetOffer(Entity data, int { case AsteroidOffering asteroid: var grid = _mapManager.CreateGridEntity(salvMap); - await _dungeon.GenerateDungeonAsync(asteroid.DungeonConfig, asteroid.Id, grid.Owner, grid.Comp, Vector2i.Zero, seed); // Frontier: added asteroid.Id - FIXME: value makes no sense. + await _dungeon.GenerateDungeonAsync(asteroid.DungeonConfig, asteroid.Id, grid.Owner, grid.Comp, Vector2i.Zero, seed); // Frontier: add asteroid.Id break; case DebrisOffering debris: var debrisProto = _prototypeManager.Index(debris.Id); var debrisGrid = _mapManager.CreateGridEntity(salvMap); - await _dungeon.GenerateDungeonAsync(debrisProto, debrisProto.ID, debrisGrid.Owner, debrisGrid.Comp, Vector2i.Zero, seed); // Frontier: debrisProto.ID + await _dungeon.GenerateDungeonAsync(debrisProto, debris.Id, debrisGrid.Owner, debrisGrid.Comp, Vector2i.Zero, seed); // Frontier: add debris.Id break; case SalvageOffering wreck: var salvageProto = wreck.SalvageMap; diff --git a/Content.Server/Salvage/SalvageSystem.Runner.cs b/Content.Server/Salvage/SalvageSystem.Runner.cs index 6557898788c..4f563c79806 100644 --- a/Content.Server/Salvage/SalvageSystem.Runner.cs +++ b/Content.Server/Salvage/SalvageSystem.Runner.cs @@ -1,7 +1,5 @@ using System.Numerics; -using Content.Server.GameTicking; using Content.Server.Salvage.Expeditions; -using Content.Server.Salvage.Expeditions.Structure; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; using Content.Server.Station.Components; @@ -10,13 +8,15 @@ using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Salvage.Expeditions; -using Robust.Shared.Map; using Content.Shared.Shuttles.Components; using Content.Shared.Localizations; using Robust.Shared.Map.Components; using Robust.Shared.Player; -using Robust.Shared.Utility; -using Content.Shared.Coordinates; +using Robust.Shared.Map; // Frontier +using Content.Server.GameTicking; // Frontier +using Content.Server._NF.Salvage.Expeditions.Structure; // Frontier +using Content.Server._NF.Salvage.Expeditions; +using Content.Shared.Salvage; // Frontier namespace Content.Server.Salvage; @@ -27,7 +27,8 @@ public sealed partial class SalvageSystem */ [Dependency] private readonly MobStateSystem _mobState = default!; - [Dependency] private readonly GameTicker _gameTicker = default!; + [Dependency] private readonly GameTicker _gameTicker = default!; // Frontier + private void InitializeRunner() { SubscribeLocalEvent(OnFTLRequest); @@ -47,7 +48,7 @@ private void OnConsoleFTLAttempt(ref ConsoleFTLAttemptEvent ev) // TODO: This is terrible but need bluespace harnesses or something. var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var _, out var mobState, out var mobXform)) + while (query.MoveNext(out var uid, out _, out var mobState, out var mobXform)) { if (mobXform.MapUid != xform.MapUid) continue; @@ -103,17 +104,17 @@ private void OnFTLCompleted(ref FTLCompletedEvent args) if (!TryComp(args.MapUid, out var component)) return; - // Frontier + // Someone FTLd there so start announcement + if (component.Stage != ExpeditionStage.Added) + return; + + // Frontier: early finish if (TryComp(component.Station, out var data)) { data.CanFinish = true; - UpdateConsoles(component.Station, data); + UpdateConsoles((component.Station, data)); } - // Frontier - - // Someone FTLd there so start announcement - if (component.Stage != ExpeditionStage.Added) - return; + // End Frontier: early finish Announce(args.MapUid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", (component.EndTime - _timing.CurTime).Minutes))); @@ -122,23 +123,46 @@ private void OnFTLCompleted(ref FTLCompletedEvent args) if (component.DungeonLocation != Vector2.Zero) Announce(args.MapUid, Loc.GetString("salvage-expedition-announcement-dungeon", ("direction", directionLocalization))); + // Frontier: type-specific announcement + switch (component.MissionParams.MissionType) + { + case SalvageMissionType.Destruction: + if (TryComp(args.MapUid, out var destruction) + && destruction.Structures.Count > 0 + && TryComp(destruction.Structures[0], out MetaDataComponent? structureMeta) + && structureMeta.EntityPrototype != null) + { + var name = structureMeta.EntityPrototype.Name; + if (string.IsNullOrWhiteSpace(name)) + name = Loc.GetString("salvage-expedition-announcement-destruction-entity-fallback"); + // Assuming all structures are of the same type. + Announce(args.MapUid, Loc.GetString("salvage-expedition-announcement-destruction", ("structure", name), ("count", destruction.Structures.Count))); + } + break; + case SalvageMissionType.Elimination: + if (TryComp(args.MapUid, out var elimination) + && elimination.Megafauna.Count > 0 + && TryComp(elimination.Megafauna[0], out MetaDataComponent? targetMeta) + && targetMeta.EntityPrototype != null) + { + var name = targetMeta.EntityPrototype.Name; + if (string.IsNullOrWhiteSpace(name)) + name = Loc.GetString("salvage-expedition-announcement-elimination-entity-fallback"); + // Assuming all megafauna are of the same type. + Announce(args.MapUid, Loc.GetString("salvage-expedition-announcement-elimination", ("target", name), ("count", elimination.Megafauna.Count))); + } + break; + default: + break; // No announcement + } + // End Frontier + component.Stage = ExpeditionStage.Running; Dirty(args.MapUid, component); } private void OnFTLStarted(ref FTLStartedEvent ev) { - // Started a mining mission so work out exempt entities - if (TryComp( - _mapManager.GetMapEntityId(ev.TargetCoordinates.ToMap(EntityManager, _transform).MapId), - out var mining)) - { - var ents = new List(); - var xformQuery = GetEntityQuery(); - MiningTax(ents, ev.Entity, mining, xformQuery); - mining.ExemptEntities = ents; - } - if (!TryComp(ev.FromMapUid, out var expedition) || !TryComp(expedition.Station, out var station)) { @@ -201,7 +225,7 @@ private void UpdateRunner() Dirty(uid, comp); Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", audioLength.Minutes))); } - else if (comp.Stage < ExpeditionStage.Countdown && remaining < TimeSpan.FromMinutes(5)) + else if (comp.Stage < ExpeditionStage.Countdown && remaining < TimeSpan.FromMinutes(5)) // Frontier: 4<5 { comp.Stage = ExpeditionStage.Countdown; Dirty(uid, comp); @@ -272,8 +296,9 @@ private void UpdateRunner() dropLocation = _random.NextVector2(minRange, maxRange); } - _shuttle.FTLToCoordinates(shuttleUid, shuttle, new EntityCoordinates(mapUid.Value, dropLocation), 0f, 5.5f, 50f); + _shuttle.FTLToCoordinates(shuttleUid, shuttle, new EntityCoordinates(mapUid.Value, dropLocation), 0f, ftlTime, TravelTime); // End Frontier: try to find a potential destination for ship that doesn't collide with other grids. + //_shuttle.FTLToDock(shuttleUid, shuttle, member, ftlTime); // Frontier: use above instead } break; @@ -292,10 +317,9 @@ private void UpdateRunner() } } - // Mining missions: NOOP since it's handled after ftling - - // Structure missions - var structureQuery = EntityQueryEnumerator(); + // Frontier: mission-specific logic + // Destruction + var structureQuery = EntityQueryEnumerator(); while (structureQuery.MoveNext(out var uid, out var structure, out var comp)) { @@ -304,21 +328,19 @@ private void UpdateRunner() var structureAnnounce = false; - for (var i = 0; i < structure.Structures.Count; i++) + for (var i = structure.Structures.Count - 1; i >= 0; i--) { var objective = structure.Structures[i]; if (Deleted(objective)) { - structure.Structures.RemoveSwap(i); + structure.Structures.RemoveAt(i); structureAnnounce = true; } } if (structureAnnounce) - { Announce(uid, Loc.GetString("salvage-expedition-structure-remaining", ("count", structure.Structures.Count))); - } if (structure.Structures.Count == 0) { @@ -327,7 +349,7 @@ private void UpdateRunner() } } - // Elimination missions + // Elimination var eliminationQuery = EntityQueryEnumerator(); while (eliminationQuery.MoveNext(out var uid, out var elimination, out var comp)) { @@ -336,21 +358,19 @@ private void UpdateRunner() var announce = false; - for (var i = 0; i < elimination.Megafauna.Count; i++) + for (var i = elimination.Megafauna.Count - 1; i >= 0; i--) { var mob = elimination.Megafauna[i]; if (Deleted(mob) || _mobState.IsDead(mob)) { - elimination.Megafauna.RemoveSwap(i); + elimination.Megafauna.RemoveAt(i); announce = true; } } if (announce) - { Announce(uid, Loc.GetString("salvage-expedition-megafauna-remaining", ("count", elimination.Megafauna.Count))); - } if (elimination.Megafauna.Count == 0) { @@ -358,5 +378,6 @@ private void UpdateRunner() Announce(uid, Loc.GetString("salvage-expedition-completed")); } } + // End Frontier: mission-specific logic } } diff --git a/Content.Server/Salvage/SalvageSystem.cs b/Content.Server/Salvage/SalvageSystem.cs index f478723fd86..3bd11fcbf59 100644 --- a/Content.Server/Salvage/SalvageSystem.cs +++ b/Content.Server/Salvage/SalvageSystem.cs @@ -24,6 +24,7 @@ public sealed partial class SalvageSystem : SharedSalvageSystem { [Dependency] private readonly IChatManager _chat = default!; [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly ILogManager _logManager = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _random = default!; @@ -57,14 +58,6 @@ public override void Initialize() InitializeRunner(); } - // Frontier - public override void Shutdown() - { - ShutdownExpeditions(); - base.Shutdown(); - } - // End Frontier - private void Report(EntityUid source, string channelName, string messageKey, params (string, object)[] args) { var message = args.Length == 0 ? Loc.GetString(messageKey) : Loc.GetString(messageKey, args); diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index 8d56072d2ef..d981d380eec 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -1,8 +1,8 @@ +using System.Collections; using System.Linq; using System.Numerics; using System.Threading; using System.Threading.Tasks; -using Content.Server._NF.Salvage; // Frontier: job complete event using Content.Server.Atmos; using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; @@ -12,10 +12,6 @@ using Content.Server.Procedural; using Content.Server.Salvage.Expeditions; using Content.Server.Salvage.Expeditions.Structure; -using Content.Server.Shuttles.Components; -using Content.Server.Shuttles.Systems; -using Content.Server.Station.Components; -using Content.Server.Station.Systems; using Content.Shared.Atmos; using Content.Shared.Construction.EntitySystems; using Content.Shared.Dataset; @@ -24,11 +20,13 @@ using Content.Shared.Physics; using Content.Shared.Procedural; using Content.Shared.Procedural.Loot; +using Content.Shared.Random; using Content.Shared.Salvage; using Content.Shared.Salvage.Expeditions; using Content.Shared.Salvage.Expeditions.Modifiers; using Content.Shared.Shuttles.Components; using Content.Shared.Storage; +using Robust.Shared.Collections; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; @@ -37,6 +35,13 @@ using Robust.Shared.Timing; using Robust.Shared.GameObjects; using Content.Shared._Crescent.SpaceBiomes; +using Robust.Shared.Utility; +using Content.Server.Shuttles.Components; +using Content.Server._NF.Salvage.Expeditions; // Frontier +using Content.Server.Station.Components; // Frontier +using Content.Server.Station.Systems; // Frontier +using Content.Server.Shuttles.Systems; +using Content.Server._NF.Salvage.Expeditions.Structure; // Frontier namespace Content.Server.Salvage; @@ -50,20 +55,23 @@ public sealed class SpawnSalvageMissionJob : Job private readonly BiomeSystem _biome; private readonly DungeonSystem _dungeon; private readonly MetaDataSystem _metaData; - private readonly ShuttleSystem _shuttle; - private readonly StationSystem _stationSystem; - private readonly SalvageSystem _salvage; private readonly SharedTransformSystem _xforms; private readonly SharedMapSystem _map; + private readonly StationSystem _station; // Frontier + private readonly ShuttleSystem _shuttle; // Frontier + private readonly SalvageSystem _salvage; // Frontier public readonly EntityUid Station; public readonly EntityUid? CoordinatesDisk; private readonly SalvageMissionParams _missionParams; + private readonly ISawmill _sawmill; + // Frontier: Used for saving state between async job -#pragma warning disable IDE1006 // suppressing _ prefix complaints to reduce merge conflict area +#pragma warning disable IDE1006 // suppressing prefix warnings to reduce merge conflict area private EntityUid mapUid = EntityUid.Invalid; #pragma warning restore IDE1006 + private static readonly ProtoId FallbackDifficulty = "NFModerate"; // End Frontier // Mono @@ -77,17 +85,18 @@ public SpawnSalvageMissionJob( double maxTime, IEntityManager entManager, IGameTiming timing, + ILogManager logManager, IMapManager mapManager, IPrototypeManager protoManager, AnchorableSystem anchorable, BiomeSystem biome, DungeonSystem dungeon, - ShuttleSystem shuttle, - StationSystem stationSystem, MetaDataSystem metaData, - SalvageSystem salvage, SharedTransformSystem xform, SharedMapSystem map, + StationSystem stationSystem, // Frontier + ShuttleSystem shuttleSystem, // Frontier + SalvageSystem salvageSystem, // Frontier EntityUid station, EntityUid? coordinatesDisk, SalvageMissionParams missionParams, @@ -100,15 +109,19 @@ public SpawnSalvageMissionJob( _anchorable = anchorable; _biome = biome; _dungeon = dungeon; - _shuttle = shuttle; - _stationSystem = stationSystem; _metaData = metaData; - _salvage = salvage; _xforms = xform; _map = map; + _station = stationSystem; // Frontier + _shuttle = shuttleSystem; // Frontier + _salvage = salvageSystem; // Frontier Station = station; CoordinatesDisk = coordinatesDisk; _missionParams = missionParams; + _sawmill = logManager.GetSawmill("salvage_job"); +#if !DEBUG + _sawmill.Level = LogLevel.Info; +#endif } protected override async Task Process() @@ -125,7 +138,7 @@ protected override async Task Process() ExpeditionSpawnCompleteEvent ev = new(Station, success, _missionParams.Index); _entManager.EventBus.RaiseLocalEvent(Station, ev); if (errorStackTrace != null) - Logger.ErrorS("salvage", $"Expedition generation failed with exception: {errorStackTrace}!"); + _sawmill.Error("salvage", $"Expedition generation failed with exception: {errorStackTrace}!"); if (!success) { // Invalidate station, expedition cancellation will be handled by task handler @@ -141,9 +154,8 @@ protected override async Task Process() private async Task InternalProcess() // Frontier: make process an internal function (for a try block indenting an entire), add "out EntityUid mapUid" param { - Logger.DebugS("salvage", $"Spawning salvage mission with seed {_missionParams.Seed}"); - var config = _missionParams.MissionType; - mapUid = _map.CreateMap(out var mapId, runMapInit: false); // Frontier: remove "var" + _sawmill.Debug("salvage", $"Spawning salvage mission with seed {_missionParams.Seed}"); + mapUid = _map.CreateMap(out var mapId, runMapInit: false); // Frontier: remove var MetaDataComponent? metadata = null; var grid = _entManager.EnsureComponent(mapUid); var random = new Random(_missionParams.Seed); @@ -166,16 +178,19 @@ private async Task InternalProcess() // Frontier: make process an internal // Setup mission configs // As we go through the config the rating will deplete so we'll go for most important to least important. + // Frontier: custom difficulty + if (!_prototypeManager.TryIndex(_missionParams.Difficulty, out var difficultyProto)) + difficultyProto = _prototypeManager.Index(FallbackDifficulty); + // End Frontier var mission = _entManager.System() - .GetMission(_missionParams.MissionType, _missionParams.Difficulty, _missionParams.Seed); + .GetMission(_missionParams.MissionType, difficultyProto, _missionParams.Seed); // Frontier: add MissionType - var missionBiome = _prototypeManager.Index(mission.Biome); - BiomeComponent? biome = null; + var missionBiome = _prototypeManager.Index(mission.Biome); if (missionBiome.BiomePrototype != null) { - biome = _entManager.AddComponent(mapUid); + var biome = _entManager.AddComponent(mapUid); var biomeSystem = _entManager.System(); biomeSystem.SetTemplate(mapUid, biome, _prototypeManager.Index(missionBiome.BiomePrototype)); biomeSystem.SetSeed(mapUid, biome, mission.Seed); @@ -211,23 +226,6 @@ private async Task InternalProcess() // Frontier: make process an internal expedition.Station = Station; expedition.EndTime = _timing.CurTime + mission.Duration; expedition.MissionParams = _missionParams; - expedition.Difficulty = _missionParams.Difficulty; - expedition.Rewards = mission.Rewards; - - // On Frontier, we cant share our locations it breaks ftl in a bad bad way - // Don't want consoles to have the incorrect name until refreshed. - /*var ftlUid = _entManager.CreateEntityUninitialized("FTLPoint", new EntityCoordinates(mapUid, grid.TileSizeHalfVector)); - _metaData.SetEntityName(ftlUid, SharedSalvageSystem.GetFTLName(_prototypeManager.Index("NamesBorer"), _missionParams.Seed)); - _entManager.InitializeAndStartEntity(ftlUid);*/ - - // so we just gunna yeet them there instead why not. they chose this life. - /*var stationData = _entManager.GetComponent(Station); - var shuttleUid = _stationSystem.GetLargestGrid(stationData); - if (shuttleUid is { Valid : true } vesselUid) - { - var shuttle = _entManager.GetComponent(vesselUid); - _shuttle.FTLToCoordinates(vesselUid, shuttle, new EntityCoordinates(mapUid, Vector2.Zero), 0f, 5.5f, 50f); - }*/ var landingPadRadius = 4; // Frontier: 24<4 - using this as a margin (4-16), not a radius var minDungeonOffset = landingPadRadius + 4; @@ -235,32 +233,29 @@ private async Task InternalProcess() // Frontier: make process an internal // We'll use the dungeon rotation as the spawn angle var dungeonRotation = _dungeon.GetDungeonRotation(_missionParams.Seed); - Dungeon dungeon = default!; // Frontier: explicitly type as Dungeon + var maxDungeonOffset = minDungeonOffset + 12; + var dungeonOffsetDistance = minDungeonOffset + (maxDungeonOffset - minDungeonOffset) * random.NextFloat(); + var dungeonOffset = new Vector2(0f, dungeonOffsetDistance); + dungeonOffset = dungeonRotation.RotateVec(dungeonOffset); + var dungeonMod = _prototypeManager.Index(mission.Dungeon); + var dungeonConfig = _prototypeManager.Index(dungeonMod.Proto); + var dungeons = await WaitAsyncTask(_dungeon.GenerateDungeonAsync(dungeonConfig, dungeonMod.Proto, mapUid, grid, (Vector2i)dungeonOffset, // Frontier: add dungeonMod.Proto + _missionParams.Seed)); - Vector2 dungeonOffset = new Vector2(); // Frontier: needed for dungeon offset - if (config != SalvageMissionType.Mining) // Frontier: why? - { - var maxDungeonOffset = minDungeonOffset + 12; - var dungeonOffsetDistance = minDungeonOffset + (maxDungeonOffset - minDungeonOffset) * random.NextFloat(); - dungeonOffset = new Vector2(0f, dungeonOffsetDistance); - dungeonOffset = dungeonRotation.RotateVec(dungeonOffset); - var dungeonMod = _prototypeManager.Index(mission.Dungeon); - var dungeonConfig = _prototypeManager.Index(dungeonMod.Proto); - var dungeons = await WaitAsyncTask(_dungeon.GenerateDungeonAsync(dungeonConfig, dungeonConfig.ID, mapUid, grid, (Vector2i) dungeonOffset, // Frontier: add dungeonConfig.ID - _missionParams.Seed)); - - dungeon = dungeons.First(); - - // Aborty - if (dungeon.Rooms.Count == 0) - { - return false; - } + var dungeon = dungeons.First(); - expedition.DungeonLocation = dungeonOffset; + // Aborty + if (dungeon.Rooms.Count == 0) + { + return false; } - // Frontier: get map bounding box + expedition.DungeonLocation = dungeonOffset; + + // Frontier: map generation and offset + #region Frontier map generation + + // Get map bounding box Box2 dungeonBox = new Box2(dungeonOffset, dungeonOffset); foreach (var tile in dungeon.AllTiles) { @@ -269,8 +264,8 @@ private async Task InternalProcess() // Frontier: make process an internal var stationData = _entManager.GetComponent(Station); - // Frontier: get ship bounding box relative to largest grid coords - var shuttleUid = _stationSystem.GetLargestGrid(stationData); + // Get ship bounding box relative to largest grid coords + var shuttleUid = _station.GetLargestGrid(stationData); Box2 shuttleBox = new Box2(); if (shuttleUid is { Valid: true } vesselUid && @@ -279,31 +274,15 @@ private async Task InternalProcess() // Frontier: make process an internal shuttleBox = gridComp.LocalAABB; } - // Frontier: offset ship spawn point from bounding boxes - Vector2 dungeonProjection = new Vector2(dungeonBox.Width * (float) -Math.Sin(dungeonRotation) / 2, dungeonBox.Height * (float) Math.Cos(dungeonRotation) / 2); // Project boxes to get relevant offset for dungeon rotation. - Vector2 shuttleProjection = new Vector2(shuttleBox.Width * (float) -Math.Sin(dungeonRotation) / 2, shuttleBox.Height * (float) Math.Cos(dungeonRotation) / 2); // Note: sine is negative because of CCW rotation (starting north, then west) + // Offset ship spawn point from bounding boxes + float sin = (float)Math.Sin(dungeonRotation); + float cos = (float)Math.Cos(dungeonRotation); + Vector2 dungeonProjection = new Vector2(dungeonBox.Width * -sin / 2, dungeonBox.Height * cos / 2); // Project boxes to get relevant offset for dungeon rotation. + Vector2 shuttleProjection = new Vector2(shuttleBox.Width * -sin / 2, shuttleBox.Height * cos / 2); // Note: sine is negative because of CCW rotation (starting north, then west) Vector2 coords = dungeonBox.Center - dungeonProjection - dungeonOffset - shuttleProjection - shuttleBox.Center; // Coordinates to spawn the ship at to center it with the dungeon's bounding boxes coords = coords.Rounded(); // Ensure grid is aligned to map coords - // Frontier: delay ship FTL - if (shuttleUid is { Valid: true }) - { - var shuttle = _entManager.GetComponent(shuttleUid.Value); - MassAdjustFTLExpedStartup(shuttleUid, out var massStartupTime); - _shuttle.FTLToCoordinates(shuttleUid.Value, shuttle, new EntityCoordinates(mapUid, coords), 0f, massStartupTime, HyperSpaceTime); - } - - List reservedTiles = new(); - - // Frontier: no need for intersecting tiles, we offset the map - - // Vector2 clearBoxCenter = dungeonBox.Center - dungeonProjection - dungeonOffset - shuttleProjection; - // float clearBoxHalfWidth = shuttleBox.Width / 2.0f + 4.0f; - // float clearBoxHalfHeight = shuttleBox.Height / 2.0f + 4.0f; - // Box2 shuttleClearBox = new Box2(clearBoxCenter.X - clearBoxHalfWidth, - // clearBoxCenter.Y - clearBoxHalfHeight, - // clearBoxCenter.X + clearBoxHalfWidth, - // clearBoxCenter.Y + clearBoxHalfHeight); + // List reservedTiles = new(); // foreach (var tile in _map.GetTilesIntersecting(mapUid, grid, new Circle(Vector2.Zero, landingPadRadius), false)) // { @@ -312,32 +291,113 @@ private async Task InternalProcess() // Frontier: make process an internal // reservedTiles.Add(tile.GridIndices); // } - // End Frontier + #endregion Frontier map generation + // End Frontier: map generation and offset - // Mission setup - switch (config) + // Frontier: mission setup + switch (_missionParams.MissionType) { - case SalvageMissionType.Mining: - await SetupMining(mission, mapUid); - break; case SalvageMissionType.Destruction: - await SetupStructure(mission, dungeon, mapUid, grid, random); + await SetupStructure(mission, dungeon, grid, random); break; case SalvageMissionType.Elimination: - await SetupElimination(mission, dungeon, mapUid, grid, random); + await SetupElimination(mission, dungeon, grid, random); break; default: - throw new NotImplementedException(); + _sawmill.Warning($"No setup function for salvage mission type {_missionParams.MissionType}!"); + break; } + // End Frontier: mission setup + + var budgetEntries = new List(); + + /* + * GUARANTEED LOOT + */ - // Handle loot // We'll always add this loot if possible + // mainly used for ore layers. foreach (var lootProto in _prototypeManager.EnumeratePrototypes()) { if (!lootProto.Guaranteed) continue; - await SpawnDungeonLoot(dungeon, missionBiome, lootProto, mapUid, grid, random, reservedTiles); + + await SpawnDungeonLoot(lootProto, mapUid); + } + + // Handle boss loot (when relevant). + + // Handle mob loot. + + // Handle remaining loot + + /* + * MOB SPAWNS + */ + + var mobBudget = difficultyProto.MobBudget; + var faction = _prototypeManager.Index(mission.Faction); + var randomSystem = _entManager.System(); + + foreach (var entry in faction.MobGroups) + { + budgetEntries.Add(entry); + } + + var probSum = budgetEntries.Sum(x => x.Prob); + + while (mobBudget > 0f) + { + var entry = randomSystem.GetBudgetEntry(ref mobBudget, ref probSum, budgetEntries, random); + if (entry == null) + break; + + await SpawnRandomEntry(grid, entry, dungeon, random); + } + + // Frontier: difficulty-based loot tables + var lootTable = difficultyProto.LootTable ?? SharedSalvageSystem.ExpeditionsLootProto; + var allLoot = _prototypeManager.Index(lootTable); + // End Frontier + var lootBudget = difficultyProto.LootBudget; + + foreach (var rule in allLoot.LootRules) + { + switch (rule) + { + case RandomSpawnsLoot randomLoot: + budgetEntries.Clear(); + + foreach (var entry in randomLoot.Entries) + { + budgetEntries.Add(entry); + } + + probSum = budgetEntries.Sum(x => x.Prob); + + while (lootBudget > 0f) + { + var entry = randomSystem.GetBudgetEntry(ref lootBudget, ref probSum, budgetEntries, random); + if (entry == null) + break; + + _sawmill.Debug($"Spawning dungeon loot {entry.Proto}"); + await SpawnRandomEntry(grid, entry, dungeon, random); + } + break; + default: + throw new NotImplementedException(); + } } + + // Frontier: delay ship FTL + if (shuttleUid is { Valid: true }) + { + var shuttle = _entManager.GetComponent(shuttleUid.Value); + _shuttle.FTLToCoordinates(shuttleUid.Value, shuttle, new EntityCoordinates(mapUid, coords), 0f, 5.5f, _salvage.TravelTime); + } + // End Frontier + return true; } @@ -353,7 +413,41 @@ private void MassAdjustFTLExpedStartup(EntityUid? shuttleUid, out float massStar massStartupTime = StartupTime * massMultiplier; } - private async Task SpawnDungeonLoot(Dungeon? dungeon, SalvageBiomeModPrototype biomeMod, SalvageLootPrototype loot, EntityUid gridUid, MapGridComponent grid, Random random, List reservedTiles) + private async Task SpawnRandomEntry(MapGridComponent grid, IBudgetEntry entry, Dungeon dungeon, Random random) + { + await SuspendIfOutOfTime(); + + var availableRooms = new ValueList(dungeon.Rooms); + var availableTiles = new List(); + + while (availableRooms.Count > 0) + { + availableTiles.Clear(); + var roomIndex = random.Next(availableRooms.Count); + var room = availableRooms.RemoveSwap(roomIndex); + availableTiles.AddRange(room.Tiles); + + while (availableTiles.Count > 0) + { + var tile = availableTiles.RemoveSwap(random.Next(availableTiles.Count)); + + if (!_anchorable.TileFree(grid, tile, (int)CollisionGroup.MachineLayer, + (int)CollisionGroup.MachineLayer)) + { + continue; + } + + var uid = _entManager.SpawnAtPosition(entry.Proto, grid.GridTileToLocal(tile)); + _entManager.RemoveComponent(uid); + _entManager.RemoveComponent(uid); + return; + } + } + + // oh noooooooooooo + } + + private async Task SpawnDungeonLoot(SalvageLootPrototype loot, EntityUid gridUid) { for (var i = 0; i < loot.LootRules.Count; i++) { @@ -363,10 +457,9 @@ private async Task SpawnDungeonLoot(Dungeon? dungeon, SalvageBiomeModPrototype b { case BiomeMarkerLoot biomeLoot: { - if (_entManager.TryGetComponent(gridUid, out var biome) && - biomeLoot.Prototype.TryGetValue(biomeMod.ID, out var mod)) + if (_entManager.TryGetComponent(gridUid, out var biome)) { - _biome.AddMarkerLayer(gridUid, biome, mod); + _biome.AddMarkerLayer(gridUid, biome, biomeLoot.Prototype); } } break; @@ -382,61 +475,42 @@ private async Task SpawnDungeonLoot(Dungeon? dungeon, SalvageBiomeModPrototype b } } - #region Mission Specific - - private async Task SetupMining( - SalvageMission mission, - EntityUid gridUid) - { - var faction = _prototypeManager.Index(mission.Faction); - - if (_entManager.TryGetComponent(gridUid, out var biome)) - { - // TODO: Better - for (var i = 0; i < _salvage.GetDifficulty(mission.Difficulty); i++) - { - _biome.AddMarkerLayer(gridUid, biome, faction.Configs["Mining"]); - } - } - } - + // Frontier: mission-specific setup functions private async Task SetupStructure( SalvageMission mission, Dungeon dungeon, - EntityUid gridUid, MapGridComponent grid, Random random) { - var structureComp = _entManager.EnsureComponent(gridUid); - var availableRooms = dungeon.Rooms.ToList(); + await SuspendIfOutOfTime(); + + var structureComp = _entManager.EnsureComponent(mapUid); var faction = _prototypeManager.Index(mission.Faction); - await SpawnMobsRandomRooms(mission, dungeon, faction, grid, random); + var difficulty = _prototypeManager.Index(mission.Difficulty); - var structureCount = _salvage.GetStructureCount(mission.Difficulty); var shaggy = faction.Configs["DefenseStructure"]; - var validSpawns = new List(); - // Spawn the objectives - for (var i = 0; i < structureCount; i++) + var availableRooms = new ValueList(dungeon.Rooms); + var availableTiles = new List(); + + while (availableRooms.Count > 0 && structureComp.Structures.Count < difficulty.DestructionStructures) { - var structureRoom = availableRooms[random.Next(availableRooms.Count)]; - validSpawns.Clear(); - validSpawns.AddRange(structureRoom.Tiles); - random.Shuffle(validSpawns); + availableTiles.Clear(); + var roomIndex = random.Next(availableRooms.Count); + var room = availableRooms.RemoveSwap(roomIndex); + availableTiles.AddRange(room.Tiles); - while (validSpawns.Count > 0) + while (availableTiles.Count > 0) { - var spawnTile = validSpawns[^1]; - validSpawns.RemoveAt(validSpawns.Count - 1); + var tile = availableTiles.RemoveSwap(random.Next(availableTiles.Count)); - if (!_anchorable.TileFree(grid, spawnTile, (int) CollisionGroup.MachineLayer, - (int) CollisionGroup.MachineMask)) // Frontier: MachineLayer(uid); structureComp.Structures.Add(uid); break; @@ -447,84 +521,44 @@ private async Task SetupStructure( private async Task SetupElimination( SalvageMission mission, Dungeon dungeon, - EntityUid gridUid, MapGridComponent grid, Random random) { - // spawn megafauna in a random place - var roomIndex = random.Next(dungeon.Rooms.Count); - var room = dungeon.Rooms[roomIndex]; - var tile = room.Tiles.ElementAt(random.Next(room.Tiles.Count)); - var position = _map.GridTileToLocal(mapUid, grid, tile); + await SuspendIfOutOfTime(); + // spawn megafauna in a random place var faction = _prototypeManager.Index(mission.Faction); var prototype = faction.Configs["Megafauna"]; - var uid = _entManager.SpawnEntity(prototype, position); - // not removing ghost role since its 1 megafauna, expect that you won't be able to cheese it. - var eliminationComp = _entManager.EnsureComponent(gridUid); - eliminationComp.Megafauna.Add(uid); - // spawn less mobs than usual since there's megafauna to deal with too - await SpawnMobsRandomRooms(mission, dungeon, faction, grid, random, 0.5f); - } + var availableRooms = new ValueList(dungeon.Rooms); + var availableTiles = new List(); - private async Task SpawnMobsRandomRooms(SalvageMission mission, Dungeon dungeon, SalvageFactionPrototype faction, MapGridComponent grid, Random random, float scale = 1f) - { - // scale affects how many groups are spawned, not the size of the groups themselves - var groupSpawns = _salvage.GetSpawnCount(mission.Difficulty) * scale; - var groupSum = faction.MobGroups.Sum(o => o.Prob); - var validSpawns = new List(); - - for (var i = 0; i < groupSpawns; i++) + var uid = EntityUid.Invalid; + while (availableRooms.Count > 0 && uid == EntityUid.Invalid) { - var roll = random.NextFloat() * groupSum; - var value = 0f; + availableTiles.Clear(); + var roomIndex = random.Next(availableRooms.Count); + var room = availableRooms.RemoveSwap(roomIndex); + availableTiles.AddRange(room.Tiles); - foreach (var group in faction.MobGroups) + while (availableTiles.Count > 0) { - value += group.Prob; + var tile = availableTiles.RemoveSwap(random.Next(availableTiles.Count)); - if (value < roll) - continue; - - var mobGroupIndex = random.Next(faction.MobGroups.Count); - var mobGroup = faction.MobGroups[mobGroupIndex]; - - var spawnRoomIndex = random.Next(dungeon.Rooms.Count); - var spawnRoom = dungeon.Rooms[spawnRoomIndex]; - validSpawns.Clear(); - validSpawns.AddRange(spawnRoom.Tiles); - random.Shuffle(validSpawns); - - foreach (var entry in EntitySpawnCollection.GetSpawns(mobGroup.Entries, random)) + if (!_anchorable.TileFree(grid, tile, (int)CollisionGroup.MachineLayer, + (int)CollisionGroup.MachineLayer)) { - while (validSpawns.Count > 0) - { - var spawnTile = validSpawns[^1]; - validSpawns.RemoveAt(validSpawns.Count - 1); - - if (!_anchorable.TileFree(grid, spawnTile, (int)CollisionGroup.MachineLayer, - (int)CollisionGroup.MachineLayer)) - { - continue; - } - - var spawnPosition = _map.GridTileToLocal(mapUid, grid, spawnTile); // Frontier: grid<_map - - var uid = _entManager.CreateEntityUninitialized(entry, spawnPosition); - _entManager.RemoveComponent(uid); - _entManager.RemoveComponent(uid); - _entManager.InitializeAndStartEntity(uid); - - break; - } + continue; } - await SuspendIfOutOfTime(); + uid = _entManager.SpawnAtPosition(prototype, _map.GridTileToLocal(mapUid, grid, tile)); break; } } - } - #endregion + var eliminationComp = _entManager.EnsureComponent(mapUid); + if (uid != EntityUid.Invalid) + eliminationComp.Megafauna.Add(uid); + } + // End Frontier: mission-specific setup functions } diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.GridFill.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.GridFill.cs index 084450b79cd..35bbaf904e2 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.GridFill.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.GridFill.cs @@ -118,7 +118,7 @@ private bool TryDungeonSpawn(Entity targetGrid, DungeonSpawnG var spawnedGrid = _mapManager.CreateGridEntity(mapId); _transform.SetMapCoordinates(spawnedGrid, new MapCoordinates(Vector2.Zero, mapId)); - _dungeon.GenerateDungeon(dungeonProto, dungeonProto.ID, spawnedGrid.Owner, spawnedGrid.Comp, Vector2i.Zero, _random.Next(), spawnCoords); // Frontier: add dungeonProto.ID + _dungeon.GenerateDungeon(dungeonProto, dungeonProtoId, spawnedGrid.Owner, spawnedGrid.Comp, Vector2i.Zero, _random.Next(), spawnCoords); // Frontier: add dungeonProtoId spawned = spawnedGrid.Owner; return true; diff --git a/Content.Server/_NF/Salvage/ExpeditionSpawnCompleteEvent.cs b/Content.Server/_NF/Salvage/Expeditions/ExpeditionSpawnCompleteEvent.cs similarity index 91% rename from Content.Server/_NF/Salvage/ExpeditionSpawnCompleteEvent.cs rename to Content.Server/_NF/Salvage/Expeditions/ExpeditionSpawnCompleteEvent.cs index 20582dbbccc..ab8b87c557b 100644 --- a/Content.Server/_NF/Salvage/ExpeditionSpawnCompleteEvent.cs +++ b/Content.Server/_NF/Salvage/Expeditions/ExpeditionSpawnCompleteEvent.cs @@ -1,4 +1,4 @@ -namespace Content.Server._NF.Salvage; +namespace Content.Server._NF.Salvage.Expeditions; /// /// This event is raised when an expedition spawn job has completed (either successfully or in failure), and informs whether the job was successful or not. diff --git a/Content.Server/_NF/Salvage/Expeditions/SalvageDestructionExpeditionComponent.cs b/Content.Server/_NF/Salvage/Expeditions/SalvageDestructionExpeditionComponent.cs new file mode 100644 index 00000000000..804930c1384 --- /dev/null +++ b/Content.Server/_NF/Salvage/Expeditions/SalvageDestructionExpeditionComponent.cs @@ -0,0 +1,17 @@ +using Content.Server.Salvage; +using Content.Shared.Salvage; + +namespace Content.Server._NF.Salvage.Expeditions.Structure; + +/// +/// Tracks expedition data for +/// +[RegisterComponent, Access(typeof(SalvageSystem), typeof(SpawnSalvageMissionJob))] +public sealed partial class SalvageDestructionExpeditionComponent : Component +{ + /// + /// List of structures that need to be destroyed for the mission to be complete. + /// + [DataField] + public List Structures = new(); +} diff --git a/Content.Server/Salvage/Expeditions/SalvageEliminationExpeditionComponent.cs b/Content.Server/_NF/Salvage/Expeditions/SalvageEliminationExpeditionComponent.cs similarity index 82% rename from Content.Server/Salvage/Expeditions/SalvageEliminationExpeditionComponent.cs rename to Content.Server/_NF/Salvage/Expeditions/SalvageEliminationExpeditionComponent.cs index a3ec66ff302..8cb38baef96 100644 --- a/Content.Server/Salvage/Expeditions/SalvageEliminationExpeditionComponent.cs +++ b/Content.Server/_NF/Salvage/Expeditions/SalvageEliminationExpeditionComponent.cs @@ -1,6 +1,7 @@ +using Content.Server.Salvage; using Content.Shared.Salvage; -namespace Content.Server.Salvage.Expeditions.Structure; +namespace Content.Server._NF.Salvage.Expeditions; /// /// Tracks expedition data for @@ -11,6 +12,6 @@ public sealed partial class SalvageEliminationExpeditionComponent : Component /// /// List of mobs that need to be killed for the mission to be complete. /// - [DataField("megafauna")] + [DataField] public List Megafauna = new(); } diff --git a/Content.Server/_NF/StationEvents/Events/BluespaceErrorRule.cs b/Content.Server/_NF/StationEvents/Events/BluespaceErrorRule.cs index cce61f84ca4..880e9a888d3 100644 --- a/Content.Server/_NF/StationEvents/Events/BluespaceErrorRule.cs +++ b/Content.Server/_NF/StationEvents/Events/BluespaceErrorRule.cs @@ -159,7 +159,7 @@ private bool TryDungeonSpawn(EntityCoordinates spawnCoords, BluespaceErrorRuleCo var spawnedGrid = _mapManager.CreateGridEntity(mapId); _transform.SetMapCoordinates(spawnedGrid, new MapCoordinates(Vector2.Zero, mapId)); - _dungeon.GenerateDungeon(dungeonProto, dungeonProto.ID, spawnedGrid.Owner, spawnedGrid.Comp, Vector2i.Zero, _random.Next(), spawnCoords); // Frontier: add dungeonProto.ID + _dungeon.GenerateDungeon(dungeonProto, dungeonProtoId, spawnedGrid.Owner, spawnedGrid.Comp, Vector2i.Zero, _random.Next(), spawnCoords); spawned = spawnedGrid.Owner; component.MapsUid.Add(mapId); diff --git a/Content.Shared/Procedural/DungeonLayers/OreDunGen.cs b/Content.Shared/Procedural/DungeonLayers/OreDunGen.cs index 3c2c4db441b..96b828fd22a 100644 --- a/Content.Shared/Procedural/DungeonLayers/OreDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/OreDunGen.cs @@ -1,4 +1,4 @@ -using Content.Shared.Maps; +using Content.Shared.Maps; // Upstream#33105 using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.DungeonLayers; @@ -12,6 +12,7 @@ namespace Content.Shared.Procedural.DungeonLayers; [Virtual] public partial class OreDunGen : IDunGenLayer { + // Upstream#33105: OreDunGen replacement (Thank you, TheShuEd!) /// /// This vein can only be generated by replacing the specified entities. /// @@ -23,6 +24,7 @@ public partial class OreDunGen : IDunGenLayer /// [DataField] public HashSet>? TileMask; + // End Upstream#33105: OreDunGen replacement (Thank you, TheShuEd!) /// /// Entity to spawn. diff --git a/Content.Shared/Procedural/DungeonPresetPrototype.cs b/Content.Shared/Procedural/DungeonPresetPrototype.cs index ad56104a6ce..e57c4c1d2b7 100644 --- a/Content.Shared/Procedural/DungeonPresetPrototype.cs +++ b/Content.Shared/Procedural/DungeonPresetPrototype.cs @@ -2,7 +2,7 @@ namespace Content.Shared.Procedural; -[Prototype] +[Prototype("dungeonPreset")] public sealed partial class DungeonPresetPrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; diff --git a/Content.Shared/Procedural/DungeonRoomPackPrototype.cs b/Content.Shared/Procedural/DungeonRoomPackPrototype.cs index de83b88b763..8cd129d30a4 100644 --- a/Content.Shared/Procedural/DungeonRoomPackPrototype.cs +++ b/Content.Shared/Procedural/DungeonRoomPackPrototype.cs @@ -2,7 +2,7 @@ namespace Content.Shared.Procedural; -[Prototype] +[Prototype("dungeonRoomPack")] public sealed partial class DungeonRoomPackPrototype : IPrototype { [IdDataField] diff --git a/Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs b/Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs index 600685cab50..2eda4b059c8 100644 --- a/Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs +++ b/Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs @@ -1,4 +1,5 @@ using Content.Shared.Parallax.Biomes.Markers; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; @@ -9,7 +10,6 @@ namespace Content.Shared.Procedural.Loot; /// public sealed partial class BiomeMarkerLoot : IDungeonLoot { - [DataField("proto", required: true, - customTypeSerializer: typeof(PrototypeIdValueDictionarySerializer))] - public Dictionary Prototype = new(); + [DataField("proto", required: true)] + public ProtoId Prototype = new(); } diff --git a/Content.Shared/Procedural/Loot/RandomSpawnsLoot.cs b/Content.Shared/Procedural/Loot/RandomSpawnsLoot.cs new file mode 100644 index 00000000000..e429eed402a --- /dev/null +++ b/Content.Shared/Procedural/Loot/RandomSpawnsLoot.cs @@ -0,0 +1,33 @@ +using Content.Shared.Random; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Procedural.Loot; + +/// +/// Randomly places loot in free areas inside the dungeon. +/// +public sealed partial class RandomSpawnsLoot : IDungeonLoot +{ + [ViewVariables(VVAccess.ReadWrite), DataField("entries", required: true)] + public List Entries = new(); +} + +[DataDefinition] +public partial record struct RandomSpawnLootEntry() : IBudgetEntry +{ + [ViewVariables(VVAccess.ReadWrite), DataField("proto", required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] + public string Proto { get; set; } = string.Empty; + + /// + /// Cost for this loot to spawn. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("cost")] + public float Cost { get; set; } = 1f; + + /// + /// Unit probability for this entry. Weighted against the entire table. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("prob")] + public float Prob { get; set; } = 1f; +} diff --git a/Content.Shared/Procedural/Loot/SalvageLootPrototype.cs b/Content.Shared/Procedural/Loot/SalvageLootPrototype.cs index 5a6a113080c..8189066a4fe 100644 --- a/Content.Shared/Procedural/Loot/SalvageLootPrototype.cs +++ b/Content.Shared/Procedural/Loot/SalvageLootPrototype.cs @@ -1,13 +1,11 @@ -using Content.Shared.Salvage; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.Procedural.Loot; /// /// Spawned inside of a salvage mission. /// -[Prototype] +[Prototype("salvageLoot")] public sealed partial class SalvageLootPrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; @@ -17,14 +15,6 @@ public sealed partial class SalvageLootPrototype : IPrototype /// [DataField("guaranteed")] public bool Guaranteed; - [DataField("desc")] public string Description = string.Empty; - - /// - /// Mission types this loot is not allowed to spawn for - /// - [DataField("blacklist")] - public List Blacklist = new(); - /// /// All of the loot rules /// diff --git a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs index 54b151f9266..1f26e0d9ecb 100644 --- a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs +++ b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs @@ -1,3 +1,4 @@ +using Content.Shared.Procedural.Loot; // Frontier using Robust.Shared.Prototypes; namespace Content.Shared.Procedural; @@ -13,6 +14,15 @@ public sealed partial class SalvageDifficultyPrototype : IPrototype [ViewVariables(VVAccess.ReadWrite), DataField("color")] public Color Color = Color.White; + // Frontier: loot table to use + /// + /// The loot table prototype to use for this difficulty. + /// If none is specified, the system's default will be used. + /// + [DataField] + public ProtoId? LootTable; + // End Frontier + /// /// How much loot this difficulty is allowed to spawn. /// @@ -33,4 +43,12 @@ public sealed partial class SalvageDifficultyPrototype : IPrototype [DataField("recommendedPlayers", required: true)] public int RecommendedPlayers; -} \ No newline at end of file + + // Frontier: mission types + /// + /// The number of structures to spawn on a destruction mission. + /// + [DataField] + public int DestructionStructures = 1; + // End Frontier: mission types +} diff --git a/Content.Shared/Random/IBudgetEntry.cs b/Content.Shared/Random/IBudgetEntry.cs new file mode 100644 index 00000000000..22dc69ed008 --- /dev/null +++ b/Content.Shared/Random/IBudgetEntry.cs @@ -0,0 +1,20 @@ +namespace Content.Shared.Random; + +/// +/// Budgeted random spawn entry. +/// +public interface IBudgetEntry : IProbEntry +{ + float Cost { get; set; } + + string Proto { get; set; } +} + +/// +/// Random entry that has a prob. See +/// +public interface IProbEntry +{ + float Prob { get; set; } +} + diff --git a/Content.Shared/Random/RandomSystem.cs b/Content.Shared/Random/RandomSystem.cs new file mode 100644 index 00000000000..78297e1da56 --- /dev/null +++ b/Content.Shared/Random/RandomSystem.cs @@ -0,0 +1,58 @@ +using Robust.Shared.Random; +using Robust.Shared.Utility; + +namespace Content.Shared.Random; + +public sealed class RandomSystem : EntitySystem +{ + public IBudgetEntry? GetBudgetEntry(ref float budget, ref float probSum, IList entries, System.Random random) + { + DebugTools.Assert(budget > 0f); + + if (entries.Count == 0) + return null; + + // - Pick an entry + // - Remove the cost from budget + // - If our remaining budget is under maxCost then start pruning unavailable entries. + random.Shuffle(entries); + var budgetEntry = (IBudgetEntry) GetProbEntry(entries, probSum, random); + + budget -= budgetEntry.Cost; + + // Prune invalid entries. + for (var i = 0; i < entries.Count; i++) + { + var entry = entries[i]; + + if (entry.Cost < budget) + continue; + + entries.RemoveSwap(i); + i--; + probSum -= entry.Prob; + } + + return budgetEntry; + } + + /// + /// Gets a random entry based on each entry having a different probability. + /// + public IProbEntry GetProbEntry(IEnumerable entries, float probSum, System.Random random) + { + var value = random.NextFloat() * probSum; + + foreach (var entry in entries) + { + value -= entry.Prob; + + if (value < 0f) + { + return entry; + } + } + + throw new InvalidOperationException(); + } +} diff --git a/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeMod.cs b/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeModPrototype.cs similarity index 96% rename from Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeMod.cs rename to Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeModPrototype.cs index e84223ed1fe..908d5830007 100644 --- a/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeMod.cs +++ b/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeModPrototype.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Salvage.Expeditions.Modifiers; /// /// Affects the biome to be used for salvage. /// -[Prototype] +[Prototype("salvageBiomeMod")] public sealed partial class SalvageBiomeModPrototype : IPrototype, ISalvageMod { [IdDataField] public string ID { get; private set; } = default!; diff --git a/Content.Shared/Salvage/Expeditions/Modifiers/SalvageDungeonMod.cs b/Content.Shared/Salvage/Expeditions/Modifiers/SalvageDungeonModPrototype.cs similarity index 100% rename from Content.Shared/Salvage/Expeditions/Modifiers/SalvageDungeonMod.cs rename to Content.Shared/Salvage/Expeditions/Modifiers/SalvageDungeonModPrototype.cs diff --git a/Content.Shared/Salvage/Expeditions/Modifiers/SalvageTimeMod.cs b/Content.Shared/Salvage/Expeditions/Modifiers/SalvageTimeMod.cs deleted file mode 100644 index 87b858f88a1..00000000000 --- a/Content.Shared/Salvage/Expeditions/Modifiers/SalvageTimeMod.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Robust.Shared.Prototypes; - -namespace Content.Shared.Salvage.Expeditions.Modifiers; - -// Frontier: a modifier to manipulate the length of a given salvage expedition -[Prototype("salvageTimeMod")] -public sealed partial class SalvageTimeMod : IPrototype, ISalvageMod -{ - [IdDataField] public string ID { get; private set; } = default!; - - [DataField("desc")] public LocId Description { get; private set; } = string.Empty; - - /// - /// Cost for difficulty modifiers. - /// Frontier: expedition timer min set to 900 and max to 930 - /// - [DataField("cost")] - public float Cost { get; private set; } - - [DataField("minDuration")] - public int MinDuration = 900; - - [DataField("maxDuration")] - public int MaxDuration = 930; - - // Hack: Description isn't nullable - [DataField] - public bool Hidden = true; -} diff --git a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs index c1a2053b26f..eab60c33fd3 100644 --- a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs +++ b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs @@ -1,6 +1,8 @@ +using Content.Shared.Procedural; using Content.Shared.Salvage.Expeditions.Modifiers; using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; @@ -12,18 +14,20 @@ public sealed class SalvageExpeditionConsoleState : BoundUserInterfaceState public TimeSpan NextOffer; public bool Claimed; public bool Cooldown; - public bool CanFinish; // Frontier public ushort ActiveMission; public List Missions; + public bool CanFinish; // Frontier + public TimeSpan CooldownTime; // Frontier: separate fail vs. success time - public SalvageExpeditionConsoleState(TimeSpan nextOffer, bool claimed, bool cooldown, bool canFinish, ushort activeMission, List missions) + public SalvageExpeditionConsoleState(TimeSpan nextOffer, bool claimed, bool cooldown, ushort activeMission, List missions, bool canFinish, TimeSpan cooldownTime) // Frontier: add canFinish, cooldownTime { NextOffer = nextOffer; Claimed = claimed; Cooldown = cooldown; - CanFinish = canFinish; // Frontier ActiveMission = activeMission; Missions = missions; + CanFinish = canFinish; // Frontier + CooldownTime = cooldownTime; // Frontier } } @@ -39,18 +43,19 @@ public sealed partial class SalvageExpeditionConsoleComponent : Component [DataField] public SoundSpecifier PrintSound = new SoundPathSpecifier("/Audio/Machines/terminal_insert_disc.ogg"); + // Frontier: add error to FTL warning /// - /// Frontier: Adding error to the FTL warning - Hard to tell without it - PR 377 + /// The sound made when an error happens. /// [DataField("soundError")] - public SoundSpecifier ErrorSound = - new SoundPathSpecifier("/Audio/Effects/Cargo/buzz_sigh.ogg"); + public SoundSpecifier ErrorSound = new SoundPathSpecifier("/Audio/Effects/Cargo/buzz_sigh.ogg"); /// - /// Frontier: Debug mod + /// Debug mode: skips FTL proximity checks /// [DataField] public bool Debug = false; + // End Frontier: } [Serializable, NetSerializable] @@ -59,8 +64,10 @@ public sealed class ClaimSalvageMessage : BoundUserInterfaceMessage public ushort Index; } -[Serializable, NetSerializable] // Frontier +// Frontier: early expedition finish +[Serializable, NetSerializable] public sealed class FinishSalvageMessage : BoundUserInterfaceMessage; +// End Frontier: early expedition finish /// /// Added per station to store data on their available salvage missions. @@ -80,11 +87,8 @@ public sealed partial class SalvageExpeditionDataComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("cooldown")] public bool Cooldown = false; - /// - /// Frontier - Allow early finish. - /// - [ViewVariables(VVAccess.ReadWrite), DataField] - public bool CanFinish = false; + // Frontier: early expedition finish + // End Frontier: early expedition finish /// /// Nexy time salvage missions are offered. @@ -99,31 +103,34 @@ public sealed partial class SalvageExpeditionDataComponent : Component [ViewVariables] public ushort ActiveMission; public ushort NextIndex = 1; + + // Frontier: early finish, failure vs. success cooldowns + /// + /// Allow early finish. + /// + [ViewVariables(VVAccess.ReadWrite), DataField] + public bool CanFinish = false; + + /// + /// The total cooldown time that we had to wait. + /// + [ViewVariables(VVAccess.ReadWrite), DataField] + public TimeSpan CooldownTime; + // End Frontier: early finish, failure vs. success cooldowns } [Serializable, NetSerializable] -public sealed record SalvageMissionParams : IComparable +public sealed record SalvageMissionParams { [ViewVariables] public ushort Index; - [ViewVariables(VVAccess.ReadWrite)] - public SalvageMissionType MissionType; - [ViewVariables(VVAccess.ReadWrite)] public int Seed; - /// - /// Base difficulty for this mission. - /// - [ViewVariables(VVAccess.ReadWrite)] public DifficultyRating Difficulty; - - public int CompareTo(SalvageMissionParams? other) - { - if (other == null) - return -1; + public string Difficulty = string.Empty; - return Difficulty.CompareTo(other.Difficulty); - } + [ViewVariables(VVAccess.ReadWrite)] // Frontier + public SalvageMissionType MissionType; // Frontier } /// @@ -132,17 +139,16 @@ public int CompareTo(SalvageMissionParams? other) /// public sealed record SalvageMission( int Seed, - DifficultyRating Difficulty, string Dungeon, string Faction, - SalvageMissionType Mission, string Biome, string Air, float Temperature, Color? Color, TimeSpan Duration, - List Rewards, - List Modifiers) + List Modifiers, + ProtoId Difficulty, // Frontier + SalvageMissionType MissionType) // Frontier { /// /// Seed used for the mission. @@ -150,12 +156,7 @@ public sealed record SalvageMission( public readonly int Seed = Seed; /// - /// Difficulty rating. - /// - public DifficultyRating Difficulty = Difficulty; - - /// - /// to be used. + /// to be used. /// public readonly string Dungeon = Dungeon; @@ -164,11 +165,6 @@ public sealed record SalvageMission( /// public readonly string Faction = Faction; - /// - /// Underlying mission params that generated this. - /// - public readonly SalvageMissionType Mission = Mission; - /// /// Biome to be used for the mission. /// @@ -195,14 +191,20 @@ public sealed record SalvageMission( public TimeSpan Duration = Duration; /// - /// The list of items to order on mission completion. + /// Modifiers (outside of the above) applied to the mission. /// - public List Rewards = Rewards; + public List Modifiers = Modifiers; + // Frontier: additional parameters /// - /// Modifiers (outside of the above) applied to the mission. + /// Difficulty rating. /// - public List Modifiers = Modifiers; + public readonly ProtoId Difficulty = Difficulty; + /// + /// Difficulty rating. + /// + public readonly SalvageMissionType MissionType = MissionType; + // End Frontier: additional parameters } [Serializable, NetSerializable] diff --git a/Content.Shared/Salvage/Expeditions/SalvageFactionPrototype.cs b/Content.Shared/Salvage/Expeditions/SalvageFactionPrototype.cs index 13c8dd1fffd..b4178421106 100644 --- a/Content.Shared/Salvage/Expeditions/SalvageFactionPrototype.cs +++ b/Content.Shared/Salvage/Expeditions/SalvageFactionPrototype.cs @@ -1,24 +1,16 @@ -using Content.Shared.Salvage.Expeditions.Modifiers; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; namespace Content.Shared.Salvage.Expeditions; [Prototype("salvageFaction")] -public sealed partial class SalvageFactionPrototype : IPrototype, ISalvageMod +public sealed partial class SalvageFactionPrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; [DataField("desc")] public LocId Description { get; private set; } = string.Empty; - /// - /// Cost for difficulty modifiers. - /// - [DataField("cost")] - public float Cost { get; private set; } = 0f; - - [ViewVariables(VVAccess.ReadWrite), DataField("groups", required: true)] - public List MobGroups = default!; + [ViewVariables(VVAccess.ReadWrite), DataField("entries", required: true)] + public List MobGroups = new(); /// /// Miscellaneous data for factions. diff --git a/Content.Shared/Salvage/Expeditions/SalvageMobEntry.cs b/Content.Shared/Salvage/Expeditions/SalvageMobEntry.cs new file mode 100644 index 00000000000..fcfd865d295 --- /dev/null +++ b/Content.Shared/Salvage/Expeditions/SalvageMobEntry.cs @@ -0,0 +1,24 @@ +using Content.Shared.Random; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Salvage.Expeditions; + +[DataDefinition] +public partial record struct SalvageMobEntry() : IBudgetEntry +{ + /// + /// Cost for this mob in a budget. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("cost")] + public float Cost { get; set; } = 1f; + + /// + /// Probability to spawn this mob. Summed with everything else for the faction. + /// + [ViewVariables(VVAccess.ReadWrite), DataField("prob")] + public float Prob { get; set; } = 1f; + + [ViewVariables(VVAccess.ReadWrite), DataField("proto", required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] + public string Proto { get; set; } = string.Empty; +} diff --git a/Content.Shared/Salvage/Expeditions/SalvageMobGroup.cs b/Content.Shared/Salvage/Expeditions/SalvageMobGroup.cs deleted file mode 100644 index df1917acdcb..00000000000 --- a/Content.Shared/Salvage/Expeditions/SalvageMobGroup.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Content.Shared.Storage; - -namespace Content.Shared.Salvage.Expeditions; - -[DataDefinition] -public partial record struct SalvageMobGroup() -{ - // A mob may be cheap but rare or expensive but frequent. - - /// - /// Probability to spawn this group. Summed with everything else for the faction. - /// - [ViewVariables(VVAccess.ReadWrite), DataField("prob")] - public float Prob = 1f; - - [ViewVariables(VVAccess.ReadWrite), DataField("entries", required: true)] - public List Entries = new(); -} diff --git a/Content.Shared/Salvage/SalvageMapPrototype.cs b/Content.Shared/Salvage/SalvageMapPrototype.cs index e40876e2d10..5f1ef7b1dbf 100644 --- a/Content.Shared/Salvage/SalvageMapPrototype.cs +++ b/Content.Shared/Salvage/SalvageMapPrototype.cs @@ -1,4 +1,3 @@ -using Content.Shared.Salvage.Expeditions.Modifiers; using Robust.Shared.Prototypes; using Robust.Shared.Utility; diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 85b4b999e67..4e5b079630d 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -1,84 +1,30 @@ +using System.Linq; +using Content.Shared.CCVar; using Content.Shared.Dataset; +using Content.Shared.Procedural; +using Content.Shared.Procedural.Loot; using Content.Shared.Random; using Content.Shared.Random.Helpers; using Content.Shared.Salvage.Expeditions; using Content.Shared.Salvage.Expeditions.Modifiers; +using Robust.Shared.Configuration; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization; -using System.Linq; // Frontier +using Robust.Shared.Utility; namespace Content.Shared.Salvage; public abstract partial class SharedSalvageSystem : EntitySystem { - [Dependency] private readonly ILocalizationManager _loc = default!; + [Dependency] protected readonly IConfigurationManager CfgManager = default!; [Dependency] private readonly IPrototypeManager _proto = default!; - #region Descriptions - - public string GetMissionDescription(SalvageMission mission) - { - // Hardcoded in coooooz it's dynamic based on difficulty and I'm lazy. - switch (mission.Mission) - { - case SalvageMissionType.Mining: - // Taxation: , ("tax", $"{GetMiningTax(mission.Difficulty) * 100f:0}") - return Loc.GetString("salvage-expedition-desc-mining"); - case SalvageMissionType.Destruction: - var proto = _proto.Index(mission.Faction).Configs["DefenseStructure"]; - - return Loc.GetString("salvage-expedition-desc-structure", - ("count", GetStructureCount(mission.Difficulty)), - ("structure", _loc.GetEntityData(proto).Name)); - case SalvageMissionType.Elimination: - return Loc.GetString("salvage-expedition-desc-elimination"); - default: - throw new NotImplementedException(); - } - } - - public float GetMiningTax(DifficultyRating baseRating) - { - return 0.6f + (int) baseRating * 0.05f; - } - - /// - /// Gets the amount of structures to destroy. - /// - public int GetStructureCount(DifficultyRating baseRating) - { - return 1 + (int) baseRating * 2; - } - - #endregion - - public int GetDifficulty(DifficultyRating rating) - { - switch (rating) - { - case DifficultyRating.Minimal: - return 4; - case DifficultyRating.Minor: - return 6; - case DifficultyRating.Moderate: - return 8; - case DifficultyRating.Hazardous: - return 10; - case DifficultyRating.Extreme: - return 12; - default: - throw new ArgumentOutOfRangeException(nameof(rating), rating, null); - } - } - /// - /// How many groups of mobs to spawn for a mission. + /// Main loot table for salvage expeditions. /// - public float GetSpawnCount(DifficultyRating difficulty) - { - return ((int)difficulty + 1) * 2; // Frontier: add one to difficulty (no empty expeditions) - } + [ValidatePrototypeId] + public const string ExpeditionsLootProto = "NFSalvageLootModerate"; // Frontier: SalvageLoot(rand, ref rating); - var biome = GetMod(rand, ref rating); - var air = GetBiomeMod(biome.ID, rand, ref rating); - var dungeon = GetBiomeMod(biome.ID, rand, ref rating); + var biome = GetMod(rand, ref modifierBudget); + var light = GetBiomeMod(biome.ID, rand, ref modifierBudget); + var temp = GetBiomeMod(biome.ID, rand, ref modifierBudget); + var air = GetBiomeMod(biome.ID, rand, ref modifierBudget); + var dungeon = GetBiomeMod(biome.ID, rand, ref modifierBudget); + // Frontier: restrict factions per difficulty + // var factionProtos = _proto.EnumeratePrototypes().ToList(); + var factionProtos = _proto.EnumeratePrototypes() + .Where(x => + { + return !x.Configs.TryGetValue("Difficulties", out var difficulties) + || string.IsNullOrWhiteSpace(difficulties) + || difficulties.Split(",").Contains(difficulty.ID.ToString()); + } + ).ToList(); + // End Frontier: difficulties per faction + factionProtos.Sort((x, y) => string.Compare(x.ID, y.ID, StringComparison.Ordinal)); + var faction = factionProtos[rand.Next(factionProtos.Count)]; var mods = new List(); @@ -112,31 +69,19 @@ public SalvageMission GetMission(SalvageMissionType config, DifficultyRating dif } // only show the description if there is an atmosphere since wont matter otherwise - var temp = GetBiomeMod(biome.ID, rand, ref rating); if (temp.Description != string.Empty && !air.Space) { mods.Add(Loc.GetString(temp.Description)); } - var light = GetBiomeMod(biome.ID, rand, ref rating); if (light.Description != string.Empty) { mods.Add(Loc.GetString(light.Description)); } - var time = GetMod(rand, ref rating); - // Round the duration to nearest 15 seconds. - var exactDuration = MathHelper.Lerp(time.MinDuration, time.MaxDuration, rand.NextFloat()); - exactDuration = MathF.Round(exactDuration / 15f) * 15f; - var duration = TimeSpan.FromSeconds(exactDuration); + var duration = TimeSpan.FromSeconds(CfgManager.GetCVar(CCVars.SalvageExpeditionDuration)); - if (!time.Hidden && time.Description != string.Empty) - { - mods.Add(Loc.GetString(time.Description)); - } - - var rewards = GetRewards(difficulty, rand); - return new SalvageMission(seed, difficulty, dungeon.ID, faction.ID, config, biome.ID, air.ID, temp.Temperature, light.Color, duration, rewards, mods); + return new SalvageMission(seed, dungeon.ID, faction.ID, biome.ID, air.ID, temp.Temperature, light.Color, duration, mods, difficulty.ID, config); // Frontier: add difficulty.ID, config } public T GetBiomeMod(string biome, System.Random rand, ref float rating) where T : class, IPrototype, IBiomeSpecificMod @@ -176,76 +121,25 @@ public T GetMod(System.Random rand, ref float rating) where T : class, IProto throw new InvalidOperationException(); } - - private List GetRewards(DifficultyRating difficulty, System.Random rand) - { - var rewards = new List(3); - var ids = RewardsForDifficulty(difficulty); - - foreach (var id in ids) - { - // pick a random reward to give - var weights = _proto.Index(id); - rewards.Add(weights.Pick(rand)); - } - - return rewards; - } - - /// - /// Get a list of WeightedRandomEntityPrototype IDs with the rewards for a certain difficulty. - /// Frontier: added uncommon and legendary reward tiers, limited amount of rewards to 1 per difficulty rating - /// - private string[] RewardsForDifficulty(DifficultyRating rating) - { - var t1 = "ExpeditionRewardT1"; // Frontier - Update tiers - var t2 = "ExpeditionRewardT2"; // Frontier - Update tiers - var t3 = "ExpeditionRewardT3"; // Frontier - Update tiers - var t4 = "ExpeditionRewardT4"; // Frontier - Update tiers - var t5 = "ExpeditionRewardT5"; // Frontier - Update tiers - switch (rating) - { - case DifficultyRating.Minimal: - return new string[] { t1 }; // Frontier - Update tiers // Frontier - case DifficultyRating.Minor: - return new string[] { t2 }; // Frontier - Update tiers // Frontier - case DifficultyRating.Moderate: - return new string[] { t3 }; // Frontier - Update tiers - case DifficultyRating.Hazardous: - return new string[] { t4 }; // Frontier - Update tiers - case DifficultyRating.Extreme: - return new string[] { t5 }; // Frontier - Update tiers - default: - throw new NotImplementedException(); - } - } } +// Frontier: salvage mission type [Serializable, NetSerializable] public enum SalvageMissionType : byte { - /// - /// No dungeon, just ore loot and random mob spawns. - /// - Mining, - /// /// Destroy the specified structures in a dungeon. /// - Destruction, + Destruction = 0, /// /// Kill a large creature in a dungeon. /// - Elimination, -} + Elimination = 1, -[Serializable, NetSerializable] -public enum DifficultyRating : byte -{ - Minimal, - Minor, - Moderate, - Hazardous, - Extreme, + /// + /// Maximum value for random generation, should not be used directly. + /// + Max = Elimination, } +// End Frontier diff --git a/Content.Shared/_NF/CCVar/NFCCVars.cs b/Content.Shared/_NF/CCVar/NFCCVars.cs index fee3e715a50..c0cfa787794 100644 --- a/Content.Shared/_NF/CCVar/NFCCVars.cs +++ b/Content.Shared/_NF/CCVar/NFCCVars.cs @@ -140,13 +140,19 @@ public sealed class NFCCVars /// Cooldown for failed missions. /// public static readonly CVarDef SalvageExpeditionFailedCooldown = - CVarDef.Create("salvage.expedition_failed_cooldown", 450f, CVar.REPLICATED); //Mono 1200->450 + CVarDef.Create("nf14.salvage.expedition_failed_cooldown", 450f, CVar.REPLICATED); //Mono 1200->450 /// - /// Whether salvage expedition rewards is enabled. + /// Transit time in hyperspace in seconds. /// - public static readonly CVarDef SalvageExpeditionRewardsEnabled = - CVarDef.Create("nf14.salvage.expedition_rewards_enabled", false, CVar.REPLICATED); + public static readonly CVarDef SalvageExpeditionTravelTime = + CVarDef.Create("nf14.salvage.expedition_travel_time", 50f, CVar.REPLICATED); + + /// + /// Whether or not to skip the expedition proximity check. + /// + public static readonly CVarDef SalvageExpeditionProximityCheck = + CVarDef.Create("nf14.salvage.expedition_proximity_check", true, CVar.REPLICATED); /* * Smuggling diff --git a/Resources/ConfigPresets/Build/development.toml b/Resources/ConfigPresets/Build/development.toml index 43a8079371c..a3fa1b1fadd 100644 --- a/Resources/ConfigPresets/Build/development.toml +++ b/Resources/ConfigPresets/Build/development.toml @@ -1,6 +1,7 @@ [game] # Straight in-game baby lobbyenabled = false +# Frontier: special map map = "NFDev" role_timers = false current_year_offset = 802 @@ -24,7 +25,8 @@ preload = false [salvage] expedition_cooldown = 30.0 -expedition_failed_cooldown = 10.0 +# Frontier: shorter expeditions +expedition_duration = 180.0 [shuttle] grid_fill = false @@ -36,3 +38,10 @@ shipyard = true [admin] see_own_notes = true + +# Frontier: expedition params +[nf14.salvage] +expedition_failed_cooldown = 10.0 +expedition_travel_time = 5.0 +expedition_proximity_check = false +# End Frontier: expedition params diff --git a/Resources/IgnoredPrototypes/ignoredPrototypes.yml b/Resources/IgnoredPrototypes/ignoredPrototypes.yml index 561620ac53a..5536a5789c4 100644 --- a/Resources/IgnoredPrototypes/ignoredPrototypes.yml +++ b/Resources/IgnoredPrototypes/ignoredPrototypes.yml @@ -11,3 +11,5 @@ - /Prototypes/Procedural/vgroid.yml # Frontier - /Prototypes/Procedural/salvage_loot.yml # Frontier - /Prototypes/Procedural/salvage_rewards.yml # Frontier + - /Prototypes/Procedural/salvage_factions.yml # Frontier + - /Prototypes/Procedural/salvage_difficulties.yml # Frontier diff --git a/Resources/Locale/en-US/_NF/adventure/adventure.ftl b/Resources/Locale/en-US/_NF/adventure/adventure.ftl index f9934c58d08..d7b2901996b 100644 --- a/Resources/Locale/en-US/_NF/adventure/adventure.ftl +++ b/Resources/Locale/en-US/_NF/adventure/adventure.ftl @@ -33,6 +33,8 @@ shipyard-rules-default2 = can and will result in administrative action. Glory to the TSF Security Forces! +shuttle-ftl-proximity = Nearby objects too massive for FTL! +shuttle-ftl-invalid = Invalid ship for FTL! shuttle-ftl-recharge = FTL drives still spooling down! shuttle-ftl-too-many = Too many shuttles already on expedition! diff --git a/Resources/Locale/en-US/_NF/procedural/expeditions.ftl b/Resources/Locale/en-US/_NF/procedural/expeditions.ftl index cbc242978d0..854597f2e35 100644 --- a/Resources/Locale/en-US/_NF/procedural/expeditions.ftl +++ b/Resources/Locale/en-US/_NF/procedural/expeditions.ftl @@ -1,12 +1,23 @@ salvage-expedition-window-finish = Finish expedition salvage-expedition-announcement-early-finish = The expedition was completed ahead of schedule. Shuttle will depart in {$departTime} seconds. +salvage-expedition-announcement-destruction = { $count -> + [1] Destroy the {$structure} before the expedition ends. + *[others] Destroy {$count} {MAKEPLURAL($structure)} before the expedition ends. +} +salvage-expedition-announcement-elimination = { $count -> + [1] Eliminate the {$target} before the expedition ends. + *[others] Eliminate {$count} {MAKEPLURAL($target)} before the expedition ends. +} +salvage-expedition-announcement-destruction-entity-fallback = structure +salvage-expedition-announcement-elimination-entity-fallback = target + salvage-expedition-shuttle-not-found = Cannot locate shuttle. salvage-expedition-not-everyone-aboard = Not all crew aboard! {CAPITALIZE(THE($target))} is still out there! salvage-expedition-ftl-cooldown = The FTL drive is still spooling down from the jump in. Wait for it to cool down before returning. # Salvage mods salvage-time-mod-standard-time = Normal Duration -salvage-time-mod-rush = Rush +salvage-time-mod-rush = Rushs salvage-weather-mod-heavy-snowfall = Heavy Snowfall salvage-weather-mod-rain = Rain @@ -38,4 +49,16 @@ salvage-air-mod-15 = 103 CO2 salvage-air-mod-16 = 34 CO2, 34 NH3, 34 N2O salvage-air-mod-17 = 34 H2O, 34 NH3, 34 N2O salvage-air-mod-18 = 34 H2O, 34 N2O, 17 NH3, 17 CO2 -salvage-air-mod-unknown = Unknown atmosphere \ No newline at end of file +salvage-air-mod-unknown = Unknown atmosphere + +salvage-expedition-difficulty-NFModerate = Moderate +salvage-expedition-difficulty-NFHazardous = Hazardous +salvage-expedition-difficulty-NFExtreme = Extreme + +salvage-expedition-megafauna-remaining = {$count -> + [one] {$count} target remaining. + *[other] {$count} targets remaining. +} + +salvage-expedition-type-Destruction = Destruction +salvage-expedition-type-Elimination = Elimination \ No newline at end of file diff --git a/Resources/Locale/en-US/_NF/procedural/salvage-faction.ftl b/Resources/Locale/en-US/_NF/procedural/salvage-faction.ftl index 591e1d3500a..62257ef018c 100644 --- a/Resources/Locale/en-US/_NF/procedural/salvage-faction.ftl +++ b/Resources/Locale/en-US/_NF/procedural/salvage-faction.ftl @@ -1,11 +1,13 @@ dungeon-boss-grid-warning = Return to the dungeon. -salvage-faction-syndicate = Syndicate -salvage-faction-cultists = Cultists -salvage-faction-flesh = Flesh -salvage-faction-argocytes = Argocytes -salvage-faction-dinosaurs = Dinosaurs -salvage-faction-mercenaries = Mercenaries -salvage-faction-explorers = Explorers -salvage-faction-silicons = Rogue Silicon -salvage-faction-punks = Punks +nf-salvage-faction-xenos = Xenos +nf-salvage-faction-carps = Carp +nf-salvage-faction-syndicate = Syndicate +nf-salvage-faction-cultists = Cultists +nf-salvage-faction-flesh = Flesh +nf-salvage-faction-argocytes = Argocytes +nf-salvage-faction-dinosaurs = Dinosaurs +nf-salvage-faction-mercenaries = Mercenaries +nf-salvage-faction-explorers = Explorers +nf-salvage-faction-silicons = Rogue Silicon +nf-salvage-faction-punks = Punks diff --git a/Resources/Locale/en-US/procedural/expeditions.ftl b/Resources/Locale/en-US/procedural/expeditions.ftl index 6c2222d5068..4b8f92f02f4 100644 --- a/Resources/Locale/en-US/procedural/expeditions.ftl +++ b/Resources/Locale/en-US/procedural/expeditions.ftl @@ -4,9 +4,7 @@ salvage-expedition-structure-remaining = {$count -> *[other] {$count} structures remaining. } -# Frontier: megafauna - [one] Destroy {$count} {$structure}. - *[other] Destroy {$count} {MAKEPLURAL($structure)}. -} -salvage-expedition-desc-elimination = Kill a large and dangerous creature. -# End Frontier +offering-window-claimed = Claimed +offering-window-claim = Claim -salvage-expedition-type-Mining = Mining -salvage-expedition-type-Destruction = Destruction -salvage-expedition-type-Elimination = Elimination +salvage-expedition-window-next = Next offer -salvage-expedition-difficulty-Minimal = Minimal -salvage-expedition-difficulty-Minor = Minor salvage-expedition-difficulty-Moderate = Moderate salvage-expedition-difficulty-Hazardous = Hazardous salvage-expedition-difficulty-Extreme = Extreme +# Frontier: salvagers at least 1 required -# Standard time, no description, no need to show. -- type: salvageTimeMod - id: StandardTime - desc: salvage-time-mod-standard-time - hidden: true - -- type: salvageTimeMod - id: RushTime - desc: salvage-time-mod-rush - minDuration: 630 # Frontier - maxDuration: 840 # Frontier - cost: 1 - # Weather mods - type: salvageWeatherMod id: SnowfallHeavy From 02935732137cdcab9ad60f9ad3fb6639e7d5b866 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sun, 13 Apr 2025 17:03:13 +0100 Subject: [PATCH 04/14] add some error logging to exped generation (#32867) Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Salvage/SpawnSalvageMissionJob.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index d981d380eec..11efe7b9268 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -322,7 +322,14 @@ private async Task InternalProcess() // Frontier: make process an internal if (!lootProto.Guaranteed) continue; - await SpawnDungeonLoot(lootProto, mapUid); + try + { + await SpawnDungeonLoot(lootProto, mapUid); + } + catch (Exception e) + { + _sawmill.Error($"Failed to spawn guaranteed loot {lootProto.ID}: {e}"); + } } // Handle boss loot (when relevant). @@ -352,7 +359,14 @@ private async Task InternalProcess() // Frontier: make process an internal if (entry == null) break; - await SpawnRandomEntry(grid, entry, dungeon, random); + try + { + await SpawnRandomEntry(grid, entry, dungeon, random); + } + catch (Exception e) + { + _sawmill.Error($"Failed to spawn mobs for {entry.Proto}: {e}"); + } } // Frontier: difficulty-based loot tables From 70367af80e8ab632682f6fb9eefaff60467efddc Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Wed, 23 Apr 2025 19:33:30 -0400 Subject: [PATCH 05/14] Cleanup warnings in `SpawnSalvageMissionJob` (#36866) * DoMapInitialize and SetMapPaused * GridTileToLocal * Formatting * Remove unused variables * Update Content.Server/Salvage/SpawnSalvageMissionJob.cs Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../Salvage/SalvageSystem.Expeditions.cs | 2 -- .../Salvage/SpawnSalvageMissionJob.cs | 18 ++++++------------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs index 38bec3df7d6..07bee5376d3 100644 --- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs +++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs @@ -251,13 +251,11 @@ private void SpawnMission(SalvageMissionParams missionParams, EntityUid station, EntityManager, _timing, _logManager, - _mapManager, _prototypeManager, _anchorable, _biome, _dungeon, _metaData, - _transform, _mapSystem, _station, // Frontier _shuttle, // Frontier diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index 11efe7b9268..c1e1a473f98 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -49,13 +49,11 @@ public sealed class SpawnSalvageMissionJob : Job { private readonly IEntityManager _entManager; private readonly IGameTiming _timing; - private readonly IMapManager _mapManager; private readonly IPrototypeManager _prototypeManager; private readonly AnchorableSystem _anchorable; private readonly BiomeSystem _biome; private readonly DungeonSystem _dungeon; private readonly MetaDataSystem _metaData; - private readonly SharedTransformSystem _xforms; private readonly SharedMapSystem _map; private readonly StationSystem _station; // Frontier private readonly ShuttleSystem _shuttle; // Frontier @@ -86,13 +84,11 @@ public SpawnSalvageMissionJob( IEntityManager entManager, IGameTiming timing, ILogManager logManager, - IMapManager mapManager, IPrototypeManager protoManager, AnchorableSystem anchorable, BiomeSystem biome, DungeonSystem dungeon, MetaDataSystem metaData, - SharedTransformSystem xform, SharedMapSystem map, StationSystem stationSystem, // Frontier ShuttleSystem shuttleSystem, // Frontier @@ -104,13 +100,11 @@ public SpawnSalvageMissionJob( { _entManager = entManager; _timing = timing; - _mapManager = mapManager; _prototypeManager = protoManager; _anchorable = anchorable; _biome = biome; _dungeon = dungeon; _metaData = metaData; - _xforms = xform; _map = map; _station = stationSystem; // Frontier _shuttle = shuttleSystem; // Frontier @@ -218,8 +212,8 @@ private async Task InternalProcess() // Frontier: make process an internal } } - _mapManager.DoMapInitialize(mapId); - _mapManager.SetMapPaused(mapId, true); + _map.InitializeMap(mapId); + _map.SetPaused(mapUid, true); // Setup expedition var expedition = _entManager.AddComponent(mapUid); @@ -361,7 +355,7 @@ private async Task InternalProcess() // Frontier: make process an internal try { - await SpawnRandomEntry(grid, entry, dungeon, random); + await SpawnRandomEntry((mapUid, grid), entry, dungeon, random); } catch (Exception e) { @@ -396,7 +390,7 @@ private async Task InternalProcess() // Frontier: make process an internal break; _sawmill.Debug($"Spawning dungeon loot {entry.Proto}"); - await SpawnRandomEntry(grid, entry, dungeon, random); + await SpawnRandomEntry((mapUid, grid), entry, dungeon, random); } break; default: @@ -427,7 +421,7 @@ private void MassAdjustFTLExpedStartup(EntityUid? shuttleUid, out float massStar massStartupTime = StartupTime * massMultiplier; } - private async Task SpawnRandomEntry(MapGridComponent grid, IBudgetEntry entry, Dungeon dungeon, Random random) + private async Task SpawnRandomEntry(Entity grid, IBudgetEntry entry, Dungeon dungeon, Random random) { await SuspendIfOutOfTime(); @@ -451,7 +445,7 @@ private async Task SpawnRandomEntry(MapGridComponent grid, IBudgetEntry entry, D continue; } - var uid = _entManager.SpawnAtPosition(entry.Proto, grid.GridTileToLocal(tile)); + var uid = _entManager.SpawnAtPosition(entry.Proto, _map.GridTileToLocal(grid, grid, tile)); _entManager.RemoveComponent(uid); _entManager.RemoveComponent(uid); return; From b4e41b50a1934cefed898e53d2ba0b5b4283a138 Mon Sep 17 00:00:00 2001 From: Wuffindy Date: Wed, 29 Jul 2026 17:09:26 +0700 Subject: [PATCH 06/14] duration adjustments, it was too fast on everything --- Resources/ConfigPresets/Build/development.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/ConfigPresets/Build/development.toml b/Resources/ConfigPresets/Build/development.toml index a3fa1b1fadd..880a47ce342 100644 --- a/Resources/ConfigPresets/Build/development.toml +++ b/Resources/ConfigPresets/Build/development.toml @@ -24,9 +24,9 @@ grid_splitting = false preload = false [salvage] -expedition_cooldown = 30.0 -# Frontier: shorter expeditions -expedition_duration = 180.0 +expedition_cooldown = 60.0 +# Triad: Base 15m +expedition_duration = 900.0 [shuttle] grid_fill = false @@ -41,7 +41,7 @@ see_own_notes = true # Frontier: expedition params [nf14.salvage] -expedition_failed_cooldown = 10.0 -expedition_travel_time = 5.0 -expedition_proximity_check = false +expedition_failed_cooldown = 180.0 +expedition_travel_time = 30.0 +expedition_proximity_check = true # End Frontier: expedition params From ca120773aa957d27665a4c3946cce79528bf53ed Mon Sep 17 00:00:00 2001 From: Wuffindy Date: Thu, 30 Jul 2026 17:24:59 +0700 Subject: [PATCH 07/14] Readded the old reward code (unclean) --- .../Salvage/Expeditions/SalvageExpeditions.cs | 6 +++ Content.Shared/Salvage/SharedSalvageSystem.cs | 46 ++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs index eab60c33fd3..7687002a913 100644 --- a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs +++ b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs @@ -147,6 +147,7 @@ public sealed record SalvageMission( Color? Color, TimeSpan Duration, List Modifiers, + List Rewards, ProtoId Difficulty, // Frontier SalvageMissionType MissionType) // Frontier { @@ -195,6 +196,11 @@ public sealed record SalvageMission( /// public List Modifiers = Modifiers; + /// + /// The list of items to order on mission completion. + /// + public List Rewards = Rewards; + // Frontier: additional parameters /// /// Difficulty rating. diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 4e5b079630d..5886f1ed52f 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -47,6 +47,7 @@ public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPro var temp = GetBiomeMod(biome.ID, rand, ref modifierBudget); var air = GetBiomeMod(biome.ID, rand, ref modifierBudget); var dungeon = GetBiomeMod(biome.ID, rand, ref modifierBudget); + var rewards = GetRewards(difficulty, rand); // Frontier: restrict factions per difficulty // var factionProtos = _proto.EnumeratePrototypes().ToList(); var factionProtos = _proto.EnumeratePrototypes() @@ -81,7 +82,7 @@ public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPro var duration = TimeSpan.FromSeconds(CfgManager.GetCVar(CCVars.SalvageExpeditionDuration)); - return new SalvageMission(seed, dungeon.ID, faction.ID, biome.ID, air.ID, temp.Temperature, light.Color, duration, mods, difficulty.ID, config); // Frontier: add difficulty.ID, config + return new SalvageMission(seed, dungeon.ID, faction.ID, biome.ID, air.ID, temp.Temperature, light.Color, duration, mods, rewards, difficulty.ID, config); // Triad: add rewards & weather back// Frontier: add difficulty.ID, config } public T GetBiomeMod(string biome, System.Random rand, ref float rating) where T : class, IPrototype, IBiomeSpecificMod @@ -121,6 +122,49 @@ public T GetMod(System.Random rand, ref float rating) where T : class, IProto throw new InvalidOperationException(); } + + private List GetRewards(SalvageDifficultyPrototype difficulty, System.Random rand) + { + var rewards = new List(3); + var ids = difficulty.ID.ToString(); + + foreach (var id in ids) + { + // pick a random reward to give + var weights = _proto.Index(id); + rewards.Add(weights.Pick(rand)); + } + + return rewards; + } + + /// + /// Get a list of WeightedRandomEntityPrototype IDs with the rewards for a certain difficulty. + /// Frontier: added uncommon and legendary reward tiers, limited amount of rewards to 1 per difficulty rating + /// + private string[] RewardsForDifficulty(DifficultyRating rating) + { + var t1 = "ExpeditionRewardT1"; // Frontier - Update tiers + var t2 = "ExpeditionRewardT2"; // Frontier - Update tiers + var t3 = "ExpeditionRewardT3"; // Frontier - Update tiers + var t4 = "ExpeditionRewardT4"; // Frontier - Update tiers + var t5 = "ExpeditionRewardT5"; // Frontier - Update tiers + switch (rating) + { + case DifficultyRating.Minimal: + return new string[] { t1 }; // Frontier - Update tiers + case DifficultyRating.Minor: + return new string[] { t2 }; // Frontier - Update tiers + case DifficultyRating.Moderate: + return new string[] { t3 }; // Frontier - Update tiers + case DifficultyRating.Hazardous: + return new string[] { t4 }; // Frontier - Update tiers + case DifficultyRating.Extreme: + return new string[] { t5 }; // Frontier - Update tiers + default: + throw new NotImplementedException(); + } + } } // Frontier: salvage mission type From f2183fd7bd8847f7858cf9fc067dc3f0820ef691 Mon Sep 17 00:00:00 2001 From: Wuffindy Date: Fri, 31 Jul 2026 17:17:17 +0700 Subject: [PATCH 08/14] adds expeditionReward component to salvage difficulty prototype for easier access to rewards (unadjuste variable type yet) --- .../Procedural/SalvageDifficultyPrototype.cs | 10 ++- Content.Shared/Salvage/SharedSalvageSystem.cs | 72 +++++++++---------- .../_NF/Procedural/salvage_difficulties.yml | 3 + 3 files changed, 47 insertions(+), 38 deletions(-) diff --git a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs index 1f26e0d9ecb..395a6a4377d 100644 --- a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs +++ b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs @@ -26,13 +26,13 @@ public sealed partial class SalvageDifficultyPrototype : IPrototype /// /// How much loot this difficulty is allowed to spawn. /// - [DataField("lootBudget", required : true)] + [DataField("lootBudget", required: true)] public float LootBudget; /// /// How many mobs this difficulty is allowed to spawn. /// - [DataField("mobBudget", required : true)] + [DataField("mobBudget", required: true)] public float MobBudget; /// @@ -51,4 +51,10 @@ public sealed partial class SalvageDifficultyPrototype : IPrototype [DataField] public int DestructionStructures = 1; // End Frontier: mission types + + /// + /// List of entities that will beconsidered as rewards for completing mission. + /// + [DataField("expeditionReward")] + public List Rewards = []; } diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 5886f1ed52f..734eca6d2f9 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -47,7 +47,7 @@ public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPro var temp = GetBiomeMod(biome.ID, rand, ref modifierBudget); var air = GetBiomeMod(biome.ID, rand, ref modifierBudget); var dungeon = GetBiomeMod(biome.ID, rand, ref modifierBudget); - var rewards = GetRewards(difficulty, rand); + var rewards = difficulty.Rewards; // Frontier: restrict factions per difficulty // var factionProtos = _proto.EnumeratePrototypes().ToList(); var factionProtos = _proto.EnumeratePrototypes() @@ -123,48 +123,48 @@ public T GetMod(System.Random rand, ref float rating) where T : class, IProto throw new InvalidOperationException(); } - private List GetRewards(SalvageDifficultyPrototype difficulty, System.Random rand) - { - var rewards = new List(3); - var ids = difficulty.ID.ToString(); + // private List GetRewards(SalvageDifficultyPrototype difficulty, System.Random rand) + // { + // var rewards = new List(3); + // var ids = difficulty.ID.ToString(); - foreach (var id in ids) - { - // pick a random reward to give - var weights = _proto.Index(id); - rewards.Add(weights.Pick(rand)); - } + // foreach (var id in ids) + // { + // // gets the reward in the salvage difficulty prototypes + // var weights = _proto.Index(id); + // rewards.Add(weights.Pick(rand)); + // } - return rewards; - } + // return rewards; + // } /// /// Get a list of WeightedRandomEntityPrototype IDs with the rewards for a certain difficulty. /// Frontier: added uncommon and legendary reward tiers, limited amount of rewards to 1 per difficulty rating /// - private string[] RewardsForDifficulty(DifficultyRating rating) - { - var t1 = "ExpeditionRewardT1"; // Frontier - Update tiers - var t2 = "ExpeditionRewardT2"; // Frontier - Update tiers - var t3 = "ExpeditionRewardT3"; // Frontier - Update tiers - var t4 = "ExpeditionRewardT4"; // Frontier - Update tiers - var t5 = "ExpeditionRewardT5"; // Frontier - Update tiers - switch (rating) - { - case DifficultyRating.Minimal: - return new string[] { t1 }; // Frontier - Update tiers - case DifficultyRating.Minor: - return new string[] { t2 }; // Frontier - Update tiers - case DifficultyRating.Moderate: - return new string[] { t3 }; // Frontier - Update tiers - case DifficultyRating.Hazardous: - return new string[] { t4 }; // Frontier - Update tiers - case DifficultyRating.Extreme: - return new string[] { t5 }; // Frontier - Update tiers - default: - throw new NotImplementedException(); - } - } + // private string[] RewardsForDifficulty(DifficultyRating rating) + // { + // var t1 = "ExpeditionRewardT1"; // Frontier - Update tiers + // var t2 = "ExpeditionRewardT2"; // Frontier - Update tiers + // var t3 = "ExpeditionRewardT3"; // Frontier - Update tiers + // var t4 = "ExpeditionRewardT4"; // Frontier - Update tiers + // var t5 = "ExpeditionRewardT5"; // Frontier - Update tiers + // switch (rating) + // { + // case DifficultyRating.Minimal: + // return new string[] { t1 }; // Frontier - Update tiers + // case DifficultyRating.Minor: + // return new string[] { t2 }; // Frontier - Update tiers + // case DifficultyRating.Moderate: + // return new string[] { t3 }; // Frontier - Update tiers + // case DifficultyRating.Hazardous: + // return new string[] { t4 }; // Frontier - Update tiers + // case DifficultyRating.Extreme: + // return new string[] { t5 }; // Frontier - Update tiers + // default: + // throw new NotImplementedException(); + // } + // } } // Frontier: salvage mission type diff --git a/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml b/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml index a551cda8093..d47bd60a9f0 100644 --- a/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml +++ b/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml @@ -9,6 +9,7 @@ color: "#EFB34196" recommendedPlayers: 2 destructionStructures: 5 + expeditionReward: SpaceCashExpeditionT1 - type: salvageDifficulty id: NFHazardous @@ -19,6 +20,7 @@ color: "#DE3A3A96" recommendedPlayers: 3 destructionStructures: 7 + expeditionReward: SpaceCashExpeditionT1 - type: salvageDifficulty id: NFExtreme @@ -29,3 +31,4 @@ color: "#D381C996" recommendedPlayers: 4 destructionStructures: 9 + expeditionReward: SpaceCashExpeditionT1 From 992ce32c553924c6e15db4c2be4adaac3784465c Mon Sep 17 00:00:00 2001 From: Wuffindy <71980308+Wuffindy@users.noreply.github.com> Date: Sat, 1 Aug 2026 00:10:47 +0700 Subject: [PATCH 09/14] errors regarding prototype, commit for future reference, in case of reverting --- ...vageExpeditionConsoleBoundUserInterface.cs | 16 +++++++ .../Procedural/SalvageDifficultyPrototype.cs | 2 +- .../Salvage/Expeditions/SalvageExpeditions.cs | 4 +- Content.Shared/Salvage/SharedSalvageSystem.cs | 45 +------------------ .../_NF/Procedural/salvage_difficulties.yml | 4 +- 5 files changed, 22 insertions(+), 49 deletions(-) diff --git a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs index 87899d9febf..ff707725f91 100644 --- a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs +++ b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs @@ -173,6 +173,22 @@ string LogAndReturnDefaultBiomDescription(string biome) Margin = new Thickness(0f, 0f, 0f, 5f), }); + // Rewards + offering.AddContent(new Label + { + Text = Loc.GetString("salvage-expedition-window-rewards") + }); + + var rewards = mission.ExpeditionRewards; + + offering.AddContent(new Label + { + Text = string.Join("\n", rewards.Select(o => "- " + o)).TrimEnd(), + FontColorOverride = StyleNano.ConcerningOrangeFore, + HorizontalAlignment = Control.HAlignment.Left, + Margin = new Thickness(0f, 0f, 0f, 5f) + }); + offering.ClaimPressed += args => { SendMessage(new ClaimSalvageMessage() diff --git a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs index 395a6a4377d..e5be996bbcf 100644 --- a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs +++ b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs @@ -56,5 +56,5 @@ public sealed partial class SalvageDifficultyPrototype : IPrototype /// List of entities that will beconsidered as rewards for completing mission. /// [DataField("expeditionReward")] - public List Rewards = []; + public List ExpeditionRewards = []; } diff --git a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs index 7687002a913..4eab587d0e4 100644 --- a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs +++ b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs @@ -147,7 +147,7 @@ public sealed record SalvageMission( Color? Color, TimeSpan Duration, List Modifiers, - List Rewards, + List ExpeditionRewards, ProtoId Difficulty, // Frontier SalvageMissionType MissionType) // Frontier { @@ -199,7 +199,7 @@ public sealed record SalvageMission( /// /// The list of items to order on mission completion. /// - public List Rewards = Rewards; + public List ExpeditionRewards = ExpeditionRewards; // Frontier: additional parameters /// diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 734eca6d2f9..0a6aed578c6 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -47,7 +47,7 @@ public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPro var temp = GetBiomeMod(biome.ID, rand, ref modifierBudget); var air = GetBiomeMod(biome.ID, rand, ref modifierBudget); var dungeon = GetBiomeMod(biome.ID, rand, ref modifierBudget); - var rewards = difficulty.Rewards; + var rewards = difficulty.ExpeditionRewards.Select(x => x.Id).ToList(); // Triad: Simplified the reward to get it from the Salvage Difficulty Prototype // Frontier: restrict factions per difficulty // var factionProtos = _proto.EnumeratePrototypes().ToList(); var factionProtos = _proto.EnumeratePrototypes() @@ -122,49 +122,6 @@ public T GetMod(System.Random rand, ref float rating) where T : class, IProto throw new InvalidOperationException(); } - - // private List GetRewards(SalvageDifficultyPrototype difficulty, System.Random rand) - // { - // var rewards = new List(3); - // var ids = difficulty.ID.ToString(); - - // foreach (var id in ids) - // { - // // gets the reward in the salvage difficulty prototypes - // var weights = _proto.Index(id); - // rewards.Add(weights.Pick(rand)); - // } - - // return rewards; - // } - - /// - /// Get a list of WeightedRandomEntityPrototype IDs with the rewards for a certain difficulty. - /// Frontier: added uncommon and legendary reward tiers, limited amount of rewards to 1 per difficulty rating - /// - // private string[] RewardsForDifficulty(DifficultyRating rating) - // { - // var t1 = "ExpeditionRewardT1"; // Frontier - Update tiers - // var t2 = "ExpeditionRewardT2"; // Frontier - Update tiers - // var t3 = "ExpeditionRewardT3"; // Frontier - Update tiers - // var t4 = "ExpeditionRewardT4"; // Frontier - Update tiers - // var t5 = "ExpeditionRewardT5"; // Frontier - Update tiers - // switch (rating) - // { - // case DifficultyRating.Minimal: - // return new string[] { t1 }; // Frontier - Update tiers - // case DifficultyRating.Minor: - // return new string[] { t2 }; // Frontier - Update tiers - // case DifficultyRating.Moderate: - // return new string[] { t3 }; // Frontier - Update tiers - // case DifficultyRating.Hazardous: - // return new string[] { t4 }; // Frontier - Update tiers - // case DifficultyRating.Extreme: - // return new string[] { t5 }; // Frontier - Update tiers - // default: - // throw new NotImplementedException(); - // } - // } } // Frontier: salvage mission type diff --git a/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml b/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml index d47bd60a9f0..79b6eb31d74 100644 --- a/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml +++ b/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml @@ -20,7 +20,7 @@ color: "#DE3A3A96" recommendedPlayers: 3 destructionStructures: 7 - expeditionReward: SpaceCashExpeditionT1 + expeditionReward: SpaceCashExpeditionT2 - type: salvageDifficulty id: NFExtreme @@ -31,4 +31,4 @@ color: "#D381C996" recommendedPlayers: 4 destructionStructures: 9 - expeditionReward: SpaceCashExpeditionT1 + expeditionReward: SpaceCashExpeditionT3 From c239fbacb9d82a155c7925b7d73211e5d0d0d186 Mon Sep 17 00:00:00 2001 From: Wuffindy Date: Tue, 4 Aug 2026 16:23:45 +0700 Subject: [PATCH 10/14] Revert "errors regarding prototype, commit for future reference, in case of reverting" This reverts commit 992ce32c553924c6e15db4c2be4adaac3784465c. --- ...vageExpeditionConsoleBoundUserInterface.cs | 16 ------- .../Procedural/SalvageDifficultyPrototype.cs | 2 +- .../Salvage/Expeditions/SalvageExpeditions.cs | 4 +- Content.Shared/Salvage/SharedSalvageSystem.cs | 45 ++++++++++++++++++- .../_NF/Procedural/salvage_difficulties.yml | 4 +- 5 files changed, 49 insertions(+), 22 deletions(-) diff --git a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs index ff707725f91..87899d9febf 100644 --- a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs +++ b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs @@ -173,22 +173,6 @@ string LogAndReturnDefaultBiomDescription(string biome) Margin = new Thickness(0f, 0f, 0f, 5f), }); - // Rewards - offering.AddContent(new Label - { - Text = Loc.GetString("salvage-expedition-window-rewards") - }); - - var rewards = mission.ExpeditionRewards; - - offering.AddContent(new Label - { - Text = string.Join("\n", rewards.Select(o => "- " + o)).TrimEnd(), - FontColorOverride = StyleNano.ConcerningOrangeFore, - HorizontalAlignment = Control.HAlignment.Left, - Margin = new Thickness(0f, 0f, 0f, 5f) - }); - offering.ClaimPressed += args => { SendMessage(new ClaimSalvageMessage() diff --git a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs index e5be996bbcf..395a6a4377d 100644 --- a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs +++ b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs @@ -56,5 +56,5 @@ public sealed partial class SalvageDifficultyPrototype : IPrototype /// List of entities that will beconsidered as rewards for completing mission. /// [DataField("expeditionReward")] - public List ExpeditionRewards = []; + public List Rewards = []; } diff --git a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs index 4eab587d0e4..7687002a913 100644 --- a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs +++ b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs @@ -147,7 +147,7 @@ public sealed record SalvageMission( Color? Color, TimeSpan Duration, List Modifiers, - List ExpeditionRewards, + List Rewards, ProtoId Difficulty, // Frontier SalvageMissionType MissionType) // Frontier { @@ -199,7 +199,7 @@ public sealed record SalvageMission( /// /// The list of items to order on mission completion. /// - public List ExpeditionRewards = ExpeditionRewards; + public List Rewards = Rewards; // Frontier: additional parameters /// diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 0a6aed578c6..734eca6d2f9 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -47,7 +47,7 @@ public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPro var temp = GetBiomeMod(biome.ID, rand, ref modifierBudget); var air = GetBiomeMod(biome.ID, rand, ref modifierBudget); var dungeon = GetBiomeMod(biome.ID, rand, ref modifierBudget); - var rewards = difficulty.ExpeditionRewards.Select(x => x.Id).ToList(); // Triad: Simplified the reward to get it from the Salvage Difficulty Prototype + var rewards = difficulty.Rewards; // Frontier: restrict factions per difficulty // var factionProtos = _proto.EnumeratePrototypes().ToList(); var factionProtos = _proto.EnumeratePrototypes() @@ -122,6 +122,49 @@ public T GetMod(System.Random rand, ref float rating) where T : class, IProto throw new InvalidOperationException(); } + + // private List GetRewards(SalvageDifficultyPrototype difficulty, System.Random rand) + // { + // var rewards = new List(3); + // var ids = difficulty.ID.ToString(); + + // foreach (var id in ids) + // { + // // gets the reward in the salvage difficulty prototypes + // var weights = _proto.Index(id); + // rewards.Add(weights.Pick(rand)); + // } + + // return rewards; + // } + + /// + /// Get a list of WeightedRandomEntityPrototype IDs with the rewards for a certain difficulty. + /// Frontier: added uncommon and legendary reward tiers, limited amount of rewards to 1 per difficulty rating + /// + // private string[] RewardsForDifficulty(DifficultyRating rating) + // { + // var t1 = "ExpeditionRewardT1"; // Frontier - Update tiers + // var t2 = "ExpeditionRewardT2"; // Frontier - Update tiers + // var t3 = "ExpeditionRewardT3"; // Frontier - Update tiers + // var t4 = "ExpeditionRewardT4"; // Frontier - Update tiers + // var t5 = "ExpeditionRewardT5"; // Frontier - Update tiers + // switch (rating) + // { + // case DifficultyRating.Minimal: + // return new string[] { t1 }; // Frontier - Update tiers + // case DifficultyRating.Minor: + // return new string[] { t2 }; // Frontier - Update tiers + // case DifficultyRating.Moderate: + // return new string[] { t3 }; // Frontier - Update tiers + // case DifficultyRating.Hazardous: + // return new string[] { t4 }; // Frontier - Update tiers + // case DifficultyRating.Extreme: + // return new string[] { t5 }; // Frontier - Update tiers + // default: + // throw new NotImplementedException(); + // } + // } } // Frontier: salvage mission type diff --git a/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml b/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml index 79b6eb31d74..d47bd60a9f0 100644 --- a/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml +++ b/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml @@ -20,7 +20,7 @@ color: "#DE3A3A96" recommendedPlayers: 3 destructionStructures: 7 - expeditionReward: SpaceCashExpeditionT2 + expeditionReward: SpaceCashExpeditionT1 - type: salvageDifficulty id: NFExtreme @@ -31,4 +31,4 @@ color: "#D381C996" recommendedPlayers: 4 destructionStructures: 9 - expeditionReward: SpaceCashExpeditionT3 + expeditionReward: SpaceCashExpeditionT1 From 6a17f6048950bb7f60a96e41795c085c319332f9 Mon Sep 17 00:00:00 2001 From: Wuffindy Date: Tue, 4 Aug 2026 16:24:22 +0700 Subject: [PATCH 11/14] Revert "adds expeditionReward component to salvage difficulty prototype for easier access to rewards (unadjuste variable type yet)" This reverts commit f2183fd7bd8847f7858cf9fc067dc3f0820ef691. --- .../Procedural/SalvageDifficultyPrototype.cs | 10 +-- Content.Shared/Salvage/SharedSalvageSystem.cs | 72 +++++++++---------- .../_NF/Procedural/salvage_difficulties.yml | 3 - 3 files changed, 38 insertions(+), 47 deletions(-) diff --git a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs index 395a6a4377d..1f26e0d9ecb 100644 --- a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs +++ b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs @@ -26,13 +26,13 @@ public sealed partial class SalvageDifficultyPrototype : IPrototype /// /// How much loot this difficulty is allowed to spawn. /// - [DataField("lootBudget", required: true)] + [DataField("lootBudget", required : true)] public float LootBudget; /// /// How many mobs this difficulty is allowed to spawn. /// - [DataField("mobBudget", required: true)] + [DataField("mobBudget", required : true)] public float MobBudget; /// @@ -51,10 +51,4 @@ public sealed partial class SalvageDifficultyPrototype : IPrototype [DataField] public int DestructionStructures = 1; // End Frontier: mission types - - /// - /// List of entities that will beconsidered as rewards for completing mission. - /// - [DataField("expeditionReward")] - public List Rewards = []; } diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 734eca6d2f9..5886f1ed52f 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -47,7 +47,7 @@ public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPro var temp = GetBiomeMod(biome.ID, rand, ref modifierBudget); var air = GetBiomeMod(biome.ID, rand, ref modifierBudget); var dungeon = GetBiomeMod(biome.ID, rand, ref modifierBudget); - var rewards = difficulty.Rewards; + var rewards = GetRewards(difficulty, rand); // Frontier: restrict factions per difficulty // var factionProtos = _proto.EnumeratePrototypes().ToList(); var factionProtos = _proto.EnumeratePrototypes() @@ -123,48 +123,48 @@ public T GetMod(System.Random rand, ref float rating) where T : class, IProto throw new InvalidOperationException(); } - // private List GetRewards(SalvageDifficultyPrototype difficulty, System.Random rand) - // { - // var rewards = new List(3); - // var ids = difficulty.ID.ToString(); + private List GetRewards(SalvageDifficultyPrototype difficulty, System.Random rand) + { + var rewards = new List(3); + var ids = difficulty.ID.ToString(); - // foreach (var id in ids) - // { - // // gets the reward in the salvage difficulty prototypes - // var weights = _proto.Index(id); - // rewards.Add(weights.Pick(rand)); - // } + foreach (var id in ids) + { + // pick a random reward to give + var weights = _proto.Index(id); + rewards.Add(weights.Pick(rand)); + } - // return rewards; - // } + return rewards; + } /// /// Get a list of WeightedRandomEntityPrototype IDs with the rewards for a certain difficulty. /// Frontier: added uncommon and legendary reward tiers, limited amount of rewards to 1 per difficulty rating /// - // private string[] RewardsForDifficulty(DifficultyRating rating) - // { - // var t1 = "ExpeditionRewardT1"; // Frontier - Update tiers - // var t2 = "ExpeditionRewardT2"; // Frontier - Update tiers - // var t3 = "ExpeditionRewardT3"; // Frontier - Update tiers - // var t4 = "ExpeditionRewardT4"; // Frontier - Update tiers - // var t5 = "ExpeditionRewardT5"; // Frontier - Update tiers - // switch (rating) - // { - // case DifficultyRating.Minimal: - // return new string[] { t1 }; // Frontier - Update tiers - // case DifficultyRating.Minor: - // return new string[] { t2 }; // Frontier - Update tiers - // case DifficultyRating.Moderate: - // return new string[] { t3 }; // Frontier - Update tiers - // case DifficultyRating.Hazardous: - // return new string[] { t4 }; // Frontier - Update tiers - // case DifficultyRating.Extreme: - // return new string[] { t5 }; // Frontier - Update tiers - // default: - // throw new NotImplementedException(); - // } - // } + private string[] RewardsForDifficulty(DifficultyRating rating) + { + var t1 = "ExpeditionRewardT1"; // Frontier - Update tiers + var t2 = "ExpeditionRewardT2"; // Frontier - Update tiers + var t3 = "ExpeditionRewardT3"; // Frontier - Update tiers + var t4 = "ExpeditionRewardT4"; // Frontier - Update tiers + var t5 = "ExpeditionRewardT5"; // Frontier - Update tiers + switch (rating) + { + case DifficultyRating.Minimal: + return new string[] { t1 }; // Frontier - Update tiers + case DifficultyRating.Minor: + return new string[] { t2 }; // Frontier - Update tiers + case DifficultyRating.Moderate: + return new string[] { t3 }; // Frontier - Update tiers + case DifficultyRating.Hazardous: + return new string[] { t4 }; // Frontier - Update tiers + case DifficultyRating.Extreme: + return new string[] { t5 }; // Frontier - Update tiers + default: + throw new NotImplementedException(); + } + } } // Frontier: salvage mission type diff --git a/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml b/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml index d47bd60a9f0..a551cda8093 100644 --- a/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml +++ b/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml @@ -9,7 +9,6 @@ color: "#EFB34196" recommendedPlayers: 2 destructionStructures: 5 - expeditionReward: SpaceCashExpeditionT1 - type: salvageDifficulty id: NFHazardous @@ -20,7 +19,6 @@ color: "#DE3A3A96" recommendedPlayers: 3 destructionStructures: 7 - expeditionReward: SpaceCashExpeditionT1 - type: salvageDifficulty id: NFExtreme @@ -31,4 +29,3 @@ color: "#D381C996" recommendedPlayers: 4 destructionStructures: 9 - expeditionReward: SpaceCashExpeditionT1 From 71c7a67efdb2a49f05d7dfec1b1212fcb0a5e2f3 Mon Sep 17 00:00:00 2001 From: Wuffindy Date: Tue, 4 Aug 2026 16:24:31 +0700 Subject: [PATCH 12/14] Revert "Readded the old reward code (unclean)" This reverts commit ca120773aa957d27665a4c3946cce79528bf53ed. --- .../Salvage/Expeditions/SalvageExpeditions.cs | 6 --- Content.Shared/Salvage/SharedSalvageSystem.cs | 46 +------------------ 2 files changed, 1 insertion(+), 51 deletions(-) diff --git a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs index 7687002a913..eab60c33fd3 100644 --- a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs +++ b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs @@ -147,7 +147,6 @@ public sealed record SalvageMission( Color? Color, TimeSpan Duration, List Modifiers, - List Rewards, ProtoId Difficulty, // Frontier SalvageMissionType MissionType) // Frontier { @@ -196,11 +195,6 @@ public sealed record SalvageMission( /// public List Modifiers = Modifiers; - /// - /// The list of items to order on mission completion. - /// - public List Rewards = Rewards; - // Frontier: additional parameters /// /// Difficulty rating. diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 5886f1ed52f..4e5b079630d 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -47,7 +47,6 @@ public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPro var temp = GetBiomeMod(biome.ID, rand, ref modifierBudget); var air = GetBiomeMod(biome.ID, rand, ref modifierBudget); var dungeon = GetBiomeMod(biome.ID, rand, ref modifierBudget); - var rewards = GetRewards(difficulty, rand); // Frontier: restrict factions per difficulty // var factionProtos = _proto.EnumeratePrototypes().ToList(); var factionProtos = _proto.EnumeratePrototypes() @@ -82,7 +81,7 @@ public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPro var duration = TimeSpan.FromSeconds(CfgManager.GetCVar(CCVars.SalvageExpeditionDuration)); - return new SalvageMission(seed, dungeon.ID, faction.ID, biome.ID, air.ID, temp.Temperature, light.Color, duration, mods, rewards, difficulty.ID, config); // Triad: add rewards & weather back// Frontier: add difficulty.ID, config + return new SalvageMission(seed, dungeon.ID, faction.ID, biome.ID, air.ID, temp.Temperature, light.Color, duration, mods, difficulty.ID, config); // Frontier: add difficulty.ID, config } public T GetBiomeMod(string biome, System.Random rand, ref float rating) where T : class, IPrototype, IBiomeSpecificMod @@ -122,49 +121,6 @@ public T GetMod(System.Random rand, ref float rating) where T : class, IProto throw new InvalidOperationException(); } - - private List GetRewards(SalvageDifficultyPrototype difficulty, System.Random rand) - { - var rewards = new List(3); - var ids = difficulty.ID.ToString(); - - foreach (var id in ids) - { - // pick a random reward to give - var weights = _proto.Index(id); - rewards.Add(weights.Pick(rand)); - } - - return rewards; - } - - /// - /// Get a list of WeightedRandomEntityPrototype IDs with the rewards for a certain difficulty. - /// Frontier: added uncommon and legendary reward tiers, limited amount of rewards to 1 per difficulty rating - /// - private string[] RewardsForDifficulty(DifficultyRating rating) - { - var t1 = "ExpeditionRewardT1"; // Frontier - Update tiers - var t2 = "ExpeditionRewardT2"; // Frontier - Update tiers - var t3 = "ExpeditionRewardT3"; // Frontier - Update tiers - var t4 = "ExpeditionRewardT4"; // Frontier - Update tiers - var t5 = "ExpeditionRewardT5"; // Frontier - Update tiers - switch (rating) - { - case DifficultyRating.Minimal: - return new string[] { t1 }; // Frontier - Update tiers - case DifficultyRating.Minor: - return new string[] { t2 }; // Frontier - Update tiers - case DifficultyRating.Moderate: - return new string[] { t3 }; // Frontier - Update tiers - case DifficultyRating.Hazardous: - return new string[] { t4 }; // Frontier - Update tiers - case DifficultyRating.Extreme: - return new string[] { t5 }; // Frontier - Update tiers - default: - throw new NotImplementedException(); - } - } } // Frontier: salvage mission type From 18415227434f02921c949c8db8973ee97033ec6d Mon Sep 17 00:00:00 2001 From: Wuffindy <71980308+Wuffindy@users.noreply.github.com> Date: Tue, 4 Aug 2026 22:53:08 +0700 Subject: [PATCH 13/14] adding description on difficulty bypass, for future reference --- Content.Shared/Salvage/SharedSalvageSystem.cs | 4 ++-- Resources/Prototypes/_NF/Procedural/salvage_factions.yml | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 4e5b079630d..9798107de73 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -29,7 +29,7 @@ public abstract partial class SharedSalvageSystem : EntitySystem public string GetFTLName(LocalizedDatasetPrototype dataset, int seed) { var random = new System.Random(seed); - return $"{Loc.GetString(dataset.Values[random.Next(dataset.Values.Count)])}-{random.Next(10, 100)}-{(char) (65 + random.Next(26))}"; + return $"{Loc.GetString(dataset.Values[random.Next(dataset.Values.Count)])}-{random.Next(10, 100)}-{(char)(65 + random.Next(26))}"; } public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPrototype difficulty, int seed) // Frontier: add config @@ -47,8 +47,8 @@ public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPro var temp = GetBiomeMod(biome.ID, rand, ref modifierBudget); var air = GetBiomeMod(biome.ID, rand, ref modifierBudget); var dungeon = GetBiomeMod(biome.ID, rand, ref modifierBudget); + // var factionProtos = _proto.EnumeratePrototypes().ToList(); //Triad: older version for all mob all difficulty // Frontier: restrict factions per difficulty - // var factionProtos = _proto.EnumeratePrototypes().ToList(); var factionProtos = _proto.EnumeratePrototypes() .Where(x => { diff --git a/Resources/Prototypes/_NF/Procedural/salvage_factions.yml b/Resources/Prototypes/_NF/Procedural/salvage_factions.yml index 80439547567..bca3420d96a 100644 --- a/Resources/Prototypes/_NF/Procedural/salvage_factions.yml +++ b/Resources/Prototypes/_NF/Procedural/salvage_factions.yml @@ -25,7 +25,7 @@ configs: DefenseStructure: XenoWardingTower Megafauna: NFMobXenoQueen - Difficulties: NFModerate + # Difficulties: NFModerate #Triad commented out so it shows up on all difficulties - type: salvageFaction id: NFCarps @@ -120,8 +120,6 @@ # region Hazardous - - - type: salvageFaction id: NFPunks desc: nf-salvage-faction-punks From 76bd26e3aa350fe40270c94a6c7c06c7d7528dab Mon Sep 17 00:00:00 2001 From: Wuffindy <71980308+Wuffindy@users.noreply.github.com> Date: Wed, 5 Aug 2026 21:11:42 +0700 Subject: [PATCH 14/14] adds ExpeditionReward into SalvageDifficultyPrototype --- Content.Shared/Procedural/SalvageDifficultyPrototype.cs | 8 ++++++-- Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs | 1 + Content.Shared/Salvage/SharedSalvageSystem.cs | 4 +++- .../Prototypes/_NF/Procedural/salvage_difficulties.yml | 3 +++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs index 1f26e0d9ecb..dacb87ee964 100644 --- a/Content.Shared/Procedural/SalvageDifficultyPrototype.cs +++ b/Content.Shared/Procedural/SalvageDifficultyPrototype.cs @@ -26,13 +26,13 @@ public sealed partial class SalvageDifficultyPrototype : IPrototype /// /// How much loot this difficulty is allowed to spawn. /// - [DataField("lootBudget", required : true)] + [DataField("lootBudget", required: true)] public float LootBudget; /// /// How many mobs this difficulty is allowed to spawn. /// - [DataField("mobBudget", required : true)] + [DataField("mobBudget", required: true)] public float MobBudget; /// @@ -51,4 +51,8 @@ public sealed partial class SalvageDifficultyPrototype : IPrototype [DataField] public int DestructionStructures = 1; // End Frontier: mission types + + //Triad: readds reward + [DataField("expeditionReward")] + public EntProtoId ExpeditionReward = string.Empty; } diff --git a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs index eab60c33fd3..1c60499426c 100644 --- a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs +++ b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs @@ -148,6 +148,7 @@ public sealed record SalvageMission( TimeSpan Duration, List Modifiers, ProtoId Difficulty, // Frontier + string ExpeditionReward, //Triad SalvageMissionType MissionType) // Frontier { /// diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 9798107de73..b8f725e5a24 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -47,6 +47,8 @@ public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPro var temp = GetBiomeMod(biome.ID, rand, ref modifierBudget); var air = GetBiomeMod(biome.ID, rand, ref modifierBudget); var dungeon = GetBiomeMod(biome.ID, rand, ref modifierBudget); + // var rewards = + var rewards = difficulty.ExpeditionReward; //Triad: adds reward // var factionProtos = _proto.EnumeratePrototypes().ToList(); //Triad: older version for all mob all difficulty // Frontier: restrict factions per difficulty var factionProtos = _proto.EnumeratePrototypes() @@ -81,7 +83,7 @@ public SalvageMission GetMission(SalvageMissionType config, SalvageDifficultyPro var duration = TimeSpan.FromSeconds(CfgManager.GetCVar(CCVars.SalvageExpeditionDuration)); - return new SalvageMission(seed, dungeon.ID, faction.ID, biome.ID, air.ID, temp.Temperature, light.Color, duration, mods, difficulty.ID, config); // Frontier: add difficulty.ID, config + return new SalvageMission(seed, dungeon.ID, faction.ID, biome.ID, air.ID, temp.Temperature, light.Color, duration, mods, difficulty.ID, difficulty.ExpeditionReward, config); // Frontier: add difficulty.ID, config } public T GetBiomeMod(string biome, System.Random rand, ref float rating) where T : class, IPrototype, IBiomeSpecificMod diff --git a/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml b/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml index a551cda8093..066f439926b 100644 --- a/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml +++ b/Resources/Prototypes/_NF/Procedural/salvage_difficulties.yml @@ -9,6 +9,7 @@ color: "#EFB34196" recommendedPlayers: 2 destructionStructures: 5 + expeditionReward: SpaceCashExpeditionT3 - type: salvageDifficulty id: NFHazardous @@ -19,6 +20,7 @@ color: "#DE3A3A96" recommendedPlayers: 3 destructionStructures: 7 + expeditionReward: SpaceCashExpeditionT4 - type: salvageDifficulty id: NFExtreme @@ -29,3 +31,4 @@ color: "#D381C996" recommendedPlayers: 4 destructionStructures: 9 + expeditionReward: SpaceCashExpeditionT5