Track LocalMods as part of monolith
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
using Barotrauma;
|
||||
using Barotrauma.MoreLevelContent.Config;
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics.Collision;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MoreLevelContent.Networking;
|
||||
using MoreLevelContent.Shared.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace MoreLevelContent.Shared.Generation
|
||||
{
|
||||
abstract partial class TimedEventMapModule : MapModule
|
||||
{
|
||||
public TimedEventMapModule()
|
||||
{
|
||||
InitProjSpecific();
|
||||
}
|
||||
|
||||
public string ForcedMissionIdentifier = "";
|
||||
public bool ForceSpawnMission = false;
|
||||
|
||||
// Networking
|
||||
protected abstract NetEvent EventCreated { get; }
|
||||
//protected abstract NetEvent EventUpdated { get; }
|
||||
|
||||
// Text
|
||||
protected abstract string NewEventText { get; }
|
||||
//protected abstract string UpdatedEventText { get; }
|
||||
protected abstract string EventTag { get; }
|
||||
|
||||
// Config
|
||||
protected abstract int MaxActiveEvents { get; }
|
||||
protected abstract float EventSpawnChance { get; }
|
||||
protected abstract int MinDistance { get; }
|
||||
protected abstract int MaxDistance { get; }
|
||||
protected abstract int MinEventDuration { get; }
|
||||
protected abstract int MaxEventDuration { get; }
|
||||
protected abstract bool ShouldSpawnEventAtStart { get; }
|
||||
protected bool SpawnedEventAtStart
|
||||
{
|
||||
get => GameMain.GameSession.Campaign.CampaignMetadata.GetBoolean($"{EventTag}SpawnedStart", false);
|
||||
set => GameMain.GameSession.Campaign.CampaignMetadata.SetValue($"{EventTag}SpawnedStart", value);
|
||||
}
|
||||
|
||||
private readonly List<Mission> _internalMissionStore = new();
|
||||
|
||||
public override void OnProgressWorld(Map __instance)
|
||||
{
|
||||
foreach (LocationConnection connection in __instance.Connections)
|
||||
{
|
||||
// skip locations that are close
|
||||
if (GameMain.GameSession.Campaign.Map.CurrentLocation.Connections.Contains(connection)) continue;
|
||||
HandleUpdate(connection.LevelData.MLC(), connection);
|
||||
}
|
||||
|
||||
if (ShouldSpawnEventAtStart && !SpawnedEventAtStart)
|
||||
{
|
||||
TrySpawnEvent(GameMain.GameSession.Map, true);
|
||||
SpawnedEventAtStart = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
TrySpawnEvent(GameMain.GameSession.Map, false);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnPreRoundStart(LevelData levelData)
|
||||
{
|
||||
if (levelData == null) return;
|
||||
if (!Main.IsCampaign) return;
|
||||
|
||||
if (!LevelHasEvent(levelData.MLC()) && !ForceSpawnMission)
|
||||
{
|
||||
Log.Debug($"Level has no {EventTag}");
|
||||
return;
|
||||
}
|
||||
|
||||
// Never try to spawn a timed event on an outpost level
|
||||
if (levelData.Type == LevelData.LevelType.Outpost) return;
|
||||
|
||||
if (TryGetMissionPrefab(levelData, out MissionPrefab prefab))
|
||||
{
|
||||
Log.Debug($"Adding {EventTag} mission");
|
||||
Mission inst = prefab.Instantiate(GameMain.GameSession.Map.SelectedConnection.Locations, Submarine.MainSub);
|
||||
AddExtraMission(inst); // we have to double add missions to make them work correctly
|
||||
_internalMissionStore.Add(inst);
|
||||
Log.Debug($"Added {EventTag} mission to extra missions!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Failed to find any {EventTag} missions!");
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual bool TryGetMissionPrefab(LevelData levelData, out MissionPrefab prefab)
|
||||
{
|
||||
return TryGetMissionByTag(EventTag, levelData, out prefab, ForcedMissionIdentifier);
|
||||
}
|
||||
|
||||
protected 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 OnAddExtraMissions(CampaignMode __instance, LevelData levelData)
|
||||
{
|
||||
if (!_internalMissionStore.Any()) return;
|
||||
foreach (Mission mission in _internalMissionStore)
|
||||
{
|
||||
AddExtraMission(mission);
|
||||
}
|
||||
_internalMissionStore.Clear();
|
||||
}
|
||||
|
||||
protected abstract void HandleUpdate(LevelData_MLCData data, LocationConnection connection);
|
||||
|
||||
public void TrySpawnEvent(Map __instance, bool force = false)
|
||||
{
|
||||
if (Main.IsClient) return;
|
||||
// Check if we're at the max
|
||||
int activeEvents = __instance.Connections.Where(c => LevelHasEvent(c.LevelData.MLC())).Count();
|
||||
if (activeEvents > MaxActiveEvents)
|
||||
{
|
||||
if (force)
|
||||
{
|
||||
Log.Debug($"Ignoring max {EventTag} cap due to force creation");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Verbose($"Skipped creating new {EventTag} due to being at the limit ({MaxActiveEvents})");
|
||||
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} <= {EventSpawnChance} ({chance <= EventSpawnChance}) for {EventTag}");
|
||||
if (chance >= EventSpawnChance && !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 wantedEventSpawnDistance = Rand.Range(MinDistance, MaxDistance, Rand.RandSync.Unsynced);
|
||||
LocationConnection targetConnection = WalkConnection(__instance.CurrentLocation, rand, wantedEventSpawnDistance);
|
||||
if (targetConnection == null)
|
||||
{
|
||||
Log.Warn($"Failed to spawn new {EventTag} due to target connection being null.");
|
||||
return;
|
||||
}
|
||||
int duration = rand.Next(MinEventDuration, MaxEventDuration);
|
||||
|
||||
if (!MapDirector.ConnectionIdLookup.ContainsKey(targetConnection)) return; // how does this happen?
|
||||
|
||||
CreateEvent(targetConnection, duration);
|
||||
|
||||
#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)duration);
|
||||
NetUtil.SendAll(msg);
|
||||
}
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
|
||||
{
|
||||
campaign.IncrementLastUpdateIdForFlag(MultiPlayerCampaign.NetFlags.MapAndMissions);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
protected abstract bool LevelHasEvent(LevelData_MLCData data);
|
||||
protected void CreateEvent(LocationConnection connection, int eventDuration)
|
||||
{
|
||||
HandleEventCreation(connection.LevelData.MLC(), eventDuration);
|
||||
AddNewsStory(NewEventText, connection);
|
||||
}
|
||||
protected abstract void HandleEventCreation(LevelData_MLCData data, int eventDuration);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user