Track LocalMods as part of monolith
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MoreLevelContent.Shared.Data;
|
||||
using Barotrauma.MoreLevelContent.Config;
|
||||
using MoreLevelContent.Networking;
|
||||
using MoreLevelContent.Shared.Utils;
|
||||
|
||||
namespace MoreLevelContent.Shared.Generation
|
||||
{
|
||||
// Shared
|
||||
internal partial class OldDistressMapModule : MapModule
|
||||
{
|
||||
public static bool ForceSpawnDistress = false;
|
||||
public static string ForcedMissionIdentifier = "";
|
||||
|
||||
private readonly List<Mission> _internalMissionStore = new();
|
||||
private static OldDistressMapModule _instance;
|
||||
private static bool _spawnStartingBeacon = false;
|
||||
const int MAX_DISTRESS_CREATE_ATTEMPTS = 5;
|
||||
const int DISTRESS_MIN_DIST = 1;
|
||||
const int DISTRESS_MAX_DIST = 3;
|
||||
|
||||
public OldDistressMapModule()
|
||||
{
|
||||
_instance = this;
|
||||
InitProjSpecific();
|
||||
}
|
||||
|
||||
internal void UpdateDistressBeacons(Map __instance)
|
||||
{
|
||||
foreach (LocationConnection connection in __instance.Connections.Where(c => c.LevelData.MLC().HasDistress))
|
||||
{
|
||||
// skip locations that are close
|
||||
if (GameMain.GameSession.Campaign.Map.CurrentLocation.Connections.Contains(connection)) continue;
|
||||
|
||||
// TODO: When multiple world steps happen at once in a long mission
|
||||
// this cause a distress to skip from active -> faint -> off before
|
||||
// the player has seen any notification of it. There could be a way
|
||||
// of avoiding this by counting the world steps before doing this
|
||||
// instead of doing it every world step
|
||||
var levelData = connection.LevelData.MLC();
|
||||
levelData.DistressStepsLeft--;
|
||||
if (levelData.DistressStepsLeft <= 0)
|
||||
{
|
||||
levelData.HasDistress = false;
|
||||
SendDistressUpdate("mlc.distress.lost", connection);
|
||||
}
|
||||
if (levelData.DistressStepsLeft == 3) SendDistressUpdate("mlc.distress.faint", connection);
|
||||
}
|
||||
}
|
||||
private void SendDistressUpdate(string updateType, LocationConnection connection)
|
||||
{
|
||||
#if CLIENT
|
||||
string msg = TextManager.GetWithVariables(updateType, ("[location1]", $"‖color:gui.orange‖{connection.Locations[0].DisplayName}‖end‖"), ("[location2]", $"‖color:gui.orange‖{connection.Locations[1].DisplayName}‖end‖")).Value;
|
||||
SendChatUpdate(msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void OnPreRoundStart(LevelData levelData)
|
||||
{
|
||||
_internalMissionStore.Clear();
|
||||
|
||||
if (levelData == null) return;
|
||||
if (!Main.IsCampaign) return;
|
||||
|
||||
TrySpawnDistress(GameMain.GameSession.Map, _spawnStartingBeacon);
|
||||
_spawnStartingBeacon = false;
|
||||
|
||||
if (!levelData.MLC().HasDistress && !ForceSpawnDistress)
|
||||
{
|
||||
Log.Debug("Level has no distress mission");
|
||||
return;
|
||||
}
|
||||
|
||||
if (TryGetMissionByTag("distress", levelData, out MissionPrefab prefab, ForcedMissionIdentifier))
|
||||
{
|
||||
Log.Debug("Adding distress mission");
|
||||
Mission inst = prefab.Instantiate(GameMain.GameSession.Map.SelectedConnection.Locations, Submarine.MainSub);
|
||||
AddExtraMission(inst); // weird
|
||||
_internalMissionStore.Add(inst);
|
||||
Log.Debug("Added distress mission to extra missions!");
|
||||
} else
|
||||
{
|
||||
Log.Error("Failed to find any distress missions!");
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnAddExtraMissions(CampaignMode __instance, LevelData levelData)
|
||||
{
|
||||
if (!_internalMissionStore.Any()) return;
|
||||
foreach (Mission mission in _internalMissionStore)
|
||||
{
|
||||
AddExtraMission(mission);
|
||||
}
|
||||
_internalMissionStore.Clear();
|
||||
}
|
||||
|
||||
private void AddExtraMission(Mission mission)
|
||||
{
|
||||
List<Mission> _extraMissions = (List<Mission>)Instance.extraMissions.GetValue(GameMain.GameSession.GameMode);
|
||||
_extraMissions.Add(mission);
|
||||
Instance.extraMissions.SetValue(GameMain.GameSession.GameMode, _extraMissions);
|
||||
}
|
||||
|
||||
public override void OnProgressWorld(Map __instance) => UpdateDistressBeacons(__instance);
|
||||
|
||||
private void TrySpawnDistress(Map __instance, bool force = false)
|
||||
{
|
||||
if (Main.IsClient) return;
|
||||
|
||||
if (__instance == null || __instance.Connections.Count == 0)
|
||||
{
|
||||
Log.Debug("Skipped trying to create a distress beacon as there was no map connections");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we're at the max
|
||||
int activeDistressCalls = __instance.Connections.Where(c => c.LevelData.MLC().HasDistress).Count();
|
||||
if (activeDistressCalls > ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.MaxActiveDistressBeacons)
|
||||
{
|
||||
if (force)
|
||||
{
|
||||
Log.Debug("Ignoring max distress cap due to force creation");
|
||||
} else
|
||||
{
|
||||
Log.Debug($"Skipped creating new distress due to being at the limit ({ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.MaxActiveDistressBeacons})");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're not, lets roll to see if we should make a new distress signal
|
||||
float chance = Rand.Value(Rand.RandSync.Unsynced);
|
||||
Log.InternalDebug($"{chance} >= {ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.DistressSpawnPercentage} ({chance >= ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.DistressSpawnPercentage})");
|
||||
if (chance >= ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.DistressSpawnPercentage && !force) return;
|
||||
|
||||
// Lets get a random instance to use
|
||||
int seed = Rand.GetRNG(Rand.RandSync.Unsynced).Next();
|
||||
Random rand = new MTRandom(seed);
|
||||
|
||||
// Find a location connection to spawn a distress beacon at
|
||||
int dist = Rand.Range(DISTRESS_MIN_DIST, DISTRESS_MAX_DIST, Rand.RandSync.Unsynced);
|
||||
LocationConnection targetConnection = WalkConnection(__instance.CurrentLocation, rand, dist);
|
||||
int stepsLeft = rand.Next(4, 8);
|
||||
if (!MapDirector.ConnectionIdLookup.ContainsKey(targetConnection)) return; // how does this happen?
|
||||
|
||||
CreateDistress(targetConnection, stepsLeft);
|
||||
|
||||
#if SERVER
|
||||
if (GameMain.IsMultiplayer)
|
||||
{
|
||||
// inform clients of the new distress beacon
|
||||
IWriteMessage msg = NetUtil.CreateNetMsg(NetEvent.MAP_SEND_NEWDISTRESS);
|
||||
msg.WriteUInt32((uint)MapDirector.ConnectionIdLookup[targetConnection]);
|
||||
msg.WriteByte((byte)stepsLeft);
|
||||
NetUtil.SendAll(msg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private void CreateDistress(LocationConnection connection, int stepsLeft)
|
||||
{
|
||||
connection.LevelData.MLC().HasDistress = true;
|
||||
connection.LevelData.MLC().DistressStepsLeft = stepsLeft;
|
||||
SendDistressUpdate("mlc.distress.new", connection);
|
||||
}
|
||||
|
||||
internal static void ForceDistress()
|
||||
{
|
||||
Log.Debug("Force creating distress beacon");
|
||||
_instance.TrySpawnDistress(GameMain.GameSession.Map, true);
|
||||
}
|
||||
}
|
||||
|
||||
internal partial class DistressMapModule : TimedEventMapModule
|
||||
{
|
||||
protected override NetEvent EventCreated => NetEvent.MAP_SEND_NEWDISTRESS;
|
||||
|
||||
protected override string NewEventText => "distress.new";
|
||||
|
||||
protected override string EventTag => "distress";
|
||||
|
||||
protected override int MaxActiveEvents => ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.MaxActiveDistressBeacons;
|
||||
|
||||
protected override float EventSpawnChance => ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.DistressSpawnPercentage;
|
||||
|
||||
protected override int MinDistance => 1;
|
||||
|
||||
protected override int MaxDistance => 3;
|
||||
|
||||
protected override int MinEventDuration => 4;
|
||||
|
||||
protected override int MaxEventDuration => 8;
|
||||
|
||||
protected override bool ShouldSpawnEventAtStart => true;
|
||||
|
||||
protected override void HandleEventCreation(LevelData_MLCData data, int eventDuration)
|
||||
{
|
||||
data.HasDistress = true;
|
||||
data.DistressStepsLeft = eventDuration;
|
||||
}
|
||||
|
||||
protected override bool TryGetMissionPrefab(LevelData levelData, out MissionPrefab prefab)
|
||||
{
|
||||
prefab = null;
|
||||
if (!ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.EnableDistressMissions) return false;
|
||||
if (!ForcedMissionIdentifier.IsNullOrEmpty()) return base.TryGetMissionPrefab(levelData, out prefab);
|
||||
var orderedMissions = MissionPrefab.Prefabs.Where(m => m.Tags.Contains(EventTag) && m.IsAllowedDifficulty(levelData.Difficulty)).OrderBy(m => m.UintIdentifier);
|
||||
|
||||
Random rand = new MTRandom(ToolBox.StringToInt(levelData.Seed));
|
||||
prefab = ToolBox.SelectWeightedRandom(orderedMissions, p => p.Commonness, rand);
|
||||
return prefab != null;
|
||||
|
||||
}
|
||||
|
||||
protected override void HandleUpdate(LevelData_MLCData data, LocationConnection connection)
|
||||
{
|
||||
if (!data.HasDistress) return;
|
||||
data.DistressStepsLeft--;
|
||||
if (data.DistressStepsLeft == 3) AddNewsStory("distress.faint", connection);
|
||||
|
||||
if (data.DistressStepsLeft <= 0)
|
||||
{
|
||||
data.HasDistress = false;
|
||||
AddNewsStory("distress.lost", connection);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool LevelHasEvent(LevelData_MLCData data) => data.HasDistress && ConfigManager.Instance.Config.NetworkedConfig.GeneralConfig.EnableDistressMissions;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user